1 /*
2 * linux/fs/umsdos/namei.c
3 *
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... by Werner Almesberger
6 *
7 * Maintain and access the --linux alternate directory file.
8 */
9 #include <linux/errno.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/types.h>
13 #include <linux/fcntl.h>
14 #include <linux/stat.h>
15 #include <linux/string.h>
16 #include <linux/msdos_fs.h>
17 #include <linux/umsdos_fs.h>
18 #include <linux/malloc.h>
19
20 #define PRINTK(x)
21 #define Printk(x) printk x
22
23 #if 1
24 /*
25 Wait for creation exclusivity.
26 Return 0 if the dir was already available.
27 Return 1 if a wait was necessary.
28 When 1 is return, it means a wait was done. It does not
29 mean the directory is available.
30 */
31 static int umsdos_waitcreate(struct inode *dir)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
32 {
33 int ret = 0;
34 if (dir->u.umsdos_i.u.dir_info.creating
35 && dir->u.umsdos_i.u.dir_info.pid != current->pid){
36 sleep_on(&dir->u.umsdos_i.u.dir_info.p);
37 ret = 1;
38 }
39 return ret;
40 }
41 /*
42 Wait for any lookup process to finish
43 */
44 static void umsdos_waitlookup (struct inode *dir)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
45 {
46 while (dir->u.umsdos_i.u.dir_info.looking){
47 sleep_on(&dir->u.umsdos_i.u.dir_info.p);
48 }
49 }
50 /*
51 Lock all other process out of this directory.
52 */
53 void umsdos_lockcreate (struct inode *dir)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
54 {
55 /* #Specification: file creation / not atomic
56 File creation is a two step process. First we create (allocate)
57 an entry in the EMD file and then (using the entry offset) we
58 build a unique name for MSDOS. We create this name in the msdos
59 space.
60
61 We have to use semaphore (sleep_on/wake_up) to prevent lookup
62 into a directory when we create a file or directory and to
63 prevent creation while a lookup is going on. Since many lookup
64 may happen at the same time, the semaphore is a counter.
65
66 Only one creation is allowed at the same time. This protection
67 may not be necessary. The problem arise mainly when a lookup
68 or a readdir is done while a file is partially created. The
69 lookup process see that as a "normal" problem and silently
70 erase the file from the EMD file. Normal because a file
71 may be erased during a MSDOS session, but not removed from
72 the EMD file.
73
74 The locking is done on a directory per directory basis. Each
75 directory inode has its wait_queue.
76
77 For some operation like hard link, things even get worse. Many
78 creation must occur at once (atomic). To simplify the design
79 a process is allowed to recursively lock the directory for
80 creation. The pid of the locking process is kept along with
81 a counter so a second level of locking is granted or not.
82 */
83 /*
84 Wait for any creation process to finish except
85 if we (the process) own the lock
86 */
87 while (umsdos_waitcreate(dir)!=0);
88 dir->u.umsdos_i.u.dir_info.creating++;
89 dir->u.umsdos_i.u.dir_info.pid = current->pid;
90 umsdos_waitlookup (dir);
91 }
92 /*
93 Lock all other process out of those two directories.
94 */
95 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
96 {
97 /*
98 We must check that both directory are available before
99 locking anyone of them. This is to avoid some deadlock.
100 Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
101 this to me.
102 */
103 while (1){
104 if (umsdos_waitcreate(dir1)==0
105 && umsdos_waitcreate(dir2)==0){
106 /* We own both now */
107 dir1->u.umsdos_i.u.dir_info.creating++;
108 dir1->u.umsdos_i.u.dir_info.pid = current->pid;
109 dir2->u.umsdos_i.u.dir_info.creating++;
110 dir2->u.umsdos_i.u.dir_info.pid = current->pid;
111 break;
112 }
113 }
114 umsdos_waitlookup(dir1);
115 umsdos_waitlookup(dir2);
116 }
117 /*
118 Wait until creation is finish in this directory.
119 */
120 void umsdos_startlookup (struct inode *dir)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
121 {
122 while (umsdos_waitcreate (dir) != 0);
123 dir->u.umsdos_i.u.dir_info.looking++;
124 }
125 void check_page_tables(void);
126
127 /*
128 Unlock the directory.
129 */
130 void umsdos_unlockcreate (struct inode *dir)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
131 {
132 dir->u.umsdos_i.u.dir_info.creating--;
133 if (dir->u.umsdos_i.u.dir_info.creating < 0){
134 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
135 ,dir->u.umsdos_i.u.dir_info.creating);
136 }
137 wake_up (&dir->u.umsdos_i.u.dir_info.p);
138 }
139 /*
140 Tell directory lookup is over.
141 */
142 void umsdos_endlookup (struct inode *dir)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
143 {
144 dir->u.umsdos_i.u.dir_info.looking--;
145 if (dir->u.umsdos_i.u.dir_info.looking < 0){
146 printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
147 ,dir->u.umsdos_i.u.dir_info.looking);
148 }
149 wake_up (&dir->u.umsdos_i.u.dir_info.p);
150 }
151 #else
152 static void umsdos_lockcreate (struct inode *dir){}
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
153 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
154 void umsdos_startlookup (struct inode *dir){}
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
155 static void umsdos_unlockcreate (struct inode *dir){}
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
156 void umsdos_endlookup (struct inode *dir){}
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
157 #endif
158 static int umsdos_nevercreat(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
159 struct inode *dir,
160 const char *name, /* Name of the file to add */
161 int len,
162 int errcod) /* Length of the name */
163 {
164 int ret = 0;
165 if (umsdos_is_pseudodos(dir,name,len)){
166 /* #Specification: pseudo root / any file creation /DOS
167 The pseudo sub-directory /DOS can't be created!
168 EEXIST is returned.
169
170 The pseudo sub-directory /DOS can't be removed!
171 EPERM is returned.
172 */
173 ret = -EPERM;
174 ret = errcod;
175 }else if (name[0] == '.'
176 && (len == 1 || (len == 2 && name[1] == '.'))){
177 /* #Specification: create / . and ..
178 If one try to creates . or .., it always fail and return
179 EEXIST.
180
181 If one try to delete . or .., it always fail and return
182 EPERM.
183
184 This should be test at the VFS layer level to avoid
185 duplicating this in all file systems. Any comments ?
186 */
187 ret = errcod;
188 }
189 return ret;
190 }
191
192 /*
193 Add a new file (ordinary or special) into the alternate directory.
194 The file is added to the real MSDOS directory. If successful, it
195 is then added to the EDM file.
196
197 Return the status of the operation. 0 mean success.
198 */
199 static int umsdos_create_any (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
200 struct inode *dir,
201 const char *name, /* Name of the file to add */
202 int len, /* Length of the name */
203 int mode, /* Permission bit + file type ??? */
204 int rdev, /* major, minor or 0 for ordinary file */
205 /* and symlinks */
206 char flags,
207 struct inode **result) /* Will hold the inode of the newly created */
208 /* file */
209 {
210 int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
211 if (ret == 0){
212 struct umsdos_info info;
213 ret = umsdos_parse (name,len,&info);
214 *result = NULL;
215 if (ret == 0){
216 info.entry.mode = mode;
217 info.entry.rdev = rdev;
218 info.entry.flags = flags;
219 info.entry.uid = current->fsuid;
220 info.entry.gid = (dir->i_mode & S_ISGID)
221 ? dir->i_gid : current->fsgid;
222 info.entry.ctime = info.entry.atime = info.entry.mtime
223 = CURRENT_TIME;
224 info.entry.nlink = 1;
225 umsdos_lockcreate(dir);
226 ret = umsdos_newentry (dir,&info);
227 if (ret == 0){
228 dir->i_count++;
229 ret = msdos_create (dir,info.fake.fname,info.fake.len
230 ,S_IFREG|0777,result);
231 if (ret == 0){
232 struct inode *inode = *result;
233 umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
234 PRINTK (("inode %p[%d] ",inode,inode->i_count));
235 PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
236 ,info.fake.fname,current->pid,info.f_pos));
237 }else{
238 /* #Specification: create / file exist in DOS
239 Here is a situation. Trying to create a file with
240 UMSDOS. The file is unknown to UMSDOS but already
241 exist in the DOS directory.
242
243 Here is what we are NOT doing:
244
245 We could silently assume that everything is fine
246 and allows the creation to succeed.
247
248 It is possible not all files in the partition
249 are mean to be visible from linux. By trying to create
250 those file in some directory, one user may get access
251 to those file without proper permissions. Looks like
252 a security hole to me. Off course sharing a file system
253 with DOS is some kind of security hole :-)
254
255 So ?
256
257 We return EEXIST in this case.
258 The same is true for directory creation.
259 */
260 if (ret == -EEXIST){
261 printk ("UMSDOS: out of sync, Creation error [%ld], "
262 "deleting %s %d %d pos %ld\n",dir->i_ino
263 ,info.fake.fname,-ret,current->pid,info.f_pos);
264 }
265 umsdos_delentry (dir,&info,0);
266 }
267 PRINTK (("umsdos_create %s ret = %d pos %d\n"
268 ,info.fake.fname,ret,info.f_pos));
269 }
270 umsdos_unlockcreate(dir);
271 }
272 }
273 iput (dir);
274 return ret;
275 }
276 /*
277 Initialise the new_entry from the old for a rename operation.
278 (Only useful for umsdos_rename_f() below).
279 */
280 static void umsdos_ren_init(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
281 struct umsdos_info *new_info,
282 struct umsdos_info *old_info,
283 int flags) /* 0 == copy flags from old_name */
284 /* != 0, this is the value of flags */
285 {
286 new_info->entry.mode = old_info->entry.mode;
287 new_info->entry.rdev = old_info->entry.rdev;
288 new_info->entry.uid = old_info->entry.uid;
289 new_info->entry.gid = old_info->entry.gid;
290 new_info->entry.ctime = old_info->entry.ctime;
291 new_info->entry.atime = old_info->entry.atime;
292 new_info->entry.mtime = old_info->entry.mtime;
293 new_info->entry.flags = flags ? flags : old_info->entry.flags;
294 new_info->entry.nlink = old_info->entry.nlink;
295 }
296
297 #define chkstk() \
298 if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
299 printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
300 , current->comm,STACK_MAGIC \
301 ,*(unsigned long *)current->kernel_stack_page \
302 ,__LINE__); \
303 }
304
305 /*
306 Rename a file (move) in the file system.
307 */
308 static int umsdos_rename_f(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
309 struct inode * old_dir,
310 const char * old_name,
311 int old_len,
312 struct inode * new_dir,
313 const char * new_name,
314 int new_len,
315 int flags) /* 0 == copy flags from old_name */
316 /* != 0, this is the value of flags */
317 {
318 int ret = EPERM;
319 struct umsdos_info old_info;
320 int old_ret = umsdos_parse (old_name,old_len,&old_info);
321 struct umsdos_info new_info;
322 int new_ret = umsdos_parse (new_name,new_len,&new_info);
323 chkstk();
324 PRINTK (("umsdos_rename %d %d ",old_ret,new_ret));
325 if (old_ret == 0 && new_ret == 0){
326 umsdos_lockcreate2(old_dir,new_dir);
327 chkstk();
328 PRINTK (("old findentry "));
329 ret = umsdos_findentry(old_dir,&old_info,0);
330 chkstk();
331 PRINTK (("ret %d ",ret));
332 if (ret == 0){
333 PRINTK (("new newentry "));
334 umsdos_ren_init(&new_info,&old_info,flags);
335 ret = umsdos_newentry (new_dir,&new_info);
336 chkstk();
337 PRINTK (("ret %d %d ",ret,new_info.fake.len));
338 if (ret == 0){
339 PRINTK (("msdos_rename "));
340 old_dir->i_count++;
341 new_dir->i_count++; /* Both inode are needed later */
342 ret = msdos_rename (old_dir
343 ,old_info.fake.fname,old_info.fake.len
344 ,new_dir
345 ,new_info.fake.fname,new_info.fake.len);
346 chkstk();
347 PRINTK (("after m_rename ret %d ",ret));
348 if (ret != 0){
349 umsdos_delentry (new_dir,&new_info
350 ,S_ISDIR(new_info.entry.mode));
351 chkstk();
352 }else{
353 ret = umsdos_delentry (old_dir,&old_info
354 ,S_ISDIR(old_info.entry.mode));
355 chkstk();
356 if (ret == 0){
357 /*
358 This UMSDOS_lookup does not look very useful.
359 It makes sure that the inode of the file will
360 be correctly setup (umsdos_patch_inode()) in
361 case it is already in use.
362
363 Not very efficient ...
364 */
365 struct inode *inode;
366 new_dir->i_count++;
367 PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
368 ret = UMSDOS_lookup (new_dir,new_name,new_len
369 ,&inode);
370 chkstk();
371 if (ret != 0){
372 printk ("UMSDOS: partial rename for file %s\n"
373 ,new_info.entry.name);
374 }else{
375 /*
376 Update f_pos so notify_change will succeed
377 if the file was already in use.
378 */
379 umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
380 chkstk();
381 iput (inode);
382 }
383 }
384 }
385 }
386 }
387 umsdos_unlockcreate(old_dir);
388 umsdos_unlockcreate(new_dir);
389 }
390 iput (old_dir);
391 iput (new_dir);
392 PRINTK (("\n"));
393 return ret;
394 }
395 /*
396 Setup un Symbolic link or a (pseudo) hard link
397 Return a negative error code or 0 if ok.
398 */
399 static int umsdos_symlink_x(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
400 struct inode * dir,
401 const char * name,
402 int len,
403 const char * symname, /* name will point to this path */
404 int mode,
405 char flags)
406 {
407 /* #Specification: symbolic links / strategy
408 A symbolic link is simply a file which hold a path. It is
409 implemented as a normal MSDOS file (not very space efficient :-()
410
411 I see 2 different way to do it. One is to place the link data
412 in unused entry of the EMD file. The other is to have a separate
413 file dedicated to hold all symbolic links data.
414
415 Lets go for simplicity...
416 */
417 struct inode *inode;
418 int ret;
419 dir->i_count++; /* We keep the inode in case we need it */
420 /* later */
421 ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
422 PRINTK (("umsdos_symlink ret %d ",ret));
423 if (ret == 0){
424 int len = strlen(symname);
425 struct file filp;
426 filp.f_pos = 0;
427 /* Make the inode acceptable to MSDOS */
428 ret = umsdos_file_write_kmem (inode,&filp,(char*)symname,len);
429 iput (inode);
430 if (ret >= 0){
431 if (ret != len){
432 ret = -EIO;
433 printk ("UMSDOS: "
434 "Can't write symbolic link data\n");
435 }else{
436 ret = 0;
437 }
438 }
439 if (ret != 0){
440 UMSDOS_unlink (dir,name,len);
441 dir = NULL;
442 }
443 }
444 iput (dir);
445 PRINTK (("\n"));
446 return ret;
447 }
448 /*
449 Setup un Symbolic link.
450 Return a negative error code or 0 if ok.
451 */
452 int UMSDOS_symlink(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
453 struct inode * dir,
454 const char * name,
455 int len,
456 const char * symname) /* name will point to this path */
457 {
458 return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
459 }
460 /*
461 Add a link to an inode in a directory
462 */
463 int UMSDOS_link (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
464 struct inode * oldinode,
465 struct inode * dir,
466 const char * name,
467 int len)
468 {
469 /* #Specification: hard link / strategy
470 Well ... hard link are difficult to implement on top of an
471 MsDOS fat file system. Unlike UNIX file systems, there are no
472 inode. A directory entry hold the functionality of the inode
473 and the entry.
474
475 We will used the same strategy as a normal Unix file system
476 (with inode) except we will do it symbolically (using paths).
477
478 Because anything can happen during a DOS session (defragment,
479 directory sorting, etc...), we can't rely on MsDOS pseudo
480 inode number to record the link. For this reason, the link
481 will be done using hidden symbolic links. The following
482 scenario illustrate how it work.
483
484 Given a file /foo/file
485
486 ln /foo/file /tmp/file2
487
488 become internally
489
490 mv /foo/file /foo/-LINK1
491 ln -s /foo/-LINK1 /foo/file
492 ln -s /foo/-LINK1 /tmp/file2
493
494 Using this strategy, we can operate on /foo/file or /foo/file2.
495 We can remove one and keep the other, like a normal Unix hard link.
496 We can rename /foo/file or /tmp/file2 independently.
497
498 The entry -LINK1 will be hidden. It will hold a link count.
499 When all link are erased, the hidden file is erased too.
500 */
501 /* #Specification: weakness / hard link
502 The strategy for hard link introduces a side effect that
503 may or may not be acceptable. Here is the sequence
504
505 mkdir subdir1
506 touch subdir1/file
507 mkdir subdir2
508 ln subdir1/file subdir2/file
509 rm subdir1/file
510 rmdir subdir1
511 rmdir: subdir1: Directory not empty
512
513 This happen because there is an invisible file (--link) in
514 subdir1 which is referenced by subdir2/file.
515
516 Any idea ?
517 */
518 /* #Specification: weakness / hard link / rename directory
519 Another weakness of hard link come from the fact that
520 it is based on hidden symbolic links. Here is an example.
521
522 mkdir /subdir1
523 touch /subdir1/file
524 mkdir /subdir2
525 ln /subdir1/file subdir2/file
526 mv /subdir1 subdir3
527 ls -l /subdir2/file
528
529 Since /subdir2/file is a hidden symbolic link
530 to /subdir1/..hlinkNNN, accessing it will fail since
531 /subdir1 does not exist anymore (has been renamed).
532 */
533 int ret = 0;
534 if (S_ISDIR(oldinode->i_mode)){
535 /* #Specification: hard link / directory
536 A hard link can't be made on a directory. EPERM is returned
537 in this case.
538 */
539 ret = -EPERM;
540 }else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){
541 struct inode *olddir;
542 ret = umsdos_get_dirowner(oldinode,&olddir);
543 PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
544 ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
545 if (ret == 0){
546 struct umsdos_dirent entry;
547 umsdos_lockcreate2(dir,olddir);
548 ret = umsdos_inode2entry (olddir,oldinode,&entry);
549 if (ret == 0){
550 PRINTK (("umsdos_link :%s: ino %d flags %d "
551 ,entry.name
552 ,oldinode->i_ino,entry.flags));
553 if (!(entry.flags & UMSDOS_HIDDEN)){
554 /* #Specification: hard link / first hard link
555 The first time a hard link is done on a file, this
556 file must be renamed and hidden. Then an internal
557 symbolic link must be done on the hidden file.
558
559 The second link is done after on this hidden file.
560
561 It is expected that the Linux MSDOS file system
562 keeps the same pseudo inode when a rename operation
563 is done on a file in the same directory.
564 */
565 struct umsdos_info info;
566 ret = umsdos_newhidden (olddir,&info);
567 if (ret == 0){
568 olddir->i_count+=2;
569 PRINTK (("olddir[%d] ",olddir->i_count));
570 ret = umsdos_rename_f (olddir,entry.name
571 ,entry.name_len
572 ,olddir,info.entry.name,info.entry.name_len
573 ,UMSDOS_HIDDEN);
574 if (ret == 0){
575 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
576 if (path == NULL){
577 ret = -ENOMEM;
578 }else{
579 PRINTK (("olddir[%d] ",olddir->i_count));
580 ret = umsdos_locate_path (oldinode,path);
581 PRINTK (("olddir[%d] ",olddir->i_count));
582 if (ret == 0){
583 olddir->i_count++;
584 ret = umsdos_symlink_x (olddir
585 ,entry.name
586 ,entry.name_len,path
587 ,S_IFREG|0777,UMSDOS_HLINK);
588 if (ret == 0){
589 dir->i_count++;
590 ret = umsdos_symlink_x (dir,name,len
591 ,path
592 ,S_IFREG|0777,UMSDOS_HLINK);
593 }
594 }
595 kfree (path);
596 }
597 }
598 }
599 }else{
600 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
601 if (path == NULL){
602 ret = -ENOMEM;
603 }else{
604 ret = umsdos_locate_path (oldinode,path);
605 if (ret == 0){
606 dir->i_count++;
607 ret = umsdos_symlink_x (dir,name,len,path
608 ,S_IFREG|0777,UMSDOS_HLINK);
609 }
610 kfree (path);
611 }
612 }
613 }
614 umsdos_unlockcreate(olddir);
615 umsdos_unlockcreate(dir);
616 }
617 iput (olddir);
618 }
619 if (ret == 0){
620 struct iattr newattrs;
621 oldinode->i_nlink++;
622 newattrs.ia_valid = 0;
623 ret = UMSDOS_notify_change(oldinode, &newattrs);
624 }
625 iput (oldinode);
626 iput (dir);
627 PRINTK (("umsdos_link %d\n",ret));
628 return ret;
629 }
630 /*
631 Add a new file into the alternate directory.
632 The file is added to the real MSDOS directory. If successful, it
633 is then added to the EDM file.
634
635 Return the status of the operation. 0 mean success.
636 */
637 int UMSDOS_create (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
638 struct inode *dir,
639 const char *name, /* Name of the file to add */
640 int len, /* Length of the name */
641 int mode, /* Permission bit + file type ??? */
642 struct inode **result) /* Will hold the inode of the newly created */
643 /* file */
644 {
645 return umsdos_create_any (dir,name,len,mode,0,0,result);
646 }
647 /*
648 Add a sub-directory in a directory
649 */
650 int UMSDOS_mkdir(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
651 struct inode * dir,
652 const char * name,
653 int len,
654 int mode)
655 {
656 int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
657 if (ret == 0){
658 struct umsdos_info info;
659 ret = umsdos_parse (name,len,&info);
660 PRINTK (("umsdos_mkdir %d\n",ret));
661 if (ret == 0){
662 info.entry.mode = mode | S_IFDIR;
663 info.entry.rdev = 0;
664 info.entry.uid = current->fsuid;
665 info.entry.gid = (dir->i_mode & S_ISGID)
666 ? dir->i_gid : current->fsgid;
667 info.entry.ctime = info.entry.atime = info.entry.mtime
668 = CURRENT_TIME;
669 info.entry.flags = 0;
670 umsdos_lockcreate(dir);
671 info.entry.nlink = 1;
672 ret = umsdos_newentry (dir,&info);
673 PRINTK (("newentry %d ",ret));
674 if (ret == 0){
675 dir->i_count++;
676 ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
677 if (ret != 0){
678 umsdos_delentry (dir,&info,1);
679 /* #Specification: mkdir / Directory already exist in DOS
680 We do the same thing as for file creation.
681 For all user it is an error.
682 */
683 }else{
684 /* #Specification: mkdir / umsdos directory / create EMD
685 When we created a new sub-directory in a UMSDOS
686 directory (one with full UMSDOS semantic), we
687 create immediately an EMD file in the new
688 sub-directory so it inherit UMSDOS semantic.
689 */
690 struct inode *subdir;
691 ret = umsdos_real_lookup (dir,info.fake.fname
692 ,info.fake.len,&subdir);
693 if (ret == 0){
694 struct inode *result;
695 ret = msdos_create (subdir,UMSDOS_EMD_FILE
696 ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
697 subdir = NULL;
698 iput (result);
699 }
700 if (ret < 0){
701 printk ("UMSDOS: Can't create empty --linux-.---\n");
702 }
703 iput (subdir);
704 }
705 }
706 umsdos_unlockcreate(dir);
707 }
708 }
709 PRINTK (("umsdos_mkdir %d\n",ret));
710 iput (dir);
711 return ret;
712 }
713 /*
714 Add a new device special file into a directory.
715 */
716 int UMSDOS_mknod(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
717 struct inode * dir,
718 const char * name,
719 int len,
720 int mode,
721 int rdev)
722 {
723 /* #Specification: Special files / strategy
724 Device special file, pipes, etc ... are created like normal
725 file in the msdos file system. Of course they remain empty.
726
727 One strategy was to create those files only in the EMD file
728 since they were not important for MSDOS. The problem with
729 that, is that there were not getting inode number allocated.
730 The MSDOS filesystems is playing a nice game to fake inode
731 number, so why not use it.
732
733 The absence of inode number compatible with those allocated
734 for ordinary files was causing major trouble with hard link
735 in particular and other parts of the kernel I guess.
736 */
737 struct inode *inode;
738 int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
739 iput (inode);
740 return ret;
741 }
742
743 /*
744 Remove a sub-directory.
745 */
746 int UMSDOS_rmdir(
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
747 struct inode * dir,
748 const char * name,
749 int len)
750 {
751 /* #Specification: style / iput strategy
752 In the UMSDOS project, I am trying to apply a single
753 programming style regarding inode management. Many
754 entry point are receiving an inode to act on, and must
755 do an iput() as soon as they are finished with
756 the inode.
757
758 For simple case, there is no problem. When you introduce
759 error checking, you end up with many iput placed around the
760 code.
761
762 The coding style I use all around is one where I am trying
763 to provide independent flow logic (I don't know how to
764 name this). With this style, code is easier to understand
765 but you rapidly get iput() all around. Here is an exemple
766 of what I am trying to avoid.
767
768 if (a){
769 ...
770 if(b){
771 ...
772 }
773 ...
774 if (c){
775 // Complex state. Was b true ?
776 ...
777 }
778 ...
779 }
780 // Weird state
781 if (d){
782 // ...
783 }
784 // Was iput finally done ?
785 return status;
786
787 Here is the style I am using. Still sometime I do the
788 first when things are very simple (or very complicated :-( )
789
790 if (a){
791 if (b){
792 ...
793 }else if (c){
794 // A single state gets here
795 }
796 }else if (d){
797 ...
798 }
799 return status;
800
801 Again, while this help clarifying the code, I often get a lot
802 of iput(), unlike the first style, where I can place few
803 "strategic" iput(). "strategic" also mean, more difficult
804 to place.
805
806 So here is the style I will be using from now on in this project.
807 There is always an iput() at the end of a function (which has
808 to do an iput()). One iput by inode. There is also one iput()
809 at the places where a successful operation is achieved. This
810 iput() is often done by a sub-function (often from the msdos
811 file system). So I get one too many iput() ? At the place
812 where an iput() is done, the inode is simply nulled, disabling
813 the last one.
814
815 if (a){
816 if (b){
817 ...
818 }else if (c){
819 msdos_rmdir(dir,...);
820 dir = NULL;
821 }
822 }else if (d){
823 ...
824 }
825 iput (dir);
826 return status;
827
828 Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
829 pair goes against this practice of "forgetting" the inode as soon
830 as possible.
831 */
832 int ret = umsdos_nevercreat(dir,name,len,-EPERM);
833 if (ret == 0){
834 struct inode *sdir;
835 dir->i_count++;
836 ret = UMSDOS_lookup (dir,name,len,&sdir);
837 PRINTK (("rmdir lookup %d ",ret));
838 if (ret == 0){
839 int empty;
840 umsdos_lockcreate(dir);
841 if (sdir->i_count > 1){
842 ret = -EBUSY;
843 }else if ((empty = umsdos_isempty (sdir)) != 0){
844 PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
845 if (empty == 1){
846 /* We have to removed the EMD file */
847 ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
848 ,UMSDOS_EMD_NAMELEN);
849 sdir = NULL;
850 }
851 /* sdir must be free before msdos_rmdir() */
852 iput (sdir);
853 sdir = NULL;
854 PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
855 if (ret == 0){
856 struct umsdos_info info;
857 dir->i_count++;
858 umsdos_parse (name,len,&info);
859 /* The findentry is there only to complete */
860 /* the mangling */
861 umsdos_findentry (dir,&info,2);
862 ret = msdos_rmdir (dir,info.fake.fname
863 ,info.fake.len);
864 if (ret == 0){
865 ret = umsdos_delentry (dir,&info,1);
866 }
867 }
868 }else{
869 /*
870 The subdirectory is not empty, so leave it there
871 */
872 ret = -ENOTEMPTY;
873 }
874 iput(sdir);
875 umsdos_unlockcreate(dir);
876 }
877 }
878 iput (dir);
879 PRINTK (("umsdos_rmdir %d\n",ret));
880 return ret;
881 }
882 /*
883 Remove a file from the directory.
884 */
885 int UMSDOS_unlink (
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
886 struct inode * dir,
887 const char * name,
888 int len)
889 {
890 struct umsdos_info info;
891 int ret = umsdos_nevercreat(dir,name,len,-EPERM);
892 if (ret == 0){
893 ret = umsdos_parse (name,len,&info);
894 if (ret == 0){
895 umsdos_lockcreate(dir);
896 ret = umsdos_findentry(dir,&info,1);
897 if (ret == 0){
898 PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
899 if (info.entry.flags & UMSDOS_HLINK){
900 /* #Specification: hard link / deleting a link
901 When we deletes a file, and this file is a link
902 we must subtract 1 to the nlink field of the
903 hidden link.
904
905 If the count goes to 0, we delete this hidden
906 link too.
907 */
908 /*
909 First, get the inode of the hidden link
910 using the standard lookup function.
911 */
912 struct inode *inode;
913 dir->i_count++;
914 ret = UMSDOS_lookup (dir,name,len,&inode);
915 if (ret == 0){
916 PRINTK (("unlink nlink = %d ",inode->i_nlink));
917 inode->i_nlink--;
918 if (inode->i_nlink == 0){
919 struct inode *hdir = iget(inode->i_sb
920 ,inode->u.umsdos_i.i_dir_owner);
921 struct umsdos_dirent entry;
922 ret = umsdos_inode2entry (hdir,inode,&entry);
923 if (ret == 0){
924 ret = UMSDOS_unlink (hdir,entry.name
925 ,entry.name_len);
926 }else{
927 iput (hdir);
928 }
929 }else{
930 struct iattr newattrs;
931 newattrs.ia_valid = 0;
932 ret = UMSDOS_notify_change (inode, &newattrs);
933 }
934 iput (inode);
935 }
936 }
937 if (ret == 0){
938 ret = umsdos_delentry (dir,&info,0);
939 if (ret == 0){
940 PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
941 dir->i_count++;
942 ret = msdos_unlink_umsdos (dir,info.fake.fname
943 ,info.fake.len);
944 PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
945 ,info.entry.mode,ret));
946 }
947 }
948 }
949 umsdos_unlockcreate(dir);
950 }
951 }
952 iput (dir);
953 PRINTK (("umsdos_unlink %d\n",ret));
954 return ret;
955 }
956
957 /*
958 Rename a file (move) in the file system.
959 */
960 int UMSDOS_rename(
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
961 struct inode * old_dir,
962 const char * old_name,
963 int old_len,
964 struct inode * new_dir,
965 const char * new_name,
966 int new_len)
967 {
968 /* #Specification: weakness / rename
969 There is a case where UMSDOS rename has a different behavior
970 than normal UNIX file system. Renaming an open file across
971 directory boundary does not work. Renaming an open file within
972 a directory does work however.
973
974 The problem (not sure) is in the linux VFS msdos driver.
975 I believe this is not a bug but a design feature, because
976 an inode number represent some sort of directory address
977 in the MSDOS directory structure. So moving the file into
978 another directory does not preserve the inode number.
979 */
980 int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
981 if (ret == 0){
982 /* umsdos_rename_f eat the inode and we may need those later */
983 old_dir->i_count++;
984 new_dir->i_count++;
985 ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
986 ,new_len,0);
987 if (ret == -EEXIST){
988 /* #Specification: rename / new name exist
989 If the destination name already exist, it will
990 silently be removed. EXT2 does it this way
991 and this is the spec of SUNOS. So does UMSDOS.
992
993 If the destination is an empty directory it will
994 also be removed.
995 */
996 /* #Specification: rename / new name exist / possible flaw
997 The code to handle the deletion of the target (file
998 and directory) use to be in umsdos_rename_f, surrounded
999 by proper directory locking. This was insuring that only
1000 one process could achieve a rename (modification) operation
1001 in the source and destination directory. This was also
1002 insuring the operation was "atomic".
1003
1004 This has been changed because this was creating a kernel
1005 stack overflow (stack is only 4k in the kernel). To avoid
1006 the code doing the deletion of the target (if exist) has
1007 been moved to a upper layer. umsdos_rename_f is tried
1008 once and if it fails with EEXIST, the target is removed
1009 and umsdos_rename_f is done again.
1010
1011 This makes the code cleaner and (not sure) solve a
1012 deadlock problem one tester was experiencing.
1013
1014 The point is to mention that possibly, the semantic of
1015 "rename" may be wrong. Anyone dare to check that :-)
1016 Be aware that IF it is wrong, to produce the problem you
1017 will need two process trying to rename a file to the
1018 same target at the same time. Again, I am not sure it
1019 is a problem at all.
1020 */
1021 /* This is not super efficient but should work */
1022 new_dir->i_count++;
1023 ret = UMSDOS_unlink (new_dir,new_name,new_len);
1024 chkstk();
1025 PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
1026 if (ret == -EISDIR){
1027 new_dir->i_count++;
1028 ret = UMSDOS_rmdir (new_dir,new_name,new_len);
1029 chkstk();
1030 PRINTK (("rename rmdir ret %d -- ",ret));
1031 }
1032 if (ret == 0){
1033 ret = umsdos_rename_f (old_dir,old_name,old_len
1034 ,new_dir,new_name,new_len,0);
1035 new_dir = old_dir = NULL;
1036 }
1037 }
1038 }
1039 iput (new_dir);
1040 iput (old_dir);
1041 return ret;
1042 }
1043