Exemple #1
0
/**
 * jogger_checkoutfile()
 *
 * Tries to open given file (check), and reads it, if expected (checkout).
 * It is designed to be proof to special file problems (especially named pipe ones).
 *
 * @param	file	- filename to open.
 * @param	data	- pointer to store file contents or NULL, if don't want to read it.
 * @param	len	- pointer to store filelength or NULL, if not needed.
 * @param	hash	- pointer to store filehash or NULL, if not needed.
 * @param	maxlen	- maximum filesize to accept (not counting additional NUL) or 0, if n/a.
 * @param	quiet	- if set, don't output anything to __status.
 *
 * @return	0 on success, errno on failure.
 */
static int jogger_checkoutfile(const char *file, char **data, int *len, char **hash, const int maxlen, const int quiet) {
	static char jogger_hash[sizeof(int)*2+3];
	int mylen, fs, fd;

	const char *fn	= prepare_path_user(file);

	if (!fn)
		return EINVAL;

	if ((fd = open(fn, O_RDONLY|O_NONBLOCK)) == -1) { /* we use O_NONBLOCK to get rid of FIFO problems */
		const int err = errno;
		if (err == ENXIO)
			printq("io_nonfile", file);
		else
			printq("io_cantopen", file, strerror(err));
		return err;
	}

	{
		struct stat st;

		if ((fstat(fd, &st) == -1) || !S_ISREG(st.st_mode)) {
			close(fd);
			printq("io_nonfile", file);
			return EISDIR; /* nearest, I think */
		}

		fs = st.st_size;
	}

	int bufsize	= (fs ? (maxlen && fs > maxlen ? maxlen+1 : fs+1) : 0x4000); /* we leave 1 byte for additional NUL */
	char *out	= xmalloc(bufsize);
	void *p		= out;
	int _read = 0, res;

	{
		int cf	= fcntl(fd, F_GETFL);

		if (cf == -1) /* evil thing */
			cf = 0;
		else
			cf &= ~O_NONBLOCK;
		fcntl(fd, F_SETFL, cf);
	}

	while ((res = read(fd, p, bufsize-_read))) {
		if (res == -1) {
			const int err = errno;
			if (err != EINTR && err != EAGAIN) {
				close(fd);
				printq("io_cantread", file, strerror(errno));
				return err;
			}
		} else {
			_read += res;
			if (maxlen && _read > maxlen) {
				xfree(out);
				printq("io_toobig", file, ekg_itoa(_read > fs ? _read : fs), ekg_itoa(maxlen));
				return EFBIG;
			} else if (_read == bufsize) { /* fs sucks? */
				bufsize += 0x4000;
				out	= xrealloc(out, bufsize);
				p	= out+_read;
			} else
				p	+= res;
		}
	}
	close(fd);

	if (_read == 0) {
		xfree(out);
		printq("io_emptyfile", file);
		return EINVAL; /* like mmap() */
	} else if (_read+1 != bufsize) {
		out		= xrealloc(out, _read+1);
		out[_read]	= 0; /* add NUL */
	}

	mylen = xstrlen(out);
	if (fs && _read > fs)
		printq("io_expanded", file, ekg_itoa(_read), ekg_itoa(fs));
	else if (_read < fs)
		printq("io_truncated", file, ekg_itoa(_read), ekg_itoa(fs));
	if (_read > mylen)
		printq("io_binaryfile", file, ekg_itoa(mylen), ekg_itoa(_read));
	if (len)
		*len = _read;

		/* I don't want to write my own hashing function, so using EKG2 one
		 * it will fail to hash data after any \0 in file, if there're any
		 * but we also aren't prepared to handle them */
	if (hash) {
		char sizecont[8];

		snprintf(sizecont, 8, "0x%%0%lux", sizeof(int)*2);
		snprintf(jogger_hash, sizeof(int)*2+3, sizecont, ekg_hash(out));
		*hash = jogger_hash;
	}

	if (data)
		*data = out;
	else
		xfree(out);

	return 0;
}
Exemple #2
0
/* like that in mine 'jogger' plugin, but slightly modified for xmsg
 * - quiet always 1, so removed all prints,
 * - hash not needed, giving timestamp instead.
 */
static int xmsg_checkoutfile(const char *file, char **data, int *len, time_t *ts, const int maxlen) {
	int fs, fd;

	const char *fn	= prepare_path_user(file);

	if (!fn)
		return EINVAL;

	if ((fd = open(fn, O_RDONLY|O_NONBLOCK)) == -1) /* we use O_NONBLOCK to get rid of FIFO problems */
		return errno;

	{
		struct stat st;

		if ((fstat(fd, &st) == -1) || !S_ISREG(st.st_mode)) {
			close(fd);
			return EISDIR; /* nearest, I think */
		}

		fs = st.st_size;
		/* mtime > ctime > atime > time(NULL) */
#define X(x,y) (x ? x : y)
		if (ts)
			*ts = X(st.st_mtime, X(st.st_ctime, X(st.st_atime, time(NULL))));
#undef X
	}

	int bufsize	= (fs ? (maxlen && fs > maxlen ? maxlen+1 : fs+1) : 0x4000); /* we leave 1 byte for additional NUL */
	char *out	= xmalloc(bufsize);
	void *p		= out;
	int _read = 0, res;

	{
		int cf	= fcntl(fd, F_GETFL);

		if (cf == -1) /* evil thing */
			cf = 0;
		else
			cf &= ~O_NONBLOCK;
		fcntl(fd, F_SETFL, cf);
	}

	while ((res = read(fd, p, bufsize-_read))) {
		if (res == -1) {
			const int err = errno;
			if (err != EINTR && err != EAGAIN) {
				close(fd);
				return err;
			}
		} else {
			_read += res;
			if (maxlen && _read > maxlen) {
				xfree(out);
				return EFBIG;
			} else if (_read == bufsize) { /* fs sucks? */
				bufsize += 0x4000;
				out	= xrealloc(out, bufsize);
				p	= out+_read;
			} else
				p	+= res;
		}
	}
	close(fd);

	if (_read == 0) {
		xfree(out);
		return EINVAL; /* like mmap() */
	} else if (_read+1 != bufsize) {
		out		= xrealloc(out, _read+1);
		out[_read]	= 0; /* add NUL */
	}

	if (len)
		*len = _read;

	if (data)
		*data = out;
	else
		xfree(out);

	return 0;
}