⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fromfile.cc

📁 Click is a modular router toolkit. To use it you ll need to know how to compile and install the sof
💻 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 + -