patch-2.1.103 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.102/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
@@ -24,326 +24,336 @@
 };
 
 /*
-	Record a single entry the first call.
-	Return -EINVAL the next one.
-*/
-static int umsdos_ioctl_fill(
-	void * buf,
-	const char * name,
-	int name_len,
-	off_t offset,
-	ino_t ino)
+ * Record a single entry the first call.
+ * Return -EINVAL the next one.
+ */
+static int umsdos_ioctl_fill (
+				     void *buf,
+				     const char *name,
+				     int name_len,
+				     off_t offset,
+				     ino_t ino)
 {
-  int ret = -EINVAL;
-  struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
-  if (d->count == 0){
-    copy_to_user (d->ent->d_name,name,name_len);
-    put_user ('\0',d->ent->d_name+name_len);
-    put_user (name_len,&d->ent->d_reclen);
-    put_user (ino,&d->ent->d_ino);
-    put_user (offset,&d->ent->d_off);
-    d->count = 1;
-    ret = 0;
-  }
-  return ret;
+	int ret = -EINVAL;
+	struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
+
+	if (d->count == 0) {
+		copy_to_user (d->ent->d_name, name, name_len);
+		put_user ('\0', d->ent->d_name + name_len);
+		put_user (name_len, &d->ent->d_reclen);
+		put_user (ino, &d->ent->d_ino);
+		put_user (offset, &d->ent->d_off);
+		d->count = 1;
+		ret = 0;
+	}
+	return ret;
 }
 
 
 /*
-	Perform special function on a directory
-*/
+ * Perform special function on a directory
+ */
 int UMSDOS_ioctl_dir (
-		      struct inode *dir,
-		      struct file *filp,
-		      unsigned int cmd,
-		      unsigned long data)
+			     struct inode *dir,
+			     struct file *filp,
+			     unsigned int cmd,
+			     unsigned long data)
 {
-  int ret = -EPERM;
-  int err;
+	int ret = -EPERM;
+	int err;
 
-       /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
-       if(cmd!=UMSDOS_GETVERSION
-          &&cmd!=UMSDOS_READDIR_DOS
-          &&cmd!=UMSDOS_READDIR_EMD
-          &&cmd!=UMSDOS_INIT_EMD
-          &&cmd!=UMSDOS_CREAT_EMD
-          &&cmd!=UMSDOS_RENAME_DOS
-          &&cmd!=UMSDOS_UNLINK_EMD
-          &&cmd!=UMSDOS_UNLINK_DOS
-          &&cmd!=UMSDOS_RMDIR_DOS
-          &&cmd!=UMSDOS_STAT_DOS
-          &&cmd!=UMSDOS_DOS_SETUP)
-              return fat_dir_ioctl(dir,filp,cmd,data);
-
-  /* #Specification: ioctl / acces
-     Only root (effective id) is allowed to do IOCTL on directory
-     in UMSDOS. EPERM is returned for other user.
-  */
-  /*
-    Well, not all cases require write access, but it simplifies
-    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 = 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.
-      */
-      struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0);
-      if (emd_dir != NULL){
-	while (1){
-	  if (filp->f_pos >= emd_dir->i_size){
-	    ret = 0;
-	    break;
-	  }else{
-	    struct umsdos_dirent entry;
-	    off_t f_pos = filp->f_pos;
-	    ret = umsdos_emd_dir_readentry (emd_dir,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;
-	    }
-	  }
-	}
-	/* iput (emd_dir); 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.
-	*/
-	dir->i_count+=2;
-	/*
-	  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, NULL);	/* FIXME: prolly should fill inode part */
-	new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, NULL);
-	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; /* FIXME */
-	/* #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.
-	*/
-	dir->i_count++;
-	/*
-	  ret = msdos_unlink (dir,data.dos_dirent.d_name,data.dos_dirent.d_reclen);
-	*/
-	ret = msdos_unlink(dir,dentry);
-      }else if (cmd == UMSDOS_RMDIR_DOS){
-	struct dentry *dentry; /* FIXME */
-	/* #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.
-	*/
-	dir->i_count++;
+	/* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
+	if (cmd != UMSDOS_GETVERSION
+	    && cmd != UMSDOS_READDIR_DOS
+	    && cmd != UMSDOS_READDIR_EMD
+	    && cmd != UMSDOS_INIT_EMD
+	    && cmd != UMSDOS_CREAT_EMD
+	    && cmd != UMSDOS_RENAME_DOS
+	    && cmd != UMSDOS_UNLINK_EMD
+	    && cmd != UMSDOS_UNLINK_DOS
+	    && cmd != UMSDOS_RMDIR_DOS
+	    && cmd != UMSDOS_STAT_DOS
+	    && cmd != UMSDOS_DOS_SETUP)
+		return fat_dir_ioctl (dir, filp, cmd, data);
+
+	/* #Specification: ioctl / acces
+	 * Only root (effective id) is allowed to do IOCTL on directory
+	 * in UMSDOS. EPERM is returned for other user.
+	 */
 	/*
-	  ret = msdos_rmdir (dir,data.dos_dirent.d_name
-	  ,data.dos_dirent.d_reclen);
-	*/
-	ret = msdos_rmdir(dir,dentry);
-      }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;
-
-	  ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode);
-	if (ret == 0){
-	  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));
-	  /* iput (inode); FIXME */
-	}
-      }else if (cmd == UMSDOS_DOS_SETUP){
-      /* #Specification: ioctl / UMSDOS_DOS_SETUP
-	 The UMSDOS_DOS_SETUP ioctl allow changing the
-	 default permission of the MsDOS file system driver
-	 on the fly. The MsDOS driver apply global permission
-	 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 apply ONLY to MsDOS directory
-	 (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));
-  return ret;
-}
+	 * Well, not all cases require write access, but it simplifies
+	 * 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 = 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.
+			 */
+			struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 0);
 
+			if (emd_dir != NULL) {
+				while (1) {
+					if (filp->f_pos >= emd_dir->i_size) {
+						ret = 0;
+						break;
+					} else {
+						struct umsdos_dirent entry;
+						off_t f_pos = filp->f_pos;
+
+						ret = umsdos_emd_dir_readentry (emd_dir, 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;
+						}
+					}
+				}
+				iput (emd_dir); /* 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: prolly 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.
+				 */
+				inc_count (dir);
+				dp = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, dir, NULL);
+				dentry = creat_dentry ("ioctl_unlink", 12, NULL, dp);
+				ret = msdos_unlink (dir, dentry);
+
+			} 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.
+				 */
+				inc_count (dir);
+				dp = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, dir, NULL);
+				dentry = creat_dentry ("ioctl_unlink", 12, NULL, dp);
+				ret = msdos_rmdir (dir, dentry);
+
+			} 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;
+
+				ret = compat_umsdos_real_lookup (dir, data.dos_dirent.d_name, data.dos_dirent.d_reclen, &inode);
+				if (ret == 0) {
+					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));
+					/* iput (inode); FIXME */
+				}
+			} else if (cmd == UMSDOS_DOS_SETUP) {
+				/* #Specification: ioctl / UMSDOS_DOS_SETUP
+				 * The UMSDOS_DOS_SETUP ioctl allow changing the
+				 * default permission of the MsDOS file system driver
+				 * on the fly. The MsDOS driver apply global permission
+				 * 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 apply ONLY to MsDOS directory
+				 * (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));
+	return ret;
+}

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