define_open_500.patch
  Define XOPEN_SOURCE=500 to avoid pread/pwrite warnings.

lockf_negative_lenght.patch
  Don't pass negative lenghts to lockf() because it's not supported on some
  systems, use plockf() instead.

jwrite-const_buf.patch
  Add 'const' qualifiers to jwrite() and friends, to match real prototypes.

make_strict.patch
  Add a make option to make gcc use more strict checks (-ansi -pedantic)

pointer_arithmetic.patch
  Avoid void * arithmetic, explicit pointer arithmetic using unsigned chars.

install_instructions.patch
  Add a INSTALL file describing the installation procedure.

jfsck_close.patch
  Close the files we left open in jfsck()

jfsck_lock_transaction.patch
  jfsck() really wants to lock the transaction file, not the real one.

jfsck_const_name.patch
  Make jfsck()'s first parameter, "name", const.

jfsck_cleanup.patch
  Add a new function, jfsck_cleanup(), to help cleaning up the journal after
  checking it.

jfsck_rewrite_lockfile.patch
  Make jfsck() rewrite the lockfile to save the new maximum transaction ID.

spread_in_wrappers.patch
  Use spread() inside jread() and jpread() to avoid returning partial reads.

indent_manpage.patch
  Update and improve manpage's indentation.

version-0.14.patch
  Version 0.14



diff -u cur-root/Make.conf cur-root/Make.conf
--- cur-root/Make.conf	2004-05-04 22:34:02.000000000 -0300
+++ cur-root/Make.conf	2004-05-06 21:26:13.922562528 -0300
@@ -1,15 +1,20 @@
 
-VERSION="0.13"
+VERSION="0.14"
 
 CC = gcc
 CFLAGS += -Wall -O6 \
 	-D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 \
-	-D_LFS_LARGEFILE=1 -D_LFS64_LARGEFILE=1
+	-D_LFS_LARGEFILE=1 -D_LFS64_LARGEFILE=1 \
+	-D_XOPEN_SOURCE=500
 
 ifdef DEBUG
 CFLAGS += -g -pg -fprofile-arcs -ftest-coverage
 endif
 
+ifdef STRICT
+CFLAGS += -ansi -pedantic
+endif
+
 # prefix for installing the binaries
 PREFIX=/usr/local
 
unchanged:
--- cur-root/libjio.c	2004-05-05 15:08:22.000000000 -0300
+++ cur-root/libjio.c	2004-05-05 20:07:33.000000000 -0300
@@ -15,6 +15,7 @@
 #include <stdio.h>
 #include <dirent.h>
 #include <sys/uio.h>
+#include <errno.h>
 
 #include "libjio.h"
 
@@ -57,7 +58,7 @@
 	c = 0;
 
 	while (c < count) {
-		rv = pread(fd, buf + c, count - c, offset + c);
+		rv = pread(fd, (char *) buf + c, count - c, offset + c);
 		
 		if (rv == count)
 			/* we're done */
@@ -77,14 +78,14 @@
 }
 
 /* like spread() but for pwrite() */
-static ssize_t spwrite(int fd, void *buf, size_t count, off_t offset)
+static ssize_t spwrite(int fd, const void *buf, size_t count, off_t offset)
 {
 	int rv, c;
 
 	c = 0;
 
 	while (c < count) {
-		rv = pwrite(fd, buf + c, count - c, offset + c);
+		rv = pwrite(fd, (char *) buf + c, count - c, offset + c);
 		
 		if (rv == count)
 			/* we're done */
@@ -267,7 +268,7 @@
 {
 	int id, fd, rv, t;
 	char *name;
-	void *buf_init, *bufp;
+	unsigned char *buf_init, *bufp;
 	
 	name = (char *) malloc(PATH_MAX);
 	if (name == NULL)
@@ -503,11 +504,21 @@
 ssize_t jread(struct jfs *fs, void *buf, size_t count)
 {
 	int rv;
+	off_t pos;
 
 	pthread_mutex_lock(&(fs->lock));
-	lockf(fs->fd, F_LOCK, count);
-	rv = read(fs->fd, buf, count);
-	lockf(fs->fd, F_ULOCK, -count);
+
+	pos = lseek(fs->fd, 0, SEEK_CUR);
+
+	plockf(fs->fd, F_LOCK, pos, count);
+	rv = spread(fs->fd, buf, count, pos);
+	plockf(fs->fd, F_ULOCK, pos, count);
+
+	if (rv == count) {
+		/* if success, advance the file pointer */
+		lseek(fs->fd, count, SEEK_CUR);
+	}
+
 	pthread_mutex_unlock(&(fs->lock));
 
 	return rv;
@@ -519,7 +530,7 @@
 	int rv;
 
 	plockf(fs->fd, F_LOCK, offset, count);
-	rv = pread(fs->fd, buf, count, offset);
+	rv = spread(fs->fd, buf, count, offset);
 	plockf(fs->fd, F_ULOCK, offset, count);
 	
 	return rv;
@@ -530,22 +541,24 @@
 {
 	int rv, i;
 	size_t sum;
+	off_t pos;
 	
 	sum = 0;
 	for (i = 0; i < count; i++)
 		sum += vector[i].iov_len;
 	
 	pthread_mutex_lock(&(fs->lock));
-	lockf(fs->fd, F_LOCK, sum);
+	pos = lseek(fs->fd, 0, SEEK_CUR);
+	plockf(fs->fd, F_LOCK, pos, count);
 	rv = readv(fs->fd, vector, count);
-	lockf(fs->fd, F_ULOCK, -sum);
+	plockf(fs->fd, F_ULOCK, pos, count);
 	pthread_mutex_unlock(&(fs->lock));
 
 	return rv;
 }
 
 /* write wrapper */
-ssize_t jwrite(struct jfs *fs, void *buf, size_t count)
+ssize_t jwrite(struct jfs *fs, const void *buf, size_t count)
 {
 	int rv;
 	off_t pos;
@@ -577,7 +590,7 @@
 /* write family wrappers */
 
 /* pwrite wrapper */
-ssize_t jpwrite(struct jfs *fs, void *buf, size_t count, off_t offset)
+ssize_t jpwrite(struct jfs *fs, const void *buf, size_t count, off_t offset)
 {
 	int rv;
 	struct jtrans ts;
@@ -596,7 +609,7 @@
 }
 
 /* writev wrapper */
-ssize_t jwritev(struct jfs *fs, struct iovec *vector, int count)
+ssize_t jwritev(struct jfs *fs, const struct iovec *vector, int count)
 {
 	int rv, i, bufp;
 	ssize_t sum;
@@ -678,7 +691,7 @@
  */
 
 /* check the journal and replay the incomplete transactions */
-int jfsck(char *name, struct jfsck_result *res)
+int jfsck(const char *name, struct jfsck_result *res)
 {
 	int fd, tfd, rv, i, maxtid;
 	char jdir[PATH_MAX], jlockfile[PATH_MAX], tname[PATH_MAX];
@@ -695,7 +708,7 @@
 		return J_ENOENT;
 
 	fs.fd = fd;
-	fs.name = name;
+	fs.name = (char *) name;
 
 	if (!get_jdir(name, jdir))
 		return J_ENOMEM;
@@ -728,6 +741,14 @@
 		if (rv > maxtid)
 			maxtid = rv;
 	}
+	closedir(dir);
+
+	/* rewrite the lockfile, writing the new maxtid on it, so that when we
+	 * rollback a transaction it doesn't step over existing ones */
+	rv = spwrite(fs.jfd, &maxtid, sizeof(maxtid), 0);
+	if (rv != sizeof(maxtid)) {
+		return J_ENOMEM;
+	}
 
 	/* we loop all the way up to the max transaction id */
 	for (i = 1; i <= maxtid; i++) {
@@ -752,14 +773,14 @@
 
 		/* try to lock the transaction file, if it's locked then it is
 		 * currently being used so we skip it */
-		rv = plockf(fd, F_TLOCK, 0, 0);
+		rv = plockf(tfd, F_TLOCK, 0, 0);
 		if (rv == -1) {
 			res->in_progress++;
 			goto loop;
 		}
 		
 		/* load from disk, header first */
-		buf = (char *) malloc(J_DISKTFIXSIZE);
+		buf = (unsigned char *) malloc(J_DISKTFIXSIZE);
 		if (buf == NULL) {
 			res->load_error++;
 			goto loop;
@@ -858,6 +879,49 @@
 
+	close(fs.fd);
+	close(fs.jfd);
+
 	return 0;
 
 }
 
+/* remove all the files in the journal directory (if any) */
+int jfsck_cleanup(const char *name)
+{
+	char jdir[PATH_MAX], tfile[PATH_MAX*3];
+	DIR *dir;
+	struct dirent *dent;
+
+	if (!get_jdir(name, jdir))
+		return 0;
+
+	dir = opendir(jdir);
+	if (dir == NULL && errno == ENOENT)
+		/* it doesn't exist, so it's clean */
+		return 1;
+	else if (dir == NULL)
+		return 0;
+
+	for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+		/* we only care about transactions (named as numbers > 0) and
+		 * the lockfile (named "lock"); ignore everything else */
+		if (strcmp(dent->d_name, "lock") && atoi(dent->d_name) <= 0)
+			continue;
+
+		/* build the full path to the transaction file */
+		memset(tfile, 0, PATH_MAX * 3);
+		strcat(tfile, jdir);
+		strcat(tfile, "/");
+		strcat(tfile, dent->d_name);
+
+		/* the full filename is too large */
+		if (strlen(tfile) > PATH_MAX)
+			return 0;
+
+		/* and remove it */
+		unlink(tfile);
+	}
+	closedir(dir);
+
+	return 1;
+}
 
unchanged:
--- cur-root/libjio.h	2004-05-05 15:08:17.000000000 -0300
+++ cur-root/libjio.h	2004-05-05 15:08:20.000000000 -0300
@@ -31,7 +31,7 @@
 	char *name;		/* name of the transaction file */
 	int id;			/* transaction id */
 	int flags;		/* misc flags */
-	void *buf;		/* buffer */
+	const void *buf;	/* buffer */
 	size_t len;		/* buffer lenght */
 	off_t offset;		/* file offset to operate on */
 	void *udata;		/* user-supplied data */
@@ -73,9 +73,9 @@
 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, void *buf, size_t count);
-ssize_t jpwrite(struct jfs *fs, void *buf, size_t count, off_t offset);
-ssize_t jwritev(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);
 
@@ -86,7 +86,8 @@
 void jtrans_free(struct jtrans *ts);
 
 /* journal checker */
-int jfsck(char *name, struct jfsck_result *res);
+int jfsck(const char *name, struct jfsck_result *res);
+int jfsck_cleanup(const char *name);
 
 
 /* jfs constants */
unchanged:
--- cur-root/doc/libjio.3	2004-05-05 15:08:20.000000000 -0300
+++ cur-root/doc/libjio.3	2004-05-06 21:20:13.379373424 -0300
@@ -14,11 +14,11 @@
 
 .BI "ssize_t jreadv(struct jfs *" fs ", struct iovec *" vector ", int " count " );
 
-.BI "ssize_t jwrite(struct jfs *" fs ", void *" buf ", size_t " count " );
+.BI "ssize_t jwrite(struct jfs *" fs ", const void *" buf ", size_t " count " );
 
-.BI "ssize_t jpwrite(struct jfs *" fs ", void *" buf ", size_t " count ", off_t " offset " );
+.BI "ssize_t jpwrite(struct jfs *" fs ", const void *" buf ", size_t " count ", off_t " offset " );
 
-.BI "ssize_t jwritev(struct jfs *" fs ", struct iovec *" vector ", int " count " );
+.BI "ssize_t jwritev(struct jfs *" fs ", const struct iovec *" vector ", int " count " );
 
 .BI "int jtruncate(struct jfs *" fs ", off_t " lenght " );
 
@@ -32,57 +32,64 @@
 
 .BI "void jtrans_free(struct jtrans *" ts " );
 
-.BI "int jfsck(char *" name ", struct jfsck_result *" res " );
+.BI "int jfsck(const char *" name ", struct jfsck_result *" res " );
+
+.BI "int jfsck_cleanup(const char *" name" );"
 
 .SH STRUCTURES
 .PP
-.RS
-.NF
-struct jfs
-{
-    int fd;                 /* main file descriptor */
-    char *name;             /* and its name */
-    int jfd;                /* journal's lock file descriptor */
-    int flags;              /* journal mode options used in jopen() */
-    pthread_mutex_t lock;   /* a soft lock used in some operations */
- }
+.br
+.nf
+.in 10
+struct jfs {
+.in 14
+int fd;                 /* main file descriptor */
+char *name;             /* and its name */
+int jfd;                /* journal's lock file descriptor */
+int flags;              /* journal mode options used in jopen() */
+pthread_mutex_t lock;   /* a soft lock used in some operations */
+.in 10
+};
 .FI
-.RE
 
-.RS
-.NF
-struct jtrans
-{
-    struct jfs *fs;         /* journal file structure to operate on */
-    char *name;             /* name of the transaction file */
-    int id;                 /* transaction id */
-    int flags;              /* misc flags */
-    void *buf;              /* buffer */
-    size_t len;             /* buffer lenght */
-    off_t offset;           /* file offset to operate on */
-    void *udata;            /* user-supplied data */
-    size_t ulen;            /* udata lenght */
-    void *pdata;            /* previous data, for rollback */
-    size_t plen;            /* pdata lenght */
- }
+.PP
+.br
+.nf
+.in 10
+struct jtrans {
+.in 14
+struct jfs *fs;         /* journal file structure to operate on */
+char *name;             /* name of the transaction file */
+int id;                 /* transaction id */
+int flags;              /* misc flags */
+void *buf;              /* buffer */
+size_t len;             /* buffer lenght */
+off_t offset;           /* file offset to operate on */
+void *udata;            /* user-supplied data */
+size_t ulen;            /* udata lenght */
+void *pdata;            /* previous data, for rollback */
+size_t plen;            /* pdata lenght */
+.in 10
+};
 .FI
-.RE
 
-.RS
-.NF
-struct jfsck_result
-{
-    int total;              /* total transactions files we looked at */
-    int invalid;            /* invalid files in the journal directory */
-    int in_progress;        /* transactions in progress */
-    int broken_head;        /* transactions broken (header missing) */
-    int broken_body;        /* transactions broken (body missing) */
-    int load_error;         /* errors loading the transaction */
-    int apply_error;        /* errors applying the transaction */
-    int reapplied;          /* transactions that were re-applied */
- }
+.PP
+.br
+.nf
+.in 10
+struct jfsck_result {
+.in 14
+int total;              /* total transactions files we looked at */
+int invalid;            /* invalid files in the journal directory */
+int in_progress;        /* transactions in progress */
+int broken_head;        /* transactions broken (header missing) */
+int broken_body;        /* transactions broken (body missing) */
+int load_error;         /* errors loading the transaction */
+int apply_error;        /* errors applying the transaction */
+int rollbacked;         /* transactions that were rollbacked */
+.in 10
+};
 .FI
-.RE
 
 .SH DESCRIPTION
 
@@ -109,13 +116,22 @@
 close() functions but use a struct jfs instead of a file descriptor; take a
 look at their manpages if you have any doubts about how to use them.
 
-There is one function that differs from the rest, which is jfsck(). It is used
-to perform journal checking and recovery in case of a crash. It must be
-performed when nobody else is using the file (like in the case of a filesystem
-which can't be mounted), and it returns 0 if success or -1 in case of a
-failure. If it succeed, a structure jfsck_result that summarizes the outcome
-of the operation. There is also a program named jiofsck which is just a simple
-human frontend to this function.
+There are two functions that differs from the rest, which are jfsck() and
+jfsck_cleanup().
+
+The first one, jfsck(), is used to perform journal checking and recovery in
+case of a crash. It must be performed when nobody else is using the file (like
+in the case of a filesystem which can't be mounted), and it returns 0 if
+success or -1 in case of a failure. If it succeed, a structure jfsck_result
+that summarizes the outcome of the operation. There is also a program named
+jiofsck which is just a simple human frontend to this function.
+
+The second, jfsck_cleanup(), is intended to be used after jfsck() by programs
+wanting to remove all the stall transaction files and leave the journal
+directory ready to use. After calling jfsck(), the transaction files will no
+longer be needed, so by cleaning up the directory you make sure you're
+starting over with a clean journal. It returns 0 if there was an error, or 1
+if it succeeded.
 
 .SH HIGH LEVEL API
 
unchanged:
--- /dev/null	2004-04-14 00:22:58.000000000 -0300
+++ cur-root/INSTALL	2004-05-05 15:06:17.000000000 -0300
@@ -0,0 +1,40 @@
+
+To install the library and the checker (called jiofsck), run as root
+
+# make install
+
+
+It will copy the library to /usr/local/lib, manpages to /usr/local/man,
+binaries to /usr/local/bin, and headers to /usr/local/include.
+
+If you want to change the prefix directory (/usr/local by default), for
+instance, to /home/myself/usr; just run:
+
+# make PREFIX=/home/myself/usr install
+
+
+This will create inside PREFIX the directories "bin", "lib", "include" and
+"man" if necesary, and put the required files in there.
+
+
+After installing, you need to run "ldconfig" in order to update your dynamic
+library cache.
+
+So, if you want to install to /usr (like most distro bundled software do),
+this is a brief command line summary:
+
+make PREFIX=/usr install
+ldconfig
+
+
+There are other small options that might be useful (like compiling with
+debugging information), you can check the Make.conf file for more information.
+
+
+After installing, you're ready to use the library; you can see how by looking
+at the manpage with "man libjio".
+
+
+If you have any question, suggestion or comment, please send it to
+albertogli@telpin.com.ar.
+
unchanged:
--- cur/README~install_instructions	2004-05-05 15:06:17.000000000 -0300
+++ cur-root/README	2004-05-05 15:06:17.000000000 -0300
@@ -22,6 +22,8 @@ website, which are not included here for
 you will find the programming reference.
 
 
+To see how to install it, please read the INSTALL file.
+
 It is licensed under the Open Software License version 2.0.
 
 Comments and patches are always welcome; please send them to my email address,
unchanged:
--- cur/jiofsck.c~jfsck_cleanup	2004-05-05 15:08:20.000000000 -0300
+++ cur-root/jiofsck.c	2004-05-05 15:08:20.000000000 -0300
@@ -11,23 +11,36 @@
 
 void usage()
 {
-	printf("Use: jiofsck FILE\n\n");
-	printf("Where FILE is the name of the file"
-			"which you want to check the journal from.\n");
+	printf("Use: jiofsck [clean] FILE\n\n");
+	printf("Where \"FILE\" is the name of the file "
+			"which you want to check the journal from,\n"
+			"and the optional parameter \"clean\" makes "
+			"jiofsck to clean up the journal after\n"
+			"recovery.\n");
 }
 
 int main(int argc, char **argv)
 {
-	int rv;
+	int rv, do_cleanup;
 	char *file;
 	struct jfsck_result res;
 	
-	if (argc != 2) {
+	if (argc != 2 && argc != 3) {
 		usage();
 		return 1;
 	}
 
-	file = argv[1];
+	if (argc == 3) {
+		if (strcmp("clean", argv[1]) != 0 ) {
+			usage();
+			return 1;
+		}
+		file = argv[2];
+		do_cleanup = 1;
+	} else {
+		file = argv[1];
+		do_cleanup = 0;
+	}
 
 	memset(&res, 0, sizeof(res));
 	
@@ -45,6 +58,16 @@ int main(int argc, char **argv)
 
 	printf("done\n");
 
+	if (do_cleanup) {
+		printf("Cleaning journal: ");
+		if (!jfsck_cleanup(file)) {
+			printf("Error cleaning journal\n");
+			return 1;
+		}
+
+		printf("done\n");
+	}
+
 	printf("Journal checking results\n");
 	printf("------------------------\n\n");
 
@@ -58,8 +81,12 @@ int main(int argc, char **argv)
 	printf("Rollbacked:\t %d\n", res.rollbacked);
 	printf("\n");
 	
-	printf("You can now safely remove the journal directory completely\n"
-			"to start a new journal.\n");
+	if (!do_cleanup) {
+		printf("You can now safely remove the journal directory "
+				"completely\nto start a new journal.\n");
+	} else {
+		printf("The journal has been checked and cleaned up.\n");
+	}
 
 	return 0;
 }

