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 (
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
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_RENAME_DOS){
168 /* #Specification: ioctl / UMSDOS_RENAME_DOS
169 A file or directory is rename in a DOS directory
170 (not moved across directory). The source name
171 is in the dos_dirent.name field and the destination
172 is in umsdos_dirent.name field.
173
174 This ioctl allows umssync to rename a mangle file
175 name before syncing it back in the EMD.
176 */
177 dir->i_count += 2;
178 ret = msdos_rename (dir
179 ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
180 ,dir
181 ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
182 }else if (cmd == UMSDOS_UNLINK_EMD){
183 /* #Specification: ioctl / UMSDOS_UNLINK_EMD
184 The umsdos_dirent field of the struct umsdos_ioctl is used
185 as is to remove an entry from the EMD of the directory.
186 No validation is done (yet). The mode field is used
187 to validate S_ISDIR or S_ISREG.
188
189 Return 0 if success.
190 */
191 struct umsdos_info info;
192 /* This makes sure info.entry and info in general is correctly */
193 /* initialised */
194 memcpy (&info.entry,&data.umsdos_dirent
195 ,sizeof(data.umsdos_dirent));
196 umsdos_parse (data.umsdos_dirent.name
197 ,data.umsdos_dirent.name_len,&info);
198 ret = umsdos_delentry (dir,&info
199 ,S_ISDIR(data.umsdos_dirent.mode));
200 }else if (cmd == UMSDOS_UNLINK_DOS){
201 /* #Specification: ioctl / UMSDOS_UNLINK_DOS
202 The dos_dirent field of the struct umsdos_ioctl is used to
203 execute a msdos_unlink operation. The d_name and d_reclen
204 fields are used.
205
206 Return 0 if success.
207 */
208 dir->i_count++;
209 ret = msdos_unlink (dir,data.dos_dirent.d_name
210 ,data.dos_dirent.d_reclen);
211 }else if (cmd == UMSDOS_RMDIR_DOS){
212 /* #Specification: ioctl / UMSDOS_RMDIR_DOS
213 The dos_dirent field of the struct umsdos_ioctl is used to
214 execute a msdos_unlink operation. The d_name and d_reclen
215 fields are used.
216
217 Return 0 if success.
218 */
219 dir->i_count++;
220 ret = msdos_rmdir (dir,data.dos_dirent.d_name
221 ,data.dos_dirent.d_reclen);
222 }else if (cmd == UMSDOS_STAT_DOS){
223 /* #Specification: ioctl / UMSDOS_STAT_DOS
224 The dos_dirent field of the struct umsdos_ioctl is
225 used to execute a stat operation in the DOS directory.
226 The d_name and d_reclen fields are used.
227
228 The following field of umsdos_ioctl.stat are filled.
229
230 st_ino,st_mode,st_size,st_atime,st_mtime,st_ctime,
231 Return 0 if success.
232 */
233 struct inode *inode;
234 ret = umsdos_real_lookup (dir,data.dos_dirent.d_name
235 ,data.dos_dirent.d_reclen,&inode);
236 if (ret == 0){
237 data.stat.st_ino = inode->i_ino;
238 data.stat.st_mode = inode->i_mode;
239 data.stat.st_size = inode->i_size;
240 data.stat.st_atime = inode->i_atime;
241 data.stat.st_ctime = inode->i_ctime;
242 data.stat.st_mtime = inode->i_mtime;
243 memcpy_tofs (&idata->stat,&data.stat,sizeof(data.stat));
244 iput (inode);
245 }
246 }else if (cmd == UMSDOS_DOS_SETUP){
247 /* #Specification: ioctl / UMSDOS_DOS_SETUP
248 The UMSDOS_DOS_SETUP ioctl allow changing the
249 default permission of the MsDOS file system driver
250 on the fly. The MsDOS driver apply global permission
251 to every file and directory. Normally these permissions
252 are controlled by a mount option. This is not
253 available for root partition, so a special utility
254 (umssetup) is provided to do this, normally in
255 /etc/rc.local.
256
257 Be aware that this apply ONLY to MsDOS directory
258 (those without EMD --linux-.---). Umsdos directory
259 have independent (standard) permission for each
260 and every file.
261
262 The field umsdos_dirent provide the information needed.
263 umsdos_dirent.uid and gid sets the owner and group.
264 umsdos_dirent.mode set the permissions flags.
265 */
266 dir->i_sb->u.msdos_sb.fs_uid = data.umsdos_dirent.uid;
267 dir->i_sb->u.msdos_sb.fs_gid = data.umsdos_dirent.gid;
268 dir->i_sb->u.msdos_sb.fs_umask = data.umsdos_dirent.mode;
269 ret = 0;
270 }
271 }
272 }
273 PRINTK (("ioctl return %d\n",ret));
274 return ret;
275 }
276
277
278