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