added release() callback
diff --git a/ChangeLog b/ChangeLog
index 9a8286e..1b033f2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2002-12-10  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+	* The release() VFS call is now exported to the FUSE interface
+
 2002-12-05  Miklos Szeredi <mszeredi@inf.bme.hu>
 
 	* 64 bit file offset fixes in the fuse kernel module
diff --git a/example/fusexmp.c b/example/fusexmp.c
index 8b48af6..e783423 100644
--- a/example/fusexmp.c
+++ b/example/fusexmp.c
@@ -267,6 +267,7 @@
     read:	xmp_read,
     write:	xmp_write,
     statfs:	xmp_statfs,
+    release:	NULL
 };
 
 int main(int argc, char *argv[])
diff --git a/example/hello.c b/example/hello.c
index be8930e..cd8fb5d 100644
--- a/example/hello.c
+++ b/example/hello.c
@@ -86,6 +86,7 @@
     read:	hello_read,
     write:	NULL,
     statfs:	NULL,
+    release:	NULL
 };
 
 int main(int argc, char *argv[])
diff --git a/example/null.c b/example/null.c
index 6b2c1b6..b712b5c 100644
--- a/example/null.c
+++ b/example/null.c
@@ -89,6 +89,7 @@
     read:	null_read,
     write:	null_write,
     statfs:	null_statfs,
+    release:	NULL
 };
 
 int main(int argc, char *argv[])
diff --git a/include/fuse.h b/include/fuse.h
index 28d5f3b..f92914f 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -75,6 +75,13 @@
  *  - read(), write() are not passed a filehandle, but rather a
  *  pathname.  The offset of the read and write is passed as the last
  *  argument, like the pread() and pwrite() system calls.
+ * 
+ *  - release() is called when an open file has:
+ *       1) all file descriptors closed
+ *       2) all memory mappings unmapped
+ *    This call need only be implemented if this information is required,
+ *    otherwise set this function to NULL.
+ *    
  */
 struct fuse_operations {
     int (*getattr)  (const char *, struct stat *);
@@ -95,6 +102,7 @@
     int (*read)     (const char *, char *, size_t, off_t);
     int (*write)    (const char *, const char *, size_t, off_t);
     int (*statfs)   (struct fuse_statfs *);
+    int (*release)  (const char *);
 };
 
 /** Extra context that may be needed by some filesystems */
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 24905c4..eef77d9 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -93,6 +93,7 @@
 	FUSE_READ	= 15,
 	FUSE_WRITE	= 16,
 	FUSE_STATFS	= 17,
+	FUSE_RELEASE    = 18
 };
 
 /* Conservative buffer size for the client */
diff --git a/kernel/dev.c b/kernel/dev.c
index 7cf3844..002e23b 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -447,6 +447,7 @@
 		INIT_LIST_HEAD(&fc->processing);
 		sema_init(&fc->outstanding, MAX_OUTSTANDING);
 		fc->reqctr = 1;
+		fc->has_release = 1;
 	}
 	return fc;
 }
diff --git a/kernel/file.c b/kernel/file.c
index 14ba59b..4940117 100644
--- a/kernel/file.c
+++ b/kernel/file.c
@@ -40,6 +40,27 @@
 	return out.h.error;
 }
 
+static int fuse_release(struct inode *inode, struct file *file)
+{
+	struct fuse_conn *fc = INO_FC(inode);
+	struct fuse_in in = FUSE_IN_INIT;
+	struct fuse_out out = FUSE_OUT_INIT;
+
+	if(!fc->has_release)
+		return 0;
+
+	in.h.opcode = FUSE_RELEASE;
+	in.h.ino = inode->i_ino;
+	request_send(fc, &in, &out);
+
+	if(out.h.error == -ENOSYS) {
+		fc->has_release = 0;
+		return 0;
+	}
+
+	return out.h.error;
+}
+
 
 static int fuse_readpage(struct file *file, struct page *page)
 {
@@ -159,6 +180,7 @@
 
 static struct file_operations fuse_file_operations = {
 	open:		fuse_open,
+	release:        fuse_release,
 	read:		generic_file_read,
 	write:		generic_file_write,
 	mmap:		generic_file_mmap,
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 23cc914..e4730e6 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -56,6 +56,9 @@
 	
 	/** The next unique request id */
 	int reqctr;
+
+	/* Flag indicating whether the release call is supported */
+	int has_release;
 };
 
 /** One input argument of a request */
diff --git a/lib/fuse.c b/lib/fuse.c
index 1a11ae6..71959c4 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -19,6 +19,31 @@
 #define FUSE_MAX_PATH 4096
 #define PARAM(inarg) (((char *)(inarg)) + sizeof(*inarg))
 
+static const char *opname(enum fuse_opcode opcode)
+{
+    switch(opcode) { 
+    case FUSE_LOOKUP:   return "LOOKUP";
+    case FUSE_FORGET:   return "FORGET";
+    case FUSE_GETATTR:  return "GETATTR";
+    case FUSE_SETATTR:  return "SETATTR";
+    case FUSE_READLINK: return "READLINK";
+    case FUSE_SYMLINK:  return "SYMLINK";
+    case FUSE_GETDIR:   return "GETDIR";
+    case FUSE_MKNOD:    return "MKNOD";
+    case FUSE_MKDIR:    return "MKDIR";
+    case FUSE_UNLINK:   return "UNLINK";
+    case FUSE_RMDIR:    return "RMDIR";
+    case FUSE_RENAME:   return "RENAME";
+    case FUSE_LINK:     return "LINK";
+    case FUSE_OPEN:     return "OPEN";
+    case FUSE_READ:     return "READ";
+    case FUSE_WRITE:    return "WRITE";
+    case FUSE_STATFS:   return "STATFS";
+    case FUSE_RELEASE:  return "RELEASE";
+    default:            return "???";
+    }
+}
+
 static inline void inc_avail(struct fuse *f)
 {
     pthread_mutex_lock(&f->lock);
@@ -728,6 +753,22 @@
     send_reply(f, in, res, NULL, 0);
 }
 
+static void do_release(struct fuse *f, struct fuse_in_header *in)
+{
+    int res;
+    char *path;
+
+    res = -ENOENT;
+    path = get_path(f, in->ino);
+    if(path != NULL) {
+        res = -ENOSYS;
+        if(f->op.release)
+            res = f->op.release(path);
+        free(path);
+    }
+    send_reply(f, in, res, NULL, 0);
+}
+
 static void do_read(struct fuse *f, struct fuse_in_header *in,
                     struct fuse_read_in *arg)
 {
@@ -834,8 +875,9 @@
     dec_avail(f);
 
     if((f->flags & FUSE_DEBUG)) {
-        printf("unique: %i, opcode: %i, ino: %li, insize: %i\n", in->unique,
-               in->opcode, in->ino, cmd->buflen);
+        printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n",
+               in->unique, opname(in->opcode), in->opcode, in->ino,
+               cmd->buflen);
         fflush(stdout);
     }
 
@@ -907,6 +949,10 @@
         do_statfs(f, in);
         break;
 
+    case FUSE_RELEASE:
+        do_release(f, in);
+        break;
+
     default:
         fprintf(stderr, "Operation %i not implemented\n", in->opcode);
         send_reply(f, in, -ENOSYS, NULL, 0);