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

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