patch-2.1.121 linux/fs/umsdos/ioctl.c

Next file: linux/fs/umsdos/mangle.c
Previous file: linux/fs/umsdos/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.120/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
@@ -50,14 +50,33 @@
 /*
  * Perform special function on a directory
  */
-int UMSDOS_ioctl_dir (	     struct inode *dir,
-			     struct file *filp,
-			     unsigned int cmd,
-			     unsigned long data)
+/* #Specification: ioctl / prototypes
+ * The official prototype for the umsdos ioctl on directory
+ * is:
+ * 
+ * int ioctl (
+ * int fd,          // File handle of the directory
+ * int cmd, // command
+ * struct umsdos_ioctl *data)
+ * 
+ * The struct and the commands are defined in linux/umsdos_fs.h.
+ * 
+ * umsdos_progs/umsdosio.c provide an interface in C++ to all
+ * these ioctl. umsdos_progs/udosctl is a small utility showing
+ * all this.
+ * 
+ * These ioctl generally allow one to work on the EMD or the
+ * DOS directory independently. These are essential to implement
+ * the synchronise.
+ */
+int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd,
+			unsigned long data_ptr)
 {
-	int ret = -EPERM;
-	int err;
-	struct dentry *old_dent;
+	struct dentry *dentry = filp->f_dentry;
+	struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data_ptr;
+	int ret;
+	struct file new_filp;
+	struct umsdos_ioctl data;
 
 	/* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
 	if (cmd != UMSDOS_GETVERSION
@@ -71,7 +90,7 @@
 	    && cmd != UMSDOS_RMDIR_DOS
 	    && cmd != UMSDOS_STAT_DOS
 	    && cmd != UMSDOS_DOS_SETUP)
-		return fat_dir_ioctl (dir, filp, cmd, data);
+		return fat_dir_ioctl (dir, filp, cmd, data_ptr);
 
 	/* #Specification: ioctl / acces
 	 * Only root (effective id) is allowed to do IOCTL on directory
@@ -82,278 +101,315 @@
 	 * the code, and let's face it, there is only one client (umssync)
 	 * for all this.
 	 */
-	if ((err = verify_area (VERIFY_WRITE, (void *) data, sizeof (struct umsdos_ioctl))) < 0) {
-		ret = err;
-	} else if (current->euid == 0
-		   || cmd == UMSDOS_GETVERSION) {
-		struct umsdos_ioctl *idata = (struct umsdos_ioctl *) data;
-
-		ret = -EINVAL;
-		/* #Specification: ioctl / prototypes
-		 * The official prototype for the umsdos ioctl on directory
-		 * is:
-		 * 
-		 * int ioctl (
-		 * int fd,          // File handle of the directory
-		 * int cmd, // command
-		 * struct umsdos_ioctl *data)
-		 * 
-		 * The struct and the commands are defined in linux/umsdos_fs.h.
-		 * 
-		 * umsdos_progs/umsdosio.c provide an interface in C++ to all
-		 * these ioctl. umsdos_progs/udosctl is a small utility showing
-		 * all this.
-		 * 
-		 * These ioctl generally allow one to work on the EMD or the
-		 * DOS directory independently. These are essential to implement
-		 * the synchronise.
-		 */
-		Printk (("ioctl %d ", cmd));
-		if (cmd == UMSDOS_GETVERSION) {
-			/* #Specification: ioctl / UMSDOS_GETVERSION
-			 * The field version and release of the structure
-			 * umsdos_ioctl are filled with the version and release
-			 * number of the fs code in the kernel. This will allow
-			 * some form of checking. Users won't be able to run
-			 * incompatible utility such as the synchroniser (umssync).
-			 * umsdos_progs/umsdosio.c enforce this checking.
-			 * 
-			 * Return always 0.
-			 */
-			put_user (UMSDOS_VERSION, &idata->version);
-			put_user (UMSDOS_RELEASE, &idata->release);
+	ret = verify_area (VERIFY_WRITE, (void *) data_ptr, 
+				sizeof (struct umsdos_ioctl));
+	if (ret < 0)
+		goto out;
+
+	ret = -EPERM;
+	if (current->euid != 0 && cmd != UMSDOS_GETVERSION)
+		goto out;
+
+	ret = -EINVAL;
+	if (cmd == UMSDOS_GETVERSION) {
+		/* #Specification: ioctl / UMSDOS_GETVERSION
+		 * The field version and release of the structure
+		 * umsdos_ioctl are filled with the version and release
+		 * number of the fs code in the kernel. This will allow
+		 * some form of checking. Users won't be able to run
+		 * incompatible utility such as the synchroniser (umssync).
+		 * umsdos_progs/umsdosio.c enforce this checking.
+		 * 
+		 * Return always 0.
+		 */
+		put_user (UMSDOS_VERSION, &idata->version);
+		put_user (UMSDOS_RELEASE, &idata->release);
+		ret = 0;
+		goto out;
+	}
+	if (cmd == UMSDOS_READDIR_DOS) {
+		/* #Specification: ioctl / UMSDOS_READDIR_DOS
+		 * One entry is read from the DOS directory at the current
+		 * file position. The entry is put as is in the dos_dirent
+		 * field of struct umsdos_ioctl.
+		 * 
+		 * Return > 0 if success.
+		 */
+		struct UMSDOS_DIR_ONCE bufk;
+
+		bufk.count = 0;
+		bufk.ent = &idata->dos_dirent;
+
+		fat_readdir (filp, &bufk, umsdos_ioctl_fill);
+
+		ret = bufk.count == 1 ? 1 : 0;
+		goto out;
+	}
+	if (cmd == UMSDOS_READDIR_EMD) {
+		/* #Specification: ioctl / UMSDOS_READDIR_EMD
+		 * One entry is read from the EMD at the current
+		 * file position. The entry is put as is in the umsdos_dirent
+		 * field of struct umsdos_ioctl. The corresponding mangled
+		 * DOS entry name is put in the dos_dirent field.
+		 * 
+		 * All entries are read including hidden links. Blank
+		 * entries are skipped.
+		 * 
+		 * Return > 0 if success.
+		 */
+		struct dentry *demd;
+
+		/* The absence of the EMD is simply seen as an EOF */
+		demd = umsdos_get_emd_dentry(dentry);
+		ret = PTR_ERR(demd);
+		if (IS_ERR(demd))
+			goto out;
+		fill_new_filp(&new_filp, demd);
+		new_filp.f_pos = filp->f_pos;
+
+		while (1) {
+			off_t f_pos = new_filp.f_pos;
+			struct umsdos_dirent entry;
+			struct umsdos_info info;
+
 			ret = 0;
-		} else if (cmd == UMSDOS_READDIR_DOS) {
-			/* #Specification: ioctl / UMSDOS_READDIR_DOS
-			 * One entry is read from the DOS directory at the current
-			 * file position. The entry is put as is in the dos_dirent
-			 * field of struct umsdos_ioctl.
-			 * 
-			 * Return > 0 if success.
-			 */
-			struct UMSDOS_DIR_ONCE bufk;
-
-			bufk.count = 0;
-			bufk.ent = &idata->dos_dirent;
-
-			fat_readdir (filp, &bufk, umsdos_ioctl_fill);
-
-			ret = bufk.count == 1 ? 1 : 0;
-		} else if (cmd == UMSDOS_READDIR_EMD) {
-			/* #Specification: ioctl / UMSDOS_READDIR_EMD
-			 * One entry is read from the EMD at the current
-			 * file position. The entry is put as is in the umsdos_dirent
-			 * field of struct umsdos_ioctl. The corresponding mangled
-			 * DOS entry name is put in the dos_dirent field.
-			 * 
-			 * All entries are read including hidden links. Blank
-			 * entries are skipped.
-			 * 
-			 * Return > 0 if success.
-			 */
-
-			old_dent = filp->f_dentry;
-			if (fix_emd_filp (filp) == 0) {
-				while (1) {
-					if (filp->f_pos >= filp->f_dentry->d_inode->i_size) {
-						ret = 0;
-						break;
-					} else {
-						struct umsdos_dirent entry;
-						off_t f_pos = filp->f_pos;
-
-						ret = umsdos_emd_dir_readentry (filp, &entry);
-						if (ret < 0) {
-							break;
-						} else if (entry.name_len > 0) {
-							struct umsdos_info info;
-
-							ret = entry.name_len;
-							umsdos_parse (entry.name, entry.name_len, &info);
-							info.f_pos = f_pos;
-							umsdos_manglename (&info);
-							copy_to_user (&idata->umsdos_dirent, &entry, sizeof (entry));
-							copy_to_user (&idata->dos_dirent.d_name, info.fake.fname, info.fake.len + 1);
-							break;
-						}
-					}
-				}
-				fin_dentry (filp->f_dentry);
-				filp->f_dentry = old_dent;
-				/* iput (filp->f_dentry->d_inode); / * FIXME? */
-			} else {
-				/* The absence of the EMD is simply seen as an EOF */
-				ret = 0;
-			}
-		} else if (cmd == UMSDOS_INIT_EMD) {
-			/* #Specification: ioctl / UMSDOS_INIT_EMD
-			 * The UMSDOS_INIT_EMD command make sure the EMD
-			 * exist for a directory. If it does not, it is
-			 * created. Also, it makes sure the directory functions
-			 * table (struct inode_operations) is set to the UMSDOS
-			 * semantic. This mean that umssync may be applied to
-			 * an "opened" msdos directory, and it will change behavior
-			 * on the fly.
-			 * 
-			 * Return 0 if success.
-			 */
-			extern struct inode_operations umsdos_rdir_inode_operations;
-			struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1);
-
-			ret = emd_dir != NULL;
-			/* iput (emd_dir); / * FIXME?? */
-
-			dir->i_op = ret
-			    ? &umsdos_dir_inode_operations
-			    : &umsdos_rdir_inode_operations;
-		} else {
-			struct umsdos_ioctl data;
-
-			copy_from_user (&data, idata, sizeof (data));
-			if (cmd == UMSDOS_CREAT_EMD) {
-				/* #Specification: ioctl / UMSDOS_CREAT_EMD
-				 * The umsdos_dirent field of the struct umsdos_ioctl is used
-				 * as is to create a new entry in the EMD of the directory.
-				 * The DOS directory is not modified.
-				 * No validation is done (yet).
-				 * 
-				 * Return 0 if success.
-				 */
-				struct umsdos_info info;
-
-				/* This makes sure info.entry and info in general is correctly */
-				/* initialised */
-				memcpy (&info.entry, &data.umsdos_dirent
-					,sizeof (data.umsdos_dirent));
-				umsdos_parse (data.umsdos_dirent.name
-				    ,data.umsdos_dirent.name_len, &info);
-				ret = umsdos_newentry (dir, &info);
-			} else if (cmd == UMSDOS_RENAME_DOS) {
-				struct dentry *old_dentry, *new_dentry;		/* FIXME */
-
-				/* #Specification: ioctl / UMSDOS_RENAME_DOS
-				 * A file or directory is rename in a DOS directory
-				 * (not moved across directory). The source name
-				 * is in the dos_dirent.name field and the destination
-				 * is in umsdos_dirent.name field.
-				 * 
-				 * This ioctl allows umssync to rename a mangle file
-				 * name before syncing it back in the EMD.
-				 */
-				inc_count (dir);
-				inc_count (dir);
-				/*
-				 * ret = msdos_rename (dir
-				 * ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
-				 * ,dir
-				 * ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
-				 */
-				old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, geti_dentry (dir));	/* FIXME: probably should fill inode part */
-				new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, geti_dentry (dir));
-				ret = msdos_rename (dir, old_dentry, dir, new_dentry);
-			} else if (cmd == UMSDOS_UNLINK_EMD) {
-				/* #Specification: ioctl / UMSDOS_UNLINK_EMD
-				 * The umsdos_dirent field of the struct umsdos_ioctl is used
-				 * as is to remove an entry from the EMD of the directory.
-				 * No validation is done (yet). The mode field is used
-				 * to validate S_ISDIR or S_ISREG.
-				 * 
-				 * Return 0 if success.
-				 */
-				struct umsdos_info info;
-
-				/* This makes sure info.entry and info in general is correctly */
-				/* initialised */
-				memcpy (&info.entry, &data.umsdos_dirent
-					,sizeof (data.umsdos_dirent));
-				umsdos_parse (data.umsdos_dirent.name
-				    ,data.umsdos_dirent.name_len, &info);
-				ret = umsdos_delentry (dir, &info
-				     ,S_ISDIR (data.umsdos_dirent.mode));
-			} else if (cmd == UMSDOS_UNLINK_DOS) {
-				struct dentry *dentry, *dp;
-
-				/* #Specification: ioctl / UMSDOS_UNLINK_DOS
-				 * The dos_dirent field of the struct umsdos_ioctl is used to
-				 * execute a msdos_unlink operation. The d_name and d_reclen
-				 * fields are used.
-				 * 
-				 * Return 0 if success.
-				 */
-				dp = geti_dentry (dir);
-				dentry = compat_umsdos_real_lookup (dp, data.dos_dirent.d_name, data.dos_dirent.d_reclen);
-				ret = msdos_unlink (dir, dentry);
-				dput (dentry);	/* FIXME: is this OK now? */
-
-			} else if (cmd == UMSDOS_RMDIR_DOS) {
-				struct dentry *dentry, *dp;
-
-				/* #Specification: ioctl / UMSDOS_RMDIR_DOS
-				 * The dos_dirent field of the struct umsdos_ioctl is used to
-				 * execute a msdos_unlink operation. The d_name and d_reclen
-				 * fields are used.
-				 * 
-				 * Return 0 if success.
-				 */
-				dp = geti_dentry (dir);
-				dentry = compat_umsdos_real_lookup (dp, data.dos_dirent.d_name, data.dos_dirent.d_reclen);
-				ret = msdos_rmdir (dir, dentry);
-				dput (dentry);	/* FIXME: is this OK now? */
-
-			} else if (cmd == UMSDOS_STAT_DOS) {
-				/* #Specification: ioctl / UMSDOS_STAT_DOS
-				 * The dos_dirent field of the struct umsdos_ioctl is
-				 * used to execute a stat operation in the DOS directory.
-				 * The d_name and d_reclen fields are used.
-				 * 
-				 * The following field of umsdos_ioctl.stat are filled.
-				 * 
-				 * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
-				 * Return 0 if success.
-				 */
-				struct inode *inode;
-				struct dentry *d_dir, *dret;
-
-				d_dir = geti_dentry (dir);
-				dret = compat_umsdos_real_lookup (d_dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen);
-				if (dret) {
-					inode = dret->d_inode;
-					data.stat.st_ino = inode->i_ino;
-					data.stat.st_mode = inode->i_mode;
-					data.stat.st_size = inode->i_size;
-					data.stat.st_atime = inode->i_atime;
-					data.stat.st_ctime = inode->i_ctime;
-					data.stat.st_mtime = inode->i_mtime;
-					copy_to_user (&idata->stat, &data.stat, sizeof (data.stat));
-					fin_dentry (dret);
-				}
-			} else if (cmd == UMSDOS_DOS_SETUP) {
-				/* #Specification: ioctl / UMSDOS_DOS_SETUP
-				 * The UMSDOS_DOS_SETUP ioctl allow changing the
-				 * default permission of the MS-DOS filesystem driver
-				 * on the fly.  The MS-DOS driver applies global permissions
-				 * to every file and directory. Normally these permissions
-				 * are controlled by a mount option. This is not
-				 * available for root partition, so a special utility
-				 * (umssetup) is provided to do this, normally in
-				 * /etc/rc.local.
-				 * 
-				 * Be aware that this applies ONLY to MS-DOS directories
-				 * (those without EMD --linux-.---). Umsdos directory
-				 * have independent (standard) permission for each
-				 * and every file.
-				 * 
-				 * The field umsdos_dirent provide the information needed.
-				 * umsdos_dirent.uid and gid sets the owner and group.
-				 * umsdos_dirent.mode set the permissions flags.
-				 */
-				dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
-				dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
-				dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
+			if (new_filp.f_pos >= demd->d_inode->i_size)
+				break;
+
+			ret = umsdos_emd_dir_readentry (&new_filp, &entry);
+			if (ret < 0)
+				break;
+			if (entry.name_len <= 0)
+				continue;
+
+			umsdos_parse (entry.name, entry.name_len, &info);
+			info.f_pos = f_pos;
+			umsdos_manglename (&info);
+			ret = -EFAULT;
+			if (copy_to_user (&idata->umsdos_dirent, &entry,
+							sizeof (entry)))
+				break;
+			if (copy_to_user (&idata->dos_dirent.d_name,
+							info.fake.fname,
+				 			info.fake.len + 1))
+				break;
+			ret = entry.name_len;
+			break;
+		}
+		/* update the original f_pos */
+		filp->f_pos = new_filp.f_pos;
+		d_drop(demd);
+		dput(demd);
+		goto out;
+	}
+	if (cmd == UMSDOS_INIT_EMD) {
+		/* #Specification: ioctl / UMSDOS_INIT_EMD
+		 * The UMSDOS_INIT_EMD command makes sure the EMD
+		 * exists for a directory. If it does not, it is
+		 * created. Also, it makes sure the directory function
+		 * table (struct inode_operations) is set to the UMSDOS
+		 * semantic. This mean that umssync may be applied to
+		 * an "opened" msdos directory, and it will change behavior
+		 * on the fly.
+		 * 
+		 * Return 0 if success.
+		 */
+		extern struct inode_operations umsdos_rdir_inode_operations;
+
+		ret = umsdos_make_emd(dentry);
+		dir->i_op = (ret == 0)
+		    ? &umsdos_dir_inode_operations
+		    : &umsdos_rdir_inode_operations;
+		goto out;
+	}
+
+	ret = -EFAULT;
+	if (copy_from_user (&data, idata, sizeof (data)))
+		goto out;
+
+	if (cmd == UMSDOS_CREAT_EMD) {
+		/* #Specification: ioctl / UMSDOS_CREAT_EMD
+		 * The umsdos_dirent field of the struct umsdos_ioctl is used
+		 * as is to create a new entry in the EMD of the directory.
+		 * The DOS directory is not modified.
+		 * No validation is done (yet).
+		 * 
+		 * Return 0 if success.
+		 */
+		struct umsdos_info info;
+
+		/* This makes sure info.entry and info in general
+		 * is correctly initialised
+		 */
+		memcpy (&info.entry, &data.umsdos_dirent,
+			sizeof (data.umsdos_dirent));
+		umsdos_parse (data.umsdos_dirent.name
+		    ,data.umsdos_dirent.name_len, &info);
+		ret = umsdos_newentry (dentry, &info);
+		goto out;
+	}
+	else if (cmd == UMSDOS_RENAME_DOS) {
+		struct dentry *old_dentry, *new_dentry;		/* FIXME */
+
+		/* #Specification: ioctl / UMSDOS_RENAME_DOS
+		 * A file or directory is renamed in a DOS directory
+		 * (not moved across directory). The source name
+		 * is in the dos_dirent.name field and the destination
+		 * is in umsdos_dirent.name field.
+		 * 
+		 * This ioctl allows umssync to rename a mangle file
+		 * name before syncing it back in the EMD.
+		 */
+		old_dentry = umsdos_lookup_dentry (dentry, 
+						data.dos_dirent.d_name,
+						data.dos_dirent.d_reclen);
+		ret = PTR_ERR(old_dentry);
+		if (IS_ERR(old_dentry))
+			goto out;
+		new_dentry = umsdos_lookup_dentry (dentry,
+						data.umsdos_dirent.name,
+						data.umsdos_dirent.name_len);
+		ret = PTR_ERR(new_dentry);
+		if (!IS_ERR(new_dentry)) {
+printk("umsdos_ioctl: renaming %s/%s to %s/%s\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
+			ret = msdos_rename (dir, old_dentry, dir, new_dentry);
+			dput(new_dentry);
+		}
+		d_drop(old_dentry);
+		dput(old_dentry);
+		goto out;
+	}
+	else if (cmd == UMSDOS_UNLINK_EMD) {
+		/* #Specification: ioctl / UMSDOS_UNLINK_EMD
+		 * The umsdos_dirent field of the struct umsdos_ioctl is used
+		 * as is to remove an entry from the EMD of the directory.
+		 * No validation is done (yet). The mode field is used
+		 * to validate S_ISDIR or S_ISREG.
+		 * 
+		 * Return 0 if success.
+		 */
+		struct umsdos_info info;
+
+		/* This makes sure info.entry and info in general
+		 * is correctly initialised
+		 */
+		memcpy (&info.entry, &data.umsdos_dirent,
+			sizeof (data.umsdos_dirent));
+		umsdos_parse (data.umsdos_dirent.name,
+				data.umsdos_dirent.name_len, &info);
+		ret = umsdos_delentry (dentry, &info,
+				S_ISDIR (data.umsdos_dirent.mode));
+		goto out;
+	}
+	else if (cmd == UMSDOS_UNLINK_DOS) {
+		struct dentry *temp;
+
+		/* #Specification: ioctl / UMSDOS_UNLINK_DOS
+		 * The dos_dirent field of the struct umsdos_ioctl is used to
+		 * execute a msdos_unlink operation. The d_name and d_reclen
+		 * fields are used.
+		 * 
+		 * Return 0 if success.
+		 */
+		temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
+						    data.dos_dirent.d_reclen);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+		ret = -ENOENT;
+		if (temp->d_inode)
+			ret = msdos_unlink (dir, temp);
+		d_drop(temp);
+		dput (temp);
+		goto out;
+	}
+	else if (cmd == UMSDOS_RMDIR_DOS) {
+		struct dentry *temp;
+
+		/* #Specification: ioctl / UMSDOS_RMDIR_DOS
+		 * The dos_dirent field of the struct umsdos_ioctl is used to
+		 * execute a msdos_rmdir operation. The d_name and d_reclen
+		 * fields are used.
+		 * 
+		 * Return 0 if success.
+		 */
+		temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
+						    data.dos_dirent.d_reclen);
+		ret = PTR_ERR(temp);
+		if (IS_ERR(temp))
+			goto out;
+		ret = -ENOENT;
+		if (temp->d_inode)
+			ret = msdos_rmdir (dir, temp);
+		d_drop(temp);
+		dput (temp);
+		goto out;
+
+	} else if (cmd == UMSDOS_STAT_DOS) {
+		/* #Specification: ioctl / UMSDOS_STAT_DOS
+		 * The dos_dirent field of the struct umsdos_ioctl is
+		 * used to execute a stat operation in the DOS directory.
+		 * The d_name and d_reclen fields are used.
+		 * 
+		 * The following field of umsdos_ioctl.stat are filled.
+		 * 
+		 * st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
+		 * Return 0 if success.
+		 */
+		struct dentry *dret;
+		struct inode *inode;
+
+		dret = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
+						    data.dos_dirent.d_reclen);
+		ret = PTR_ERR(dret);
+		if (IS_ERR(dret))
+			goto out;
+		ret = -ENOENT;
+		inode = dret->d_inode;
+		if (inode) {
+			data.stat.st_ino = inode->i_ino;
+			data.stat.st_mode = inode->i_mode;
+			data.stat.st_size = inode->i_size;
+			data.stat.st_atime = inode->i_atime;
+			data.stat.st_ctime = inode->i_ctime;
+			data.stat.st_mtime = inode->i_mtime;
+			ret = -EFAULT;
+			if (!copy_to_user (&idata->stat, &data.stat, 
+						sizeof (data.stat)))
 				ret = 0;
-			}
 		}
+		d_drop(dret);
+		dput(dret);
+		goto out;
+	}
+	else if (cmd == UMSDOS_DOS_SETUP) {
+		/* #Specification: ioctl / UMSDOS_DOS_SETUP
+		 * The UMSDOS_DOS_SETUP ioctl allow changing the
+		 * default permission of the MS-DOS filesystem driver
+		 * on the fly.  The MS-DOS driver applies global permissions
+		 * to every file and directory. Normally these permissions
+		 * are controlled by a mount option. This is not
+		 * available for root partition, so a special utility
+		 * (umssetup) is provided to do this, normally in
+		 * /etc/rc.local.
+		 * 
+		 * Be aware that this applies ONLY to MS-DOS directories
+		 * (those without EMD --linux-.---). Umsdos directory
+		 * have independent (standard) permission for each
+		 * and every file.
+		 * 
+		 * The field umsdos_dirent provide the information needed.
+		 * umsdos_dirent.uid and gid sets the owner and group.
+		 * umsdos_dirent.mode set the permissions flags.
+		 */
+		dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
+		dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
+		dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
+		ret = 0;
 	}
-	Printk (("ioctl return %d\n", ret));
+out:
+	Printk (("ioctl %d, returning %d\n", cmd, ret));
 	return ret;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov