root/fs/umsdos/ioctl.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. umsdos_ioctl_fill
  2. UMSDOS_ioctl_dir

   1 /*
   2  *  linux/fs/umsdos/ioctl.c
   3  *
   4  *  Written 1993 by Jacques Gelinas
   5  *
   6  *  Extended MS-DOS ioctl directory handling functions
   7  */
   8 
   9 #include <asm/segment.h>
  10 #include <linux/errno.h>
  11 #include <linux/mm.h>
  12 #include <linux/kernel.h>
  13 #include <linux/sched.h>
  14 #include <linux/fs.h>
  15 #include <linux/msdos_fs.h>
  16 #include <linux/umsdos_fs.h>
  17 
  18 #define PRINTK(x)
  19 #define Printk(x) printk x
  20 
  21 struct UMSDOS_DIR_ONCE {
  22         struct dirent *ent;
  23         int count;
  24 };
  25 
  26 /*
  27         Record a single entry the first call.
  28         Return -EINVAL the next one.
  29 */
  30 static int umsdos_ioctl_fill(
     /* [previous][next][first][last][top][bottom][index][help] */
  31         void * buf,
  32         const char * name,
  33         int name_len,
  34         off_t offset,
  35         ino_t ino)
  36 {
  37         int ret = -EINVAL;
  38         struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
  39         if (d->count == 0){
  40                 memcpy_tofs (d->ent->d_name,name,name_len);
  41                 put_user ('\0',d->ent->d_name+name_len);
  42                 put_user (name_len,&d->ent->d_reclen);
  43                 put_user (ino,&d->ent->d_ino);
  44                 put_user (offset,&d->ent->d_off);
  45                 d->count = 1;
  46                 ret = 0;
  47         }
  48         return ret;
  49 }
  50 
  51 
  52 /*
  53         Perform special function on a directory
  54 */
  55 int UMSDOS_ioctl_dir (
     /* [previous][next][first][last][top][bottom][index][help] */
  56         struct inode *dir,
  57         struct file *filp,
  58         unsigned int cmd,
  59         unsigned long data)
  60 {
  61         int ret = -EPERM;
  62         int err;
  63         /* #Specification: ioctl / acces
  64                 Only root (effective id) is allowed to do IOCTL on directory
  65                 in UMSDOS. EPERM is returned for other user.
  66         */
  67         /*
  68                 Well, not all cases require write access, but it simplifies
  69                 the code, and let's face it, there is only one client (umssync)
  70                 for all this.
  71         */
  72         if ((err = verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl))) < 0) {
  73                 ret = err;
  74         }else if (current->euid == 0
  75                 || cmd == UMSDOS_GETVERSION){
  76                 struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data;
  77                 ret = -EINVAL;
  78                 /* #Specification: ioctl / prototypes
  79                         The official prototype for the umsdos ioctl on directory
  80                         is:
  81 
  82                         int ioctl (
  83                                 int fd,         // File handle of the directory
  84                                 int cmd,        // command
  85                                 struct umsdos_ioctl *data)
  86 
  87                         The struct and the commands are defined in linux/umsdos_fs.h.
  88 
  89                         umsdos_progs/umsdosio.c provide an interface in C++ to all
  90                         these ioctl. umsdos_progs/udosctl is a small utility showing
  91                         all this.
  92 
  93                         These ioctl generally allow one to work on the EMD or the
  94                         DOS directory independently. These are essential to implement
  95                         the synchronise.
  96                 */
  97                 PRINTK (("ioctl %d ",cmd));
  98                 if (cmd == UMSDOS_GETVERSION){
  99                         /* #Specification: ioctl / UMSDOS_GETVERSION
 100                                 The field version and release of the structure
 101                                 umsdos_ioctl are filled with the version and release
 102                                 number of the fs code in the kernel. This will allow
 103                                 some form of checking. Users won't be able to run
 104                                 incompatible utility such as the synchroniser (umssync).
 105                                 umsdos_progs/umsdosio.c enforce this checking.
 106 
 107                                 Return always 0.
 108                         */
 109                         put_fs_byte (UMSDOS_VERSION,&idata->version);
 110                         put_fs_byte (UMSDOS_RELEASE,&idata->release);
 111                         ret = 0;
 112                 }else if (cmd == UMSDOS_READDIR_DOS){
 113                         /* #Specification: ioctl / UMSDOS_READDIR_DOS
 114                                 One entry is read from the DOS directory at the current
 115                                 file position. The entry is put as is in the dos_dirent
 116                                 field of struct umsdos_ioctl.
 117 
 118                                 Return > 0 if success.
 119                         */
 120                         struct UMSDOS_DIR_ONCE bufk;
 121                         bufk.count = 0;
 122                         bufk.ent = &idata->dos_dirent;
 123                         fat_readdir(dir,filp,&bufk,umsdos_ioctl_fill);
 124                         ret = bufk.count == 1 ? 1 : 0;
 125                 }else if (cmd == UMSDOS_READDIR_EMD){
 126                         /* #Specification: ioctl / UMSDOS_READDIR_EMD
 127                                 One entry is read from the EMD at the current
 128                                 file position. The entry is put as is in the umsdos_dirent
 129                                 field of struct umsdos_ioctl. The corresponding mangled
 130                                 DOS entry name is put in the dos_dirent field.
 131 
 132                                 All entries are read including hidden links. Blank
 133                                 entries are skipped.
 134 
 135                                 Return > 0 if success.
 136                         */
 137                         struct inode *emd_dir = umsdos_emd_dir_lookup (dir,0);
 138                         if (emd_dir != NULL){
 139                                 while (1){
 140                                         if (filp->f_pos >= emd_dir->i_size){
 141                                                 ret = 0;
 142                                                 break;
 143                                         }else{
 144                                                 struct umsdos_dirent entry;
 145                                                 off_t f_pos = filp->f_pos;
 146                                                 ret = umsdos_emd_dir_readentry (emd_dir,filp,&entry);
 147                                                 if (ret < 0){
 148                                                         break;
 149                                                 }else if (entry.name_len > 0){
 150                                                         struct umsdos_info info;
 151                                                         ret = entry.name_len;
 152                                                         umsdos_parse (entry.name,entry.name_len,&info);
 153                                                         info.f_pos = f_pos;
 154                                                         umsdos_manglename(&info);
 155                                                         memcpy_tofs(&idata->umsdos_dirent,&entry
 156                                                                 ,sizeof(entry));
 157                                                         memcpy_tofs(&idata->dos_dirent.d_name
 158                                                                 ,info.fake.fname,info.fake.len+1);
 159                                                         break;
 160                                                 }
 161                                         }
 162                                 }
 163                                 iput (emd_dir);
 164                         }else{
 165                                 /* The absence of the EMD is simply seen as an EOF */
 166                                 ret = 0;
 167                         }
 168                 }else if (cmd == UMSDOS_INIT_EMD){
 169                         /* #Specification: ioctl / UMSDOS_INIT_EMD
 170                                 The UMSDOS_INIT_EMD command make sure the EMD
 171                                 exist for a directory. If it does not, it is
 172                                 created. Also, it makes sure the directory functions
 173                                 table (struct inode_operations) is set to the UMSDOS
 174                                 semantic. This mean that umssync may be applied to
 175                                 an "opened" msdos directory, and it will change behavior
 176                                 on the fly.
 177 
 178                                 Return 0 if success.
 179                         */
 180                         extern struct inode_operations umsdos_rdir_inode_operations;
 181                         struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
 182                         ret = emd_dir != NULL;
 183                         iput (emd_dir);
 184                                         
 185                         dir->i_op = ret
 186                                 ? &umsdos_dir_inode_operations
 187                                 : &umsdos_rdir_inode_operations;
 188                 }else{
 189                         struct umsdos_ioctl data;
 190                         memcpy_fromfs (&data,idata,sizeof(data));
 191                         if (cmd == UMSDOS_CREAT_EMD){
 192                                 /* #Specification: ioctl / UMSDOS_CREAT_EMD
 193                                         The umsdos_dirent field of the struct umsdos_ioctl is used
 194                                         as is to create a new entry in the EMD of the directory.
 195                                         The DOS directory is not modified.
 196                                         No validation is done (yet).
 197 
 198                                         Return 0 if success.
 199                                 */
 200                                 struct umsdos_info info;
 201                                 /* This makes sure info.entry and info in general is correctly */
 202                                 /* initialised */
 203                                 memcpy (&info.entry,&data.umsdos_dirent
 204                                         ,sizeof(data.umsdos_dirent));
 205                                 umsdos_parse (data.umsdos_dirent.name
 206                                         ,data.umsdos_dirent.name_len,&info);
 207                                 ret = umsdos_newentry (dir,&info);
 208                         }else if (cmd == UMSDOS_RENAME_DOS){
 209                                 /* #Specification: ioctl / UMSDOS_RENAME_DOS
 210                                         A file or directory is rename in a DOS directory
 211                                         (not moved across directory). The source name
 212                                         is in the dos_dirent.name field and the destination
 213                                         is in umsdos_dirent.name field.
 214 
 215                                         This ioctl allows umssync to rename a mangle file
 216                                         name before syncing it back in the EMD.
 217                                 */
 218                                 dir->i_count += 2;
 219                                 ret = msdos_rename (dir
 220                                         ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
 221                                         ,dir
 222                                         ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
 223                         }else if (cmd == UMSDOS_UNLINK_EMD){
 224                                 /* #Specification: ioctl / UMSDOS_UNLINK_EMD
 225                                         The umsdos_dirent field of the struct umsdos_ioctl is used
 226                                         as is to remove an entry from the EMD of the directory.
 227                                         No validation is done (yet). The mode field is used
 228                                         to validate S_ISDIR or S_ISREG.
 229 
 230                                         Return 0 if success.
 231                                 */
 232                                 struct umsdos_info info;
 233                                 /* This makes sure info.entry and info in general is correctly */
 234                                 /* initialised */
 235                                 memcpy (&info.entry,&data.umsdos_dirent
 236                                         ,sizeof(data.umsdos_dirent));
 237                                 umsdos_parse (data.umsdos_dirent.name
 238                                         ,data.umsdos_dirent.name_len,&info);
 239                                 ret = umsdos_delentry (dir,&info
 240                                         ,S_ISDIR(data.umsdos_dirent.mode));
 241                         }else if (cmd == UMSDOS_UNLINK_DOS){
 242                                 /* #Specification: ioctl / UMSDOS_UNLINK_DOS
 243                                         The dos_dirent field of the struct umsdos_ioctl is used to
 244                                         execute a msdos_unlink operation. The d_name and d_reclen
 245                                         fields are used.
 246 
 247                                         Return 0 if success.
 248                                 */
 249                                 dir->i_count++;
 250                                 ret = msdos_unlink (dir,data.dos_dirent.d_name
 251                                         ,data.dos_dirent.d_reclen);
 252                         }else if (cmd == UMSDOS_RMDIR_DOS){
 253                                 /* #Specification: ioctl / UMSDOS_RMDIR_DOS
 254                                         The dos_dirent field of the struct umsdos_ioctl is used to
 255                                         execute a msdos_unlink operation. The d_name and d_reclen
 256                                         fields are used.
 257 
 258                                         Return 0 if success.
 259                                 */
 260                                 dir->i_count++;
 261                                 ret = msdos_rmdir (dir,data.dos_dirent.d_name
 262                                         ,data.dos_dirent.d_reclen);
 263                         }else if (cmd == UMSDOS_STAT_DOS){
 264                                 /* #Specification: ioctl / UMSDOS_STAT_DOS
 265                                         The dos_dirent field of the struct umsdos_ioctl is
 266                                         used to execute a stat operation in the DOS directory.
 267                                         The d_name and d_reclen fields are used.
 268 
 269                                         The following field of umsdos_ioctl.stat are filled.
 270 
 271                                         st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
 272                                         Return 0 if success.
 273                                 */
 274                                 struct inode *inode;
 275                                 ret = umsdos_real_lookup (dir,data.dos_dirent.d_name
 276                                         ,data.dos_dirent.d_reclen,&inode);
 277                                 if (ret == 0){
 278                                         data.stat.st_ino = inode->i_ino;
 279                                         data.stat.st_mode = inode->i_mode;
 280                                         data.stat.st_size = inode->i_size;
 281                                         data.stat.st_atime = inode->i_atime;
 282                                         data.stat.st_ctime = inode->i_ctime;
 283                                         data.stat.st_mtime = inode->i_mtime;
 284                                         memcpy_tofs (&idata->stat,&data.stat,sizeof(data.stat));
 285                                         iput (inode);
 286                                 }
 287                         }else if (cmd == UMSDOS_DOS_SETUP){
 288                                 /* #Specification: ioctl / UMSDOS_DOS_SETUP
 289                                         The UMSDOS_DOS_SETUP ioctl allow changing the
 290                                         default permission of the MsDOS file system driver
 291                                         on the fly. The MsDOS driver apply global permission
 292                                         to every file and directory. Normally these permissions
 293                                         are controlled by a mount option. This is not
 294                                         available for root partition, so a special utility
 295                                         (umssetup) is provided to do this, normally in
 296                                         /etc/rc.local.
 297 
 298                                         Be aware that this apply ONLY to MsDOS directory
 299                                         (those without EMD --linux-.---). Umsdos directory
 300                                         have independent (standard) permission for each
 301                                         and every file.
 302 
 303                                         The field umsdos_dirent provide the information needed.
 304                                         umsdos_dirent.uid and gid sets the owner and group.
 305                                         umsdos_dirent.mode set the permissions flags.
 306                                 */
 307                                 dir->i_sb->u.msdos_sb.options.fs_uid = data.umsdos_dirent.uid;
 308                                 dir->i_sb->u.msdos_sb.options.fs_gid = data.umsdos_dirent.gid;
 309                                 dir->i_sb->u.msdos_sb.options.fs_umask = data.umsdos_dirent.mode;
 310                                 ret = 0;
 311                         }
 312                 }
 313         }
 314         PRINTK (("ioctl return %d\n",ret));
 315         return ret;
 316 }
 317 
 318 
 319 

/* [previous][next][first][last][top][bottom][index][help] */