File:  [ELWIX - Embedded LightWeight unIX -] / libaitio / src / bufio.c
Revision 1.1.2.1: download - view: text, annotated - select for diffs - revision graph
Thu Feb 2 15:58:14 2012 UTC (12 years, 4 months ago) by misho
Branches: io2_3
add new feature Buffered file I/O over memory blocks

#include "global.h"


static void
unmap_cf(struct tagBufIO *buf)
{
	if (buf)
		munmap(buf->buf_base, buf->buf_size);
}

static int
cf_(struct tagBufIO *buf)
{
	if (!buf) {
		io_SetErr(EINVAL, "Invalid arguments ...");
		return -1;
	}

	if (buf->buf_mode == BUFIO_MODE_INFINIT)
		free(buf->buf_base);
	else if (buf->buf_unmap)
		buf->buf_unmap(buf);

	free(buf);
	return 0;
}

static fpos_t
sf_lim(struct tagBufIO *buf, fpos_t pos, int w)
{
	if (!buf)
		goto err;

	switch (w) {
		case SEEK_SET:
			if (buf->buf_size < pos || pos < 0)
				goto err;
			buf->buf_offset = pos;
			break;
		case SEEK_CUR:
			if (buf->buf_size < (buf->buf_offset + pos) || (buf->buf_offset + pos) < 0)
				goto err;
			buf->buf_offset += pos;
			break;
		case SEEK_END:
			if (buf->buf_size < (buf->buf_size + pos) || (buf->buf_size + pos) < 0)
				goto err;
			buf->buf_offset = buf->buf_size + pos;
			break;
		default:
			goto err;
	}

	return buf->buf_offset;
err:
	io_SetErr(EINVAL, "Invalid arguments ...");
	return -1;
}

static int
rf_lim(struct tagBufIO *buf, char *dat, int siz)
{
	if (!buf || !dat) {
		io_SetErr(EINVAL, "Invalid arguments ...");
		return -1;
	}

	if (buf->buf_offset + siz > buf->buf_size)
		siz = buf->buf_size - buf->buf_offset;

	memcpy(dat, buf->buf_base + buf->buf_offset, siz);
	buf->buf_offset += siz;
	return siz;
}

static int
wf_lim(struct tagBufIO *buf, const char *dat, int siz)
{
	if (!buf || !dat) {
		io_SetErr(EINVAL, "Invalid arguments ...");
		return -1;
	}

	if (buf->buf_offset + siz > buf->buf_size)
		siz = buf->buf_size - buf->buf_offset;

	memcpy(buf->buf_base + buf->buf_offset, dat, siz);
	buf->buf_offset += siz;
	return siz;
}

static fpos_t
sf_inf(struct tagBufIO *buf, fpos_t pos, int w)
{
	void *b;

	if (!buf)
		goto err;

	switch (w) {
		case SEEK_SET:
			if (pos < 0)
				goto err;
			if (buf->buf_size < pos) {
				b = realloc(buf->buf_base, pos);
				if (!b) {
					LOGERR;
					return -1;
				} else {
					buf->buf_base = b;
					memset(buf->buf_base + buf->buf_size, 0, pos - buf->buf_size);
					buf->buf_size = pos;
				}
			}
			buf->buf_offset = pos;
			break;
		case SEEK_CUR:
			if ((buf->buf_offset + pos) < 0)
				goto err;
			if (buf->buf_size < (buf->buf_offset + pos)) {
				b = realloc(buf->buf_base, buf->buf_offset + pos);
				if (!b) {
					LOGERR;
					return -1;
				} else {
					buf->buf_base = b;
					memset(buf->buf_base + buf->buf_size, 0, 
							buf->buf_offset + pos - buf->buf_size);
					buf->buf_size = buf->buf_offset + pos;
				}
			}
			buf->buf_offset += pos;
			break;
		case SEEK_END:
			if ((buf->buf_size + pos) < 0)
				goto err;
			if (buf->buf_size < (buf->buf_size + pos)) {
				b = realloc(buf->buf_base, buf->buf_size + pos);
				if (!b) {
					LOGERR;
					return -1;
				} else {
					buf->buf_base = b;
					memset(buf->buf_base + buf->buf_size, 0, pos);
					buf->buf_size += pos;
					buf->buf_offset = buf->buf_size;
				}
			} else
				buf->buf_offset = buf->buf_size + pos;
			break;
		default:
			goto err;
	}

	return buf->buf_offset;
err:
	io_SetErr(EINVAL, "Invalid arguments ...");
	return -1;
}

static int
wf_inf(struct tagBufIO *buf, const char *dat, int siz)
{
	void *b;

	if (!buf || !dat) {
		io_SetErr(EINVAL, "Invalid arguments ...");
		return -1;
	}

	if (buf->buf_offset + siz > buf->buf_size) {
		b = realloc(buf->buf_base, buf->buf_offset + siz);
		if (!b) {
			LOGERR;
			return -1;
		} else {
			buf->buf_base = b;
			memset(buf->buf_base + buf->buf_size, 0, 
					buf->buf_offset + siz - buf->buf_size);
			buf->buf_size = buf->buf_offset + siz;
		}
	}

	memcpy(buf->buf_base + buf->buf_offset, dat, siz);
	buf->buf_offset += siz;
	return siz;
}


/*
 * io_fmemopen() File buffered stream operations over memory block
 *
 * @base = Base address of memory block, if =NULL Infinit length(auto-grow)
 * @basesize = Size of memory block
 * return: NULL error or !=NULL Opened file resource
 */
FILE *
io_fmemopen(void ** __restrict base, off_t basesize)
{
	FILE *f = NULL;
	struct tagBufIO *buf;

	if (!base) {
		io_SetErr(EINVAL, "Invalid base argument ...");
		return NULL;
	}

	buf = malloc(sizeof(struct tagBufIO));
	if (!buf) {
		LOGERR;
		return NULL;
	} else
		memset(buf, 0, sizeof(struct tagBufIO));

	if (!*base) {
		*base = malloc(basesize);
		if (!*base) {
			LOGERR;
			free(buf);
			return NULL;
		} else
			memset(*base, 0, basesize);

		buf->buf_mode = BUFIO_MODE_INFINIT;
	} else
		buf->buf_mode = BUFIO_MODE_LIMIT;

	buf->buf_base = *base;
	buf->buf_size = basesize;

	if (buf->buf_mode == BUFIO_MODE_INFINIT)
		f = funopen(buf, (int (*)(void *, char *, int)) rf_lim, 
				(int (*)(void *, char const *, int)) wf_inf, 
				(fpos_t (*)(void *, fpos_t, int)) sf_inf, 
				(int (*)(void *)) cf_);
	else
		f = funopen(buf, (int (*)(void *, char *, int)) rf_lim, 
				(int (*)(void *, char const *, int)) wf_lim, 
				(fpos_t (*)(void *, fpos_t, int)) sf_lim, 
				(int (*)(void *)) cf_);
	if (!f) {
		LOGERR;
		if (buf->buf_mode == BUFIO_MODE_INFINIT) {
			free(*base);
			*base = NULL;
		}
		free(buf);
		return NULL;
	}

	return f;
}

/*
 * io_fmapopen() File buffered stream operations over MMAP block
 *
 * @csFile = Filename for MMAP, if =NULL private MMAP block
 * @mode = File open mode
 * @perm = If file not exists will be created with this access permissions
 * @prot = MMAP protection
 * @flags = MMAP mode flags
 * @offset = Map from file offset, if csFile==NULL then this is size of MMAP private block
 * return: NULL error or !=NULL Opened file resource
 */
FILE *
io_fmapopen(const char *csFile, int mode, int perm, int prot, int flags, off_t offset)
{
	FILE *f;
	struct tagBufIO *buf;
	void *base;
	off_t basesize;
	int fd = -1;

	if (csFile) {
		fd = open(csFile, mode, perm);
		if (fd == -1) {
			LOGERR;
			return NULL;
		}
		basesize = lseek(fd, 0, SEEK_END);
		if (basesize == -1) {
			LOGERR;
			close(fd);
			return NULL;
		} else
			lseek(fd, 0, SEEK_SET);

		base = mmap(NULL, basesize, prot, flags | MAP_FILE, fd, offset);
		if (base == MAP_FAILED) {
			LOGERR;
			close(fd);
			return NULL;
		} else
			close(fd);
	} else if (offset) {
		basesize = offset;
		base = mmap(NULL, basesize, prot, MAP_ANON, -1, 0);
		if (base == MAP_FAILED) {
			LOGERR;
			return NULL;
		}
	} else {
		io_SetErr(EINVAL, "Invalid base argument ...");
		return NULL;
	}


	buf = malloc(sizeof(struct tagBufIO));
	if (!buf) {
		LOGERR;
		munmap(base, basesize);
		return NULL;
	} else
		memset(buf, 0, sizeof(struct tagBufIO));

	buf->buf_mode = BUFIO_MODE_LIMIT;
	buf->buf_base = base;
	buf->buf_size = basesize;
	buf->buf_unmap = unmap_cf;

	f = funopen(buf, (int (*)(void *, char *, int)) rf_lim, 
			(int (*)(void *, char const *, int)) wf_lim, 
			(fpos_t (*)(void *, fpos_t, int)) sf_lim, 
			(int (*)(void *)) cf_);
	if (!f) {
		LOGERR;
		free(buf);
		munmap(base, basesize);
		return NULL;
	}

	return f;
}

/*
 * io_dumbFile() Create empry or dumb file with fixed size
 *
 * @csFile = Filename for create
 * @mode = File access permissions
 * @size = File size
 * return: -1 error or open file handle
 */
int
io_dumbFile(const char *csFile, int mode, off_t size)
{
	int fd;

	fd = open(csFile, O_RDWR | O_CREAT, mode);
	if (fd == -1) {
		LOGERR;
		return -1;
	}

	if (lseek(fd, size - 1, SEEK_SET) == -1)
		goto err;
	if (write(fd, "", 1) != 1)
		goto err;
	else
		lseek(fd, 0, SEEK_SET);

	return fd;
err:
	LOGERR;
	close(fd);
	return -1;
}

/*
 * io_fd2buf() Convert open file handle to buffered file I/O
 *
 * @fd = File handle
 * @mode = Permissions for new buffered file I/O
 * return: NULL error or open buffered file
 */
inline FILE *
io_fd2buf(int fd, const char *mode)
{
	FILE *f;

	f = fdopen(fd, mode);
	if (!f)
		LOGERR;

	return f;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>