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

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