?? fromfile.cc
字號:
// -*- mode: c++; c-basic-offset: 4 -*-/* * fromfile.{cc,hh} -- provides convenient, fast access to files * Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2001-2003 International Computer Science Institute * Copyright (c) 2004-2007 The Regents of the University of California * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "fromfile.hh"#include <click/confparse.hh>#include <click/error.hh>#include <click/element.hh>#include <click/straccum.hh>#include <click/userutils.hh>#include "fakepcap.hh"#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef ALLOW_MMAP# include <sys/mman.h>#endifCLICK_DECLSFromFile::FromFile() : _fd(-1), _buffer(0), _data_packet(0),#ifdef ALLOW_MMAP _mmap(true),#endif _filename(), _pipe(0), _landmark_pattern("%f"), _lineno(0){}intFromFile::configure_keywords(Vector<String> &conf, Element *e, ErrorHandler *errh){#ifndef ALLOW_MMAP bool mmap = false;#else bool mmap = _mmap;#endif if (cp_va_kparse_remove_keywords(conf, e, errh, "MMAP", 0, cpBool, &mmap, cpEnd) < 0) return -1;#ifdef ALLOW_MMAP _mmap = mmap;#else if (mmap) errh->warning("'MMAP true' is not supported on this platform");#endif return 0;}StringFromFile::print_filename() const{ if (!_filename || _filename == "-") return String::make_stable("<stdin>", 7); else return _filename;}StringFromFile::landmark(const String &landmark_pattern) const{ StringAccum sa; const char *e = landmark_pattern.end(); for (const char *s = landmark_pattern.begin(); s < e; s++) if (s < e - 1 && s[0] == '%' && s[1] == 'f') { sa << print_filename(); s++; } else if (s < e - 1 && s[0] == '%' && s[1] == 'l') { sa << _lineno; s++; } else if (s < e - 1 && s[0] == '%' && s[1] == '%') { sa << '%'; s++; } else sa << *s; return sa.take_string();}intFromFile::error(ErrorHandler *errh, const char *format, ...) const{ if (!errh) errh = ErrorHandler::default_handler(); va_list val; va_start(val, format); int r = errh->xmessage(landmark(), ErrorHandler::e_error, format, val); va_end(val); return r;}intFromFile::warning(ErrorHandler *errh, const char *format, ...) const{ if (!errh) errh = ErrorHandler::default_handler(); va_list val; va_start(val, format); int r = errh->xmessage(landmark(), ErrorHandler::e_warning_annotated, format, val); va_end(val); return r;}#ifdef ALLOW_MMAPstatic voidmunmap_destructor(unsigned char *data, size_t amount){ if (munmap((caddr_t)data, amount) < 0) click_chatter("FromFile: munmap: %s", strerror(errno));}intFromFile::read_buffer_mmap(ErrorHandler *errh){ if (_mmap_unit == 0) { size_t page_size = getpagesize(); _mmap_unit = (WANT_MMAP_UNIT / page_size) * page_size; _mmap_off = 0; // don't report most errors on the first time through errh = ErrorHandler::silent_handler(); } // get length of file struct stat statbuf; if (fstat(_fd, &statbuf) < 0) return error(errh, "stat: %s", strerror(errno)); // check for end of file // But return -1 if we have not mmaped before: it might be a pipe, not // true EOF. if (_mmap_off >= statbuf.st_size) return (_mmap_off == 0 ? -1 : 0); // actually mmap _len = _mmap_unit; if ((off_t)(_mmap_off + _len) > statbuf.st_size) _len = statbuf.st_size - _mmap_off; void *mmap_data = mmap(0, _len, PROT_READ, MAP_SHARED, _fd, _mmap_off); if (mmap_data == MAP_FAILED) return error(errh, "mmap: %s", strerror(errno)); _data_packet = Packet::make((unsigned char *)mmap_data, _len, munmap_destructor); _buffer = _data_packet->data(); _file_offset = _mmap_off; _mmap_off += _len;# ifdef HAVE_MADVISE // don't care about errors (void) madvise((caddr_t)mmap_data, _len, MADV_SEQUENTIAL);# endif return 1;}#endifintFromFile::read_buffer(ErrorHandler *errh){ if (_data_packet) _data_packet->kill(); _data_packet = 0; _file_offset += _len; _pos -= _len; // adjust _pos by _len: it might validly point // beyond _len _len = 0;#ifdef ALLOW_MMAP if (_mmap) { int result = read_buffer_mmap(errh); if (result >= 0) return result; // else, try a regular read _mmap = false; (void) lseek(_fd, _mmap_off, SEEK_SET); _len = 0; }#endif _data_packet = Packet::make(0, 0, BUFFER_SIZE, 0); if (!_data_packet) return error(errh, strerror(ENOMEM)); _buffer = _data_packet->data(); unsigned char *data = _data_packet->data(); assert(_data_packet->headroom() == 0); while (_len < BUFFER_SIZE) { ssize_t got = ::read(_fd, data + _len, BUFFER_SIZE - _len); if (got > 0) _len += got; else if (got == 0) // premature end of file return _len; else if (got < 0 && errno != EINTR && errno != EAGAIN) return error(errh, strerror(errno)); } return _len;}intFromFile::read(void *vdata, uint32_t dlen, ErrorHandler *errh){ unsigned char *data = reinterpret_cast<unsigned char *>(vdata); uint32_t dpos = 0; while (dpos < dlen) { if (_pos < _len) { uint32_t howmuch = dlen - dpos; if (howmuch > _len - _pos) howmuch = _len - _pos; memcpy(data + dpos, _buffer + _pos, howmuch); dpos += howmuch; _pos += howmuch; } if (dpos < dlen && read_buffer(errh) <= 0) return dpos; } return dlen;}intFromFile::read_line(String &result, ErrorHandler *errh, bool temporary){ // first, try to read a line from the current buffer const unsigned char *s = _buffer + _pos; const unsigned char *e = _buffer + _len; while (s < e && *s != '\n' && *s != '\r') s++; if (s < e && (*s == '\n' || s + 1 < e)) { s += (*s == '\r' && s[1] == '\n' ? 2 : 1); int new_pos = s - _buffer; if (temporary) result = String::make_stable((const char *) (_buffer + _pos), new_pos - _pos); else result = String((const char *) (_buffer + _pos), new_pos - _pos); _pos = new_pos; _lineno++; return 1; } // otherwise, build up a line StringAccum sa; sa.append(_buffer + _pos, _len - _pos); while (1) { int errcode = read_buffer(errh); if (errcode < 0 || (errcode == 0 && !sa)) return errcode; // check doneness bool done; if (sa && sa.back() == '\r') { if (_len > 0 && _buffer[0] == '\n') sa << '\n', _pos++; done = true; } else if (errcode == 0) { _pos = _len; done = true; } else { s = _buffer, e = _buffer + _len; while (s < e && *s != '\n' && *s != '\r') s++; if (s < e && (*s == '\n' || s + 1 < e)) { s += (*s == '\r' && s[1] == '\n' ? 2 : 1); sa.append(_buffer, s - _buffer); _pos = s - _buffer; done = true; } else { sa.append(_buffer, _len); done = false; } } if (done) { result = sa.take_string(); _lineno++; return 1; } }}intFromFile::peek_line(String &result, ErrorHandler *errh, bool temporary){ int before_pos = _pos; int retval = read_line(result, errh, temporary); if (retval > 0) { _pos = before_pos; _lineno--; } return retval;}intFromFile::seek(off_t want, ErrorHandler* errh){ if (want >= _file_offset && want < (off_t) (_file_offset + _len)) { _pos = want; return 0; }#ifdef ALLOW_MMAP if (_mmap) { _mmap_off = (want / _mmap_unit) * _mmap_unit; _pos = _len + want - _mmap_off; return 0; }#endif // check length of file struct stat statbuf; if (fstat(_fd, &statbuf) < 0) return error(errh, "stat: %s", strerror(errno)); if (S_ISREG(statbuf.st_mode) && statbuf.st_size && want > statbuf.st_size) return errh->error("FILEPOS out of range"); // try to seek if (lseek(_fd, want, SEEK_SET) != (off_t) -1) { _pos = _len; _file_offset = want - _len; return 0; } // otherwise, read data while ((off_t) (_file_offset + _len) < want && _len) if (read_buffer(errh) < 0) return -1; _pos = want - _file_offset; return 0;}intFromFile::initialize(ErrorHandler *errh){ // open file if (!_filename || _filename == "-") _fd = STDIN_FILENO; else _fd = open(_filename.c_str(), O_RDONLY); if (_fd < 0) return errh->error("%s: %s", print_filename().c_str(), strerror(errno)); retry_file:#ifdef ALLOW_MMAP _mmap_unit = 0;#endif _file_offset = 0; _pos = _len = 0; int result = read_buffer(errh); if (result < 0) return -1; else if (result == 0) return error(errh, "empty file"); // check for a gziped or bzip2d dump if (_fd == STDIN_FILENO || _pipe) /* cannot handle gzip or bzip2 */; else if (compressed_data(_buffer, _len)) { close(_fd); _fd = -1; if (!(_pipe = open_uncompress_pipe(_filename, _buffer, _len, errh))) return -1; _fd = fileno(_pipe); goto retry_file; } return 0;}voidFromFile::take_state(FromFile &o, ErrorHandler *errh){ _fd = o._fd; o._fd = -1; _pipe = o._pipe; o._pipe = 0; _buffer = o._buffer; _pos = o._pos; _len = o._len; _data_packet = o._data_packet; o._data_packet = 0;#ifdef ALLOW_MMAP if (_mmap != o._mmap) errh->warning("different MMAP states"); _mmap = o._mmap; _mmap_unit = o._mmap_unit; _mmap_off = o._mmap_off;#endif _file_offset = o._file_offset;}voidFromFile::cleanup(){ if (_pipe) pclose(_pipe); else if (_fd >= 0 && _fd != STDIN_FILENO) close(_fd); _pipe = 0; _fd = -1; if (_data_packet) _data_packet->kill(); _data_packet = 0;}const uint8_t *FromFile::get_aligned(size_t size, void *buffer, ErrorHandler *errh){ // we may need to read bits of the file if (_pos + size <= _len) { const uint8_t *chunk = _buffer + _pos; _pos += size;#if HAVE_INDIFFERENT_ALIGNMENT return reinterpret_cast<const uint8_t *>(chunk);#else // make a copy if required for alignment if (((uintptr_t)(chunk) & 3) == 0) return reinterpret_cast<const uint8_t *>(chunk); else { memcpy(buffer, chunk, size); return reinterpret_cast<uint8_t *>(buffer); }#endif } else if (read(buffer, size, errh) == (int)size) return reinterpret_cast<uint8_t *>(buffer); else return 0;}const uint8_t *FromFile::get_unaligned(size_t size, void *buffer, ErrorHandler *errh){ // we may need to read bits of the file if (_pos + size <= _len) { const uint8_t *chunk = _buffer + _pos; _pos += size; return reinterpret_cast<const uint8_t *>(chunk); } else if (read(buffer, size, errh) == (int)size) return reinterpret_cast<uint8_t *>(buffer); else return 0;}StringFromFile::get_string(size_t size, ErrorHandler *errh){ // we may need to read bits of the file if (_pos + size <= _len) { const uint8_t *chunk = _buffer + _pos; _pos += size; return String::make_stable((const char *) chunk, size); } else { String s = String::make_garbage(size); if (read(s.mutable_data(), size, errh) == (int) size) return s; else return String(); }}Packet *FromFile::get_packet(size_t size, uint32_t sec, uint32_t subsec, ErrorHandler *errh){ if (_pos + size <= _len) { if (Packet *p = _data_packet->clone()) { p->shrink_data(_buffer + _pos, size); p->timestamp_anno().assign(sec, subsec); _pos += size; return p; } } else { if (WritablePacket *p = Packet::make(0, 0, size, 0)) { if (read(p->data(), size, errh) < (int)size) { p->kill(); return 0; } else { p->timestamp_anno().assign(sec, subsec); return p; } } } error(errh, strerror(ENOMEM)); return 0;}Packet *FromFile::get_packet_from_data(const void *data_void, size_t data_size, size_t size, uint32_t sec, uint32_t subsec, ErrorHandler *errh){ const uint8_t *data = reinterpret_cast<const uint8_t *>(data_void); if (data >= _buffer && data + size <= _buffer + _len) { if (Packet *p = _data_packet->clone()) { p->shrink_data(data, size); p->timestamp_anno().assign(sec, subsec); return p; } } else { if (WritablePacket *p = Packet::make(0, 0, size, 0)) { memcpy(p->data(), data, data_size); if (data_size < size && read(p->data() + data_size, size - data_size, errh) != (int)(size - data_size)) { p->kill(); return 0; } p->timestamp_anno().assign(sec, subsec); return p; } } error(errh, strerror(ENOMEM)); return 0;}StringFromFile::filename_handler(Element *e, void *thunk){ FromFile *fd = reinterpret_cast<FromFile *>((uint8_t *)e + (intptr_t)thunk); return fd->print_filename();}StringFromFile::filesize_handler(Element *e, void *thunk){ FromFile *fd = reinterpret_cast<FromFile *>((uint8_t *)e + (intptr_t)thunk); struct stat s; if (fd->_fd >= 0 && fstat(fd->_fd, &s) >= 0 && S_ISREG(s.st_mode)) return String(s.st_size); else return "-";}StringFromFile::filepos_handler(Element* e, void* thunk){ FromFile* fd = reinterpret_cast<FromFile*>((uint8_t*)e + (intptr_t)thunk); return String(fd->_file_offset + fd->_pos);}intFromFile::filepos_write_handler(const String& str, Element* e, void* thunk, ErrorHandler* errh){ off_t offset; if (!cp_file_offset(cp_uncomment(str), &offset)) return errh->error("argument must be file offset"); FromFile* fd = reinterpret_cast<FromFile*>((uint8_t*)e + (intptr_t)thunk); return fd->seek(offset, errh);}voidFromFile::add_handlers(Element* e, bool filepos_writable) const{ intptr_t offset = (const uint8_t *)this - (const uint8_t *)e; e->add_read_handler("filename", filename_handler, (void *)offset); e->add_read_handler("filesize", filesize_handler, (void *)offset); e->add_read_handler("filepos", filepos_handler, (void *)offset); if (filepos_writable) e->add_write_handler("filepos", filepos_write_handler, (void *)offset);}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel|ns FakePcap)ELEMENT_PROVIDES(FromFile)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -