author | Alberto Bertogli
<albertito@gmail.com> 2004-05-30 15:47:17 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-07-15 12:49:16 UTC |
parent | 2c6a55dc41dd9071ad474e82d3389131b6f2c7c7 |
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 */