fix
diff --git a/ChangeLog b/ChangeLog
index 65597a8..1855359 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2005-07-06  Miklos Szeredi <miklos@szeredi.hu>
+
+	* fusermount: check if mountpoint is empty (only '.' and '..' for
+	directories, and size = 0 for regular files).  If "nonempty"
+	option is given, omit this check.  This is useful, so users don't
+	accidentally hide data (e.g. from backup programs).  Thanks to
+	Frank van Maarseveen for pointing this out.
+
+	* kernel: check if mandatory mount options ('fd', 'rootmode',
+	'user_id', 'group_id') are all given
+
 2005-07-03  Miklos Szeredi <miklos@szeredi.hu>
 
 	* kernel: clean up 'direct_io' code
diff --git a/README b/README
index 5537ddb..fc1675e 100644
--- a/README
+++ b/README
@@ -193,3 +193,9 @@
 
   Sets the filesystem name.  The default is the program name.
 
+nonempty
+
+  Allows mounts over a non-empty file or directory.  By default these
+  mounts are rejected (from version 2.3.1) to prevent accidental
+  covering up of data, which could for example prevent automatic
+  backup.
diff --git a/include/fuse.h b/include/fuse.h
index fb1c2d6..40c9b72 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -157,6 +157,8 @@
      * is permitted for the given flags.  Optionally open may also
      * return an arbitary filehandle in the fuse_file_info structure,
      * which will be passed to all file operations.
+     * 
+     * Changed in version 2.2
      */
     int (*open) (const char *, struct fuse_file_info *);
 
@@ -168,6 +170,8 @@
      * 'direct_io' mount option is specified, in which case the return
      * value of the read system call will reflect the return value of
      * this operation.
+     *
+     * Changed in version 2.2
      */
     int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
 
@@ -176,6 +180,8 @@
      * Write should return exactly the number of bytes requested
      * except on error.  An exception to this is when the 'direct_io'
      * mount option is specified (see read operation).
+     *
+     * Changed in version 2.2
      */
     int (*write) (const char *, const char *, size_t, off_t,
                   struct fuse_file_info *);
@@ -203,6 +209,8 @@
      * not possible to determine if a flush is final, so each flush
      * should be treated equally.  Multiple write-flush sequences are
      * relatively rare, so this shouldn't be a problem.
+     * 
+     * Changed in version 2.2
      */
     int (*flush) (const char *, struct fuse_file_info *);
 
@@ -217,6 +225,8 @@
      * have a file opened more than once, in which case only the last
      * release will mean, that no more reads/writes will happen on the
      * file.  The return value of release is ignored.
+     *
+     * Changed in version 2.2
      */
     int (*release) (const char *, struct fuse_file_info *);
 
@@ -224,6 +234,8 @@
      *
      * If the datasync parameter is non-zero, then only the user data
      * should be flushed, not the meta data.
+     *
+     * Changed in version 2.2
      */
     int (*fsync) (const char *, int, struct fuse_file_info *);
 
@@ -243,6 +255,8 @@
      *
      * This method should check if the open operation is permitted for
      * this  directory
+     *
+     * Introduced in version 2.3
      */
     int (*opendir) (const char *, struct fuse_file_info *);
 
@@ -264,17 +278,24 @@
      * passes non-zero offset to the filler function.  When the buffer
      * is full (or an error happens) the filler function will return
      * '1'.
+     * 
+     * Introduced in version 2.3
      */
     int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
                     struct fuse_file_info *);
 
-    /** Release directory */
+    /** Release directory 
+     *
+     * Introduced in version 2.3
+     */
     int (*releasedir) (const char *, struct fuse_file_info *);
 
     /** Synchronize directory contents
      *
      * If the datasync parameter is non-zero, then only the user data
      * should be flushed, not the meta data
+     *
+     * Introduced in version 2.3
      */
     int (*fsyncdir) (const char *, int, struct fuse_file_info *);
 
@@ -284,6 +305,8 @@
      * The return value will passed in the private_data field of
      * fuse_context to all file operations and as a parameter to the
      * destroy() method.
+     * 
+     * Introduced in version 2.3
      */
     void *(*init) (void);
 
@@ -291,6 +314,8 @@
      * Clean up filesystem
      *
      * Called on filesystem exit.
+     * 
+     * Introduced in version 2.3
      */
     void (*destroy) (void *);
 };
diff --git a/kernel/inode.c b/kernel/inode.c
index ed14602..5dacb22 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -44,6 +44,10 @@
 	unsigned rootmode;
 	unsigned user_id;
 	unsigned group_id;
+	unsigned fd_present : 1;
+	unsigned rootmode_present : 1;
+	unsigned user_id_present : 1;
+	unsigned group_id_present : 1;
 	unsigned flags;
 	unsigned max_read;
 };
@@ -350,7 +354,6 @@
 {
 	char *p;
 	memset(d, 0, sizeof(struct fuse_mount_data));
-	d->fd = -1;
 	d->max_read = ~0;
 
 	while ((p = strsep(&opt, ",")) != NULL) {
@@ -366,24 +369,28 @@
 			if (match_int(&args[0], &value))
 				return 0;
 			d->fd = value;
+			d->fd_present = 1;
 			break;
 
 		case OPT_ROOTMODE:
 			if (match_octal(&args[0], &value))
 				return 0;
 			d->rootmode = value;
+			d->rootmode_present = 1;
 			break;
 
 		case OPT_USER_ID:
 			if (match_int(&args[0], &value))
 				return 0;
 			d->user_id = value;
+			d->user_id_present = 1;
 			break;
 
 		case OPT_GROUP_ID:
 			if (match_int(&args[0], &value))
 				return 0;
 			d->group_id = value;
+			d->group_id_present = 1;
 			break;
 
 		case OPT_DEFAULT_PERMISSIONS:
@@ -417,7 +424,9 @@
 			return 0;
 		}
 	}
-	if (d->fd == -1)
+	
+	if (!d->fd_present || !d->rootmode_present ||
+	    !d->user_id_present || !d->group_id_present)
 		return 0;
 
 	return 1;
diff --git a/util/fusermount.c b/util/fusermount.c
index 6e0abb2..ec2f39d 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <pwd.h>
 #include <mntent.h>
+#include <dirent.h>
 #include <sys/param.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
@@ -474,9 +475,41 @@
         return 0;
 }
 
+static int check_mountpoint_empty(const char *mnt, mode_t rootmode,
+                                  off_t rootsize)
+{
+    int isempty = 1;
+
+    if (S_ISDIR(rootmode)) {
+        struct dirent *ent;
+        DIR *dp = opendir(mnt);
+        if (dp == NULL) {
+            fprintf(stderr, "%s: failed to mountpoint for reading: %s\n",
+                    progname, strerror(errno));
+            return -1;
+        }
+        while ((ent = readdir(dp)) != NULL) {
+            if (strcmp(ent->d_name, ".") != 0 &&
+                strcmp(ent->d_name, "..") != 0) {
+                isempty = 0;
+                break;
+            }
+        }
+        closedir(dp);
+    } else if (rootsize)
+        isempty = 0;
+
+    if (!isempty) {
+        fprintf(stderr, "%s: mountpoint is not empty\n", progname);
+        fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
+        return -1;
+    }
+    return 0;
+}
+
 static int do_mount(const char *mnt, const char *type, mode_t rootmode,
                     int fd, const char *opts, const char *dev, char **fsnamep,
-                    char **mnt_optsp)
+                    char **mnt_optsp, off_t rootsize)
 {
     int res;
     int flags = MS_NOSUID | MS_NODEV;
@@ -485,6 +518,7 @@
     const char *s;
     char *d;
     char *fsname = NULL;
+    int check_empty = 1;
 
     optbuf = malloc(strlen(opts) + 128);
     if (!optbuf) {
@@ -503,11 +537,12 @@
             fsname = malloc(len - fsname_str_len + 1);
             if (!fsname) {
                 fprintf(stderr, "%s: failed to allocate memory\n", progname);
-                free(optbuf);
-                return -1;
+                goto err;
             }
             memcpy(fsname, s + fsname_str_len, len - fsname_str_len);
             fsname[len - fsname_str_len] = '\0';
+        } else if (opt_eq(s, len, "nonempty")) {
+            check_empty = 0;
         } else if (!begins_with(s, "fd=") &&
                    !begins_with(s, "rootmode=") &&
                    !begins_with(s, "user_id=") &&
@@ -530,8 +565,7 @@
                 (opt_eq(s, len, "allow_other") ||
                  opt_eq(s, len, "allow_root"))) {
                 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s);
-                free(optbuf);
-                return -1;
+                goto err;
             }
             if (!skip_option) {
                 if (find_mount_flag(s, len, &on, &flag)) {
@@ -552,22 +586,22 @@
     }
     *d = '\0';
     res = get_mnt_opts(flags, optbuf, &mnt_opts);
-    if (res == -1) {
-        free(mnt_opts);
-        free(optbuf);
-        return -1;
-    }
+    if (res == -1)
+        goto err;
+
     sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i",
             fd, rootmode, getuid(), getgid());
     if (fsname == NULL) {
         fsname = strdup(dev);
         if (!fsname) {
             fprintf(stderr, "%s: failed to allocate memory\n", progname);
-            free(optbuf);
-            return -1;
+            goto err;
         }
     }
 
+    if (check_empty && check_mountpoint_empty(mnt, rootmode, rootsize) == -1)
+        goto err;
+
     res = mount(fsname, mnt, type, flags, optbuf);
     if (res == -1 && errno == EINVAL) {
         /* It could be an old version not supporting group_id */
@@ -576,8 +610,7 @@
     }
     if (res == -1) {
         fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno));
-        free(fsname);
-        free(mnt_opts);
+        goto err;
     } else {
         *fsnamep = fsname;
         *mnt_optsp = mnt_opts;
@@ -585,6 +618,12 @@
     free(optbuf);
 
     return res;
+
+ err:
+    free(fsname);
+    free(mnt_opts);
+    free(optbuf);
+    return -1;
 }
 
 static int check_version(const char *dev)
@@ -822,7 +861,7 @@
         restore_privs();
         if (res != -1)
             res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT, fd, opts,
-                           dev, &fsname, &mnt_opts);
+                           dev, &fsname, &mnt_opts, stbuf.st_size);
     } else
         restore_privs();