Thu Mar 10 04:34:35 ART 2005  Alberto Bertogli (albertogli@telpin.com.ar)
  * Reintroduce dup() and dup2() in the preloader.
diff -rN -u old-libjio/bindings/preload/libjio_preload.c new-libjio/bindings/preload/libjio_preload.c
--- old-libjio/bindings/preload/libjio_preload.c	2005-03-10 15:15:11.653698708 -0300
+++ new-libjio/bindings/preload/libjio_preload.c	2005-03-10 04:31:00.000000000 -0300
@@ -58,11 +58,14 @@
 static off_t (*c_lseek)(int fd, off_t offset, int whence);
 static off64_t (*c_lseek64)(int fd, off64_t offset, int whence);
 static int (*c_fsync)(int fd);
+static int (*c_dup)(int oldfd);
+static int (*c_dup2)(int oldfd, int newfd);
 
 
 /* file descriptor table, to translate fds to jfs */
 struct fd_entry {
 	int fd;
+	unsigned int *refcount;
 	struct jfs *fs;
 	pthread_mutex_t lock;
 };
@@ -96,6 +99,7 @@
 			if (called)			\
 				fprintf(stderr, "\t");	\
 			called++;			\
+			fprintf(stderr, "%5.5d ", getpid()); \
 			fprintf(stderr, "%s(): ", __FUNCTION__ ); \
 			fprintf(stderr, __VA_ARGS__);	\
 			fflush(stderr);			\
@@ -182,6 +186,8 @@
 	libc_load(lseek);
 	libc_load(lseek64);
 	libc_load(fsync);
+	libc_load(dup);
+	libc_load(dup2);
 
 	printd("done\n");
 	return 1;
@@ -255,6 +261,8 @@
 
 	fd_lock(fd);
 	fd_table[fd].fd = fd;
+	fd_table[fd].refcount = malloc(sizeof(unsigned int));
+	*fd_table[fd].refcount = 1;
 	fd_table[fd].fs = fs;
 	fd_unlock(fd);
 
@@ -327,6 +335,8 @@
 
 	fd_lock(fd);
 	fd_table[fd].fd = fd;
+	fd_table[fd].refcount = malloc(sizeof(unsigned int));
+	*fd_table[fd].refcount = 1;
 	fd_table[fd].fs = fs;
 	fd_unlock(fd);
 
@@ -334,6 +344,38 @@
 	return fd;
 }
 
+/* close() is split in two functions: unlocked_close() that performs the real
+ * actual close and cleanup, and close() which takes care of the locking and
+ * calls unlocked_close(); this is because in dup*() we need to close with
+ * locks already held to avoid races. */
+int unlocked_close(int fd)
+{
+	int r;
+
+	if (*fd_table[fd].refcount > 1) {
+		/* we still have references, don't really close */
+		printd("not closing, refcount: %d\n", *fd_table[fd].refcount);
+		(*fd_table[fd].refcount)--;
+		fd_table[fd].fd = -1;
+		fd_table[fd].refcount = NULL;
+		fd_table[fd].fs = NULL;
+		return 0;
+	}
+
+	rec_inc();
+	r = jclose(fd_table[fd].fs);
+	rec_dec();
+
+	if (fd_table[fd].fs != NULL) {
+		fd_table[fd].fd = -1;
+		free(fd_table[fd].refcount);
+		fd_table[fd].refcount = NULL;
+		free(fd_table[fd].fs);
+		fd_table[fd].fs = NULL;
+	}
+
+	return r;
+}
 
 int close(int fd)
 {
@@ -357,14 +399,7 @@
 	}
 	printd("libjio\n");
 
-	rec_inc();
-	r = jclose(fs);
-	if (fd_table[fd].fs != NULL) {
-		free(fd_table[fd].fs);
-		fd_table[fd].fd = -1;
-		fd_table[fd].fs = NULL;
-	}
-	rec_dec();
+	r = unlocked_close(fd);
 	fd_unlock(fd);
 
 	printd("return %d\n", r);
@@ -393,6 +428,89 @@
 	return r;
 }
 
+int dup(int oldfd)
+{
+	int r;
+
+	if (called) {
+		printd("orig\n");
+		return (*c_dup)(oldfd);
+	}
+
+	if (fd_table[oldfd].fs == NULL) {
+		printd("NULL fs, fd %d\n", oldfd);
+		fd_unlock(oldfd);
+		return (*c_dup)(oldfd);
+	}
+
+	if (!fd_lock(oldfd)) {
+		printd("out of bounds fd: %d\n", oldfd);
+		return -1;
+	}
+
+	printd("libjio\n");
+
+	rec_inc();
+	r = (*c_dup)(oldfd);
+	rec_dec();
+
+	if (r >= 0) {
+		fd_lock(r);
+		fd_table[r].fd = r;
+		fd_table[r].refcount = fd_table[oldfd].refcount;
+		(*fd_table[r].refcount)++;
+		fd_table[r].fs = fd_table[oldfd].fs;
+		fd_unlock(r);
+	}
+
+	fd_unlock(oldfd);
+	printd("return %d\n", r);
+	return r;
+}
+
+int dup2(int oldfd, int newfd)
+{
+	int r;
+
+	if (called) {
+		printd("orig\n");
+		return (*c_dup2)(oldfd, newfd);
+	}
+
+	if (!fd_lock(oldfd)) {
+		printd("out of bounds fd: %d\n", oldfd);
+		return -1;
+	}
+
+	if (fd_table[oldfd].fs == NULL) {
+		printd("NULL fs, fd %d\n", oldfd);
+		fd_unlock(oldfd);
+		return (*c_dup2)(oldfd, newfd);
+	}
+
+	printd("libjio\n");
+
+	rec_inc();
+	r = (*c_dup2)(oldfd, newfd);
+	rec_dec();
+
+	if (r >= 0) {
+		fd_lock(newfd);
+		if (fd_table[newfd].fs != NULL) {
+			unlocked_close(newfd);
+		}
+		fd_table[newfd].fd = newfd;
+		fd_table[newfd].refcount = fd_table[oldfd].refcount;
+		(*fd_table[newfd].refcount)++;
+		fd_table[newfd].fs = fd_table[oldfd].fs;
+		fd_unlock(newfd);
+	}
+
+	fd_unlock(oldfd);
+	printd("return %d\n", r);
+	return r;
+}
+
 
 /* the rest of the functions are automagically generated from the following
  * macro. The ugliest. I'm so proud. */

