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

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