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