git » libjio » commit 0d61474

Implement wrappers for most common ANSI C I/O functions (fread, fwrite, etc.).

author Alberto Bertogli
2004-05-30 15:47:17 UTC
committer Alberto Bertogli
2007-07-15 12:49:16 UTC
parent 2c6a55dc41dd9071ad474e82d3389131b6f2c7c7

Implement wrappers for most common ANSI C I/O functions (fread, fwrite, etc.).

Implement wrappers for most common ANSI C I/O functions (fread, fwrite, etc.).

This is not a nice API to do serious I/O, and I doubt if I will include this
in future revisions, so it's not documented yet. Anyways, it's pretty complete
and extremely boring.

Makefile +1 -1
ansi.c +206 -0
libjio.h +27 -11

diff --git a/Makefile b/Makefile
index fc84cbe..8d068e6 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ include Make.conf
 
 
 # objects to build
-OBJS = common.o trans.o unix.o
+OBJS = common.o trans.o unix.o ansi.o
 
 # rules
 default: all
diff --git a/ansi.c b/ansi.c
new file mode 100644
index 0000000..b79f38a
--- /dev/null
+++ b/ansi.c
@@ -0,0 +1,206 @@
+
+/*
+ * libjio - A library for Journaled I/O
+ * Alberto Bertogli (albertogli@telpin.com.ar)
+ *
+ * ANSI C API wrappers
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "libjio.h"
+
+
+/*
+ * To avoid completely useless code duplication, this functions rely on the
+ * UNIX wrappers from unix.c.
+ *
+ * The API is not nice, and you I wouldn't recommend it for any serious I/O;
+ * this wrappers are done more as code samples than anything else.
+ *
+ * TODO: it should be possible to implement something like this at some
+ * LD_PRELOAD level without too much harm for most apps.
+ * TODO: this is still experimental, it hasn't received too much testing
+ * (that's why it's not even documented), so use it at your own risk.
+ */
+
+
+/* fopen wrapper */
+struct jfs *jfopen(const char *path, const char *mode)
+{
+	int fd;
+	int flags;
+	int pos_at_the_beginning;
+	struct jfs *fs;
+
+	if (strlen(mode) < 1)
+		return NULL;
+
+	if (mode[0] == 'r') {
+		pos_at_the_beginning = 1;
+		if (strlen(mode) > 1 && strchr(mode, '+'))
+			flags = O_RDWR;
+		else
+			flags = O_RDONLY;
+	} else if (mode[0] == 'a') {
+		/* in this case, make no distinction between "a" and "a+"
+		 * because the file is _always_ open for reading anyways */
+		pos_at_the_beginning = 0;
+		flags = O_RDWR | O_CREAT;
+	} else if (mode[0] == 'w') {
+		/* the same as before */
+		pos_at_the_beginning = 1;
+		flags = O_RDWR | O_CREAT | O_TRUNC;
+	} else {
+		return NULL;
+	}
+
+	fs = malloc(sizeof(struct jfs));
+
+	fd = jopen(fs, path, flags, 0666, 0);
+	if (fd < 0) {
+		free(fs);
+		return NULL;
+	}
+
+	if (pos_at_the_beginning)
+		lseek(fd, 0, SEEK_SET);
+	else
+		lseek(fd, 0, SEEK_END);
+
+	return fs;
+}
+
+/* fclose wrapper */
+int jfclose(struct jfs *stream)
+{
+	int rv;
+	rv = jclose(stream);
+	free(stream);
+
+	if (rv == 0)
+		return 0;
+	else
+		return EOF;
+}
+
+/* freopen wrapper */
+struct jfs *jfreopen(const char *path, const char *mode, struct jfs *stream)
+{
+	if (stream)
+		jfclose(stream);
+
+	stream = jfopen(path, mode);
+	return stream;
+}
+
+/* fread wrapper */
+size_t jfread(void *ptr, size_t size, size_t nmemb, struct jfs *stream)
+{
+	int rv;
+	rv = jread(stream, ptr, size * nmemb);
+
+	if (rv <= 0)
+		return 0;
+
+	return rv / size;
+}
+
+/* fwrite wrapper */
+size_t jfwrite(const void *ptr, size_t size, size_t nmemb, struct jfs *stream)
+{
+	int rv;
+	rv = jwrite(stream, ptr, size * nmemb);
+
+	if (rv <= 0)
+		return 0;
+
+	return rv / size;
+}
+
+/* fileno wrapper */
+int jfileno(struct jfs *stream)
+{
+	return stream->fd;
+}
+
+/* feof wrapper */
+int jfeof(struct jfs *stream)
+{
+	/* ANSI expects that when an EOF is reached in any operation (like
+	 * fread() or fwrite()) some internal flag is set, and this function
+	 * can be used to check if it is set or unset.
+	 * As we don't do that (it's pointless for this kind of I/O), this
+	 * just checks if the file pointer is at the end of the file */
+
+	off_t curpos, endpos;
+
+	pthread_mutex_lock(&(stream->lock));
+
+	curpos = lseek(jfileno(stream), 0, SEEK_CUR);
+	endpos = lseek(jfileno(stream), 0, SEEK_END);
+
+	lseek(jfileno(stream), curpos, SEEK_SET);
+
+	pthread_mutex_unlock(&(stream->lock));
+
+	if (curpos >= endpos)
+		return 1;
+	else
+		return 0;
+}
+
+/* clearerr wrapper */
+void jclearerr(struct jfs *stream)
+{
+	/* As we do not carry any kind of error state (like explained in
+	 * jfeof()), this function has no effect. */
+}
+
+/* ferror wrapper */
+int jferror(struct jfs *stream)
+{
+	/* The same as the above; however not returning this might have some
+	 * side effects on very subtle programs relying on this behaviour */
+	return 0;
+}
+
+/* fseek wrapper */
+int jfseek(struct jfs *stream, long offset, int whence)
+{
+	long pos;
+
+	pthread_mutex_lock(&(stream->lock));
+	pos = lseek(stream->fd, offset, whence);
+	pthread_mutex_unlock(&(stream->lock));
+
+	return pos;
+}
+
+/* ftell wrapper */
+int jftell(struct jfs *stream)
+{
+	return lseek(stream->fd, 0, SEEK_CUR);
+}
+
+/* rewind wrapper */
+void frewind(struct jfs *stream)
+{
+	lseek(stream->fd, 0, SEEK_SET);
+}
+
+/* convert a struct jfs to a FILE so you can use it with other functions that
+ * require a FILE pointer; be aware that you're bypassing the journaling layer
+ * and it can cause severe corruption if you're not extremely careful */
+FILE *jfsopen(struct jfs *stream, const char *mode)
+{
+	return fdopen(stream->fd, mode);
+}
+
diff --git a/libjio.h b/libjio.h
index 343bc69..07d54c4 100644
--- a/libjio.h
+++ b/libjio.h
@@ -8,6 +8,7 @@
 #define _LIBJIO_H
 
 #include <stdint.h>
+#include <stdio.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <pthread.h>
@@ -68,27 +69,42 @@ struct disk_trans {
 };
 
 
-/* basic operations */
+/* core operations */
 int jopen(struct jfs *fs, const char *name, int flags, int mode, int jflags);
-ssize_t jread(struct jfs *fs, void *buf, size_t count);
-ssize_t jpread(struct jfs *fs, void *buf, size_t count, off_t offset);
-ssize_t jreadv(struct jfs *fs, struct iovec *vector, int count);
-ssize_t jwrite(struct jfs *fs, const void *buf, size_t count);
-ssize_t jpwrite(struct jfs *fs, const void *buf, size_t count, off_t offset);
-ssize_t jwritev(struct jfs *fs, const struct iovec *vector, int count);
-int jtruncate(struct jfs *fs, off_t lenght);
-int jclose(struct jfs *fs);
-
-/* transaction operations */
 void jtrans_init(struct jfs *fs, struct jtrans *ts);
 int jtrans_commit(struct jtrans *ts);
 int jtrans_rollback(struct jtrans *ts);
 void jtrans_free(struct jtrans *ts);
+int jclose(struct jfs *fs);
 
 /* journal checker */
 int jfsck(const char *name, struct jfsck_result *res);
 int jfsck_cleanup(const char *name);
 
+/* UNIX API wrappers */
+ssize_t jread(struct jfs *fs, void *buf, size_t count);
+ssize_t jpread(struct jfs *fs, void *buf, size_t count, off_t offset);
+ssize_t jreadv(struct jfs *fs, struct iovec *vector, int count);
+ssize_t jwrite(struct jfs *fs, const void *buf, size_t count);
+ssize_t jpwrite(struct jfs *fs, const void *buf, size_t count, off_t offset);
+ssize_t jwritev(struct jfs *fs, const struct iovec *vector, int count);
+int jtruncate(struct jfs *fs, off_t lenght);
+
+/* ANSI C stdio wrappers */
+struct jfs *jfopen(const char *path, const char *mode);
+int jfclose(struct jfs *stream);
+struct jfs *jfreopen(const char *path, const char *mode, struct jfs *stream);
+size_t jfread(void *ptr, size_t size, size_t nmemb, struct jfs *stream);
+size_t jfwrite(const void *ptr, size_t size, size_t nmemb, struct jfs *stream);
+int jfileno(struct jfs *stream);
+int jfeof(struct jfs *stream);
+void jclearerr(struct jfs *stream);
+int jferror(struct jfs *stream);
+int jfseek(struct jfs *stream, long offset, int whence);
+int jftell(struct jfs *stream);
+void frewind(struct jfs *stream);
+FILE *jfsopen(struct jfs *stream, const char *mode);
+
 
 /* jfs constants */
 #define J_NOLOCK	1	/* don't lock the file before operating on it */