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 #definePRINTK(x)
21 #definePrintk(x) printkx 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 staticintumsdos_waitcreate(structinode *dir)
/* */ 32 { 33 intret = 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 returnret;
40 } 41 /* 42 Wait for any lookup process to finish 43 */ 44 staticvoidumsdos_waitlookup (structinode *dir)
/* */ 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 voidumsdos_lockcreate (structinode *dir)
/* */ 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 staticvoidumsdos_lockcreate2 (structinode *dir1, structinode *dir2)
/* */ 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 voidumsdos_startlookup (structinode *dir)
/* */ 121 { 122 while (umsdos_waitcreate (dir) != 0);
123 dir->u.umsdos_i.u.dir_info.looking++;
124 } 125 voidcheck_page_tables(void);
126
127 /* 128 Unlock the directory. 129 */ 130 voidumsdos_unlockcreate (structinode *dir)
/* */ 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 voidumsdos_endlookup (structinode *dir)
/* */ 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 staticvoidumsdos_lockcreate (structinode *dir){}/* */ 153 staticvoidumsdos_lockcreate2 (structinode *dir1, structinode *dir2){}/* */ 154 voidumsdos_startlookup (structinode *dir){}/* */ 155 staticvoidumsdos_unlockcreate (structinode *dir){}/* */ 156 voidumsdos_endlookup (structinode *dir){}/* */ 157 #endif 158 staticintumsdos_nevercreat(
/* */ 159 structinode *dir,
160 constchar *name, /* Name of the file to add */ 161 intlen,
162 interrcod) /* Length of the name */ 163 { 164 intret = 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 }elseif (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 returnret;
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 staticintumsdos_create_any (
/* */ 200 structinode *dir,
201 constchar *name, /* Name of the file to add */ 202 intlen, /* Length of the name */ 203 intmode, /* Permission bit + file type ??? */ 204 intrdev, /* major, minor or 0 for ordinary file */ 205 /* and symlinks */ 206 charflags,
207 structinode **result) /* Will hold the inode of the newly created */ 208 /* file */ 209 { 210 intret = umsdos_nevercreat(dir,name,len,-EEXIST);
211 if (ret == 0){ 212 structumsdos_infoinfo;
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 structinode *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 returnret;
275 } 276 /* 277 Initialise the new_entry from the old for a rename operation. 278 (Only useful for umsdos_rename_f() below). 279 */ 280 staticvoidumsdos_ren_init(
/* */ 281 structumsdos_info *new_info,
282 structumsdos_info *old_info,
283 intflags) /* 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 #definechkstk() \
298 if (STACK_MAGIC != *(unsignedlong *)current->kernel_stack_page){\
299 printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
300 , current->comm,STACK_MAGIC \
301 ,*(unsignedlong *)current->kernel_stack_page \
302 ,__LINE__); \
303 } 304
305 /* 306 Rename a file (move) in the file system. 307 */ 308 staticintumsdos_rename_f(
/* */ 309 structinode * old_dir,
310 constchar * old_name,
311 intold_len,
312 structinode * new_dir,
313 constchar * new_name,
314 intnew_len,
315 intflags) /* 0 == copy flags from old_name */ 316 /* != 0, this is the value of flags */ 317 { 318 intret = EPERM;
319 structumsdos_infoold_info;
320 intold_ret = umsdos_parse (old_name,old_len,&old_info);
321 structumsdos_infonew_info;
322 intnew_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 structinode *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 returnret;
394 } 395 /* 396 Setup un Symbolic link or a (pseudo) hard link 397 Return a negative error code or 0 if ok. 398 */ 399 staticintumsdos_symlink_x(
/* */ 400 structinode * dir,
401 constchar * name,
402 intlen,
403 constchar * symname, /* name will point to this path */ 404 intmode,
405 charflags)
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 structinode *inode;
418 intret;
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 intlen = strlen(symname);
425 structfilefilp;
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 returnret;
447 } 448 /* 449 Setup un Symbolic link. 450 Return a negative error code or 0 if ok. 451 */ 452 intUMSDOS_symlink(
/* */ 453 structinode * dir,
454 constchar * name,
455 intlen,
456 constchar * symname) /* name will point to this path */ 457 { 458 returnumsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
459 } 460 /* 461 Add a link to an inode in a directory 462 */ 463 intUMSDOS_link (
/* */ 464 structinode * oldinode,
465 structinode * dir,
466 constchar * name,
467 intlen)
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 # 487 ln /foo/file /tmp/file2 488
489 become internally 490
491 mv /foo/file /foo/-LINK1 492 ln -s /foo/-LINK1 /foo/file 493 ln -s /foo/-LINK1 /tmp/file2 494 # 495
496 Using this strategy, we can operate on /foo/file or /foo/file2. 497 We can remove one and keep the other, like a normal Unix hard link. 498 We can rename /foo/file or /tmp/file2 independently. 499 500 The entry -LINK1 will be hidden. It will hold a link count. 501 When all link are erased, the hidden file is erased too. 502 */ 503 /* #Specification: weakness / hard link 504 The strategy for hard link introduces a side effect that 505 may or may not be acceptable. Here is the sequence 506
507 # 508 mkdir subdir1 509 touch subdir1/file 510 mkdir subdir2 511 ln subdir1/file subdir2/file 512 rm subdir1/file 513 rmdir subdir1 514 rmdir: subdir1: Directory not empty 515 # 516
517 This happen because there is an invisible file (--link) in 518 subdir1 which is referenced by subdir2/file. 519
520 Any idea ? 521 */ 522 /* #Specification: weakness / hard link / rename directory 523 Another weakness of hard link come from the fact that 524 it is based on hidden symbolic links. Here is an example. 525
526 # 527 mkdir /subdir1 528 touch /subdir1/file 529 mkdir /subdir2 530 ln /subdir1/file subdir2/file 531 mv /subdir1 subdir3 532 ls -l /subdir2/file 533 # 534
535 Since /subdir2/file is a hidden symbolic link 536 to /subdir1/..hlinkNNN, accessing it will fail since 537 /subdir1 does not exist anymore (has been renamed). 538 */ 539 intret = 0;
540 if (S_ISDIR(oldinode->i_mode)){ 541 /* #Specification: hard link / directory 542 A hard link can't be made on a directory. EPERM is returned 543 in this case. 544 */ 545 ret = -EPERM;
546 }elseif ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){ 547 structinode *olddir;
548 ret = umsdos_get_dirowner(oldinode,&olddir);
549 PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
550 ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
551 if (ret == 0){ 552 structumsdos_dirententry;
553 umsdos_lockcreate2(dir,olddir);
554 ret = umsdos_inode2entry (olddir,oldinode,&entry);
555 if (ret == 0){ 556 PRINTK (("umsdos_link :%s: ino %d flags %d "
557 ,entry.name 558 ,oldinode->i_ino,entry.flags));
559 if (!(entry.flags & UMSDOS_HIDDEN)){ 560 /* #Specification: hard link / first hard link 561 The first time a hard link is done on a file, this 562 file must be renamed and hidden. Then an internal 563 symbolic link must be done on the hidden file. 564
565 The second link is done after on this hidden file. 566
567 It is expected that the Linux MSDOS file system 568 keeps the same pseudo inode when a rename operation 569 is done on a file in the same directory. 570 */ 571 structumsdos_infoinfo;
572 ret = umsdos_newhidden (olddir,&info);
573 if (ret == 0){ 574 olddir->i_count+=2;
575 PRINTK (("olddir[%d] ",olddir->i_count));
576 ret = umsdos_rename_f (olddir,entry.name 577 ,entry.name_len 578 ,olddir,info.entry.name,info.entry.name_len 579 ,UMSDOS_HIDDEN);
580 if (ret == 0){ 581 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
582 if (path == NULL){ 583 ret = -ENOMEM;
584 }else{ 585 PRINTK (("olddir[%d] ",olddir->i_count));
586 ret = umsdos_locate_path (oldinode,path);
587 PRINTK (("olddir[%d] ",olddir->i_count));
588 if (ret == 0){ 589 olddir->i_count++;
590 ret = umsdos_symlink_x (olddir 591 ,entry.name 592 ,entry.name_len,path 593 ,S_IFREG|0777,UMSDOS_HLINK);
594 if (ret == 0){ 595 dir->i_count++;
596 ret = umsdos_symlink_x (dir,name,len 597 ,path 598 ,S_IFREG|0777,UMSDOS_HLINK);
599 } 600 } 601 kfree (path);
602 } 603 } 604 } 605 }else{ 606 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
607 if (path == NULL){ 608 ret = -ENOMEM;
609 }else{ 610 ret = umsdos_locate_path (oldinode,path);
611 if (ret == 0){ 612 dir->i_count++;
613 ret = umsdos_symlink_x (dir,name,len,path 614 ,S_IFREG|0777,UMSDOS_HLINK);
615 } 616 kfree (path);
617 } 618 } 619 } 620 umsdos_unlockcreate(olddir);
621 umsdos_unlockcreate(dir);
622 } 623 iput (olddir);
624 } 625 if (ret == 0){ 626 structiattrnewattrs;
627 oldinode->i_nlink++;
628 newattrs.ia_valid = 0;
629 ret = UMSDOS_notify_change(oldinode, &newattrs);
630 } 631 iput (oldinode);
632 iput (dir);
633 PRINTK (("umsdos_link %d\n",ret));
634 returnret;
635 } 636 /* 637 Add a new file into the alternate directory. 638 The file is added to the real MSDOS directory. If successful, it 639 is then added to the EDM file. 640
641 Return the status of the operation. 0 mean success. 642 */ 643 intUMSDOS_create (
/* */ 644 structinode *dir,
645 constchar *name, /* Name of the file to add */ 646 intlen, /* Length of the name */ 647 intmode, /* Permission bit + file type ??? */ 648 structinode **result) /* Will hold the inode of the newly created */ 649 /* file */ 650 { 651 returnumsdos_create_any (dir,name,len,mode,0,0,result);
652 } 653 /* 654 Add a sub-directory in a directory 655 */ 656 intUMSDOS_mkdir(
/* */ 657 structinode * dir,
658 constchar * name,
659 intlen,
660 intmode)
661 { 662 intret = umsdos_nevercreat(dir,name,len,-EEXIST);
663 if (ret == 0){ 664 structumsdos_infoinfo;
665 ret = umsdos_parse (name,len,&info);
666 PRINTK (("umsdos_mkdir %d\n",ret));
667 if (ret == 0){ 668 info.entry.mode = mode | S_IFDIR;
669 info.entry.rdev = 0;
670 info.entry.uid = current->fsuid;
671 info.entry.gid = (dir->i_mode & S_ISGID)
672 ? dir->i_gid : current->fsgid;
673 info.entry.ctime = info.entry.atime = info.entry.mtime 674 = CURRENT_TIME;
675 info.entry.flags = 0;
676 umsdos_lockcreate(dir);
677 info.entry.nlink = 1;
678 ret = umsdos_newentry (dir,&info);
679 PRINTK (("newentry %d ",ret));
680 if (ret == 0){ 681 dir->i_count++;
682 ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
683 if (ret != 0){ 684 umsdos_delentry (dir,&info,1);
685 /* #Specification: mkdir / Directory already exist in DOS 686 We do the same thing as for file creation. 687 For all user it is an error. 688 */ 689 }else{ 690 /* #Specification: mkdir / umsdos directory / create EMD 691 When we created a new sub-directory in a UMSDOS 692 directory (one with full UMSDOS semantic), we 693 create immediately an EMD file in the new 694 sub-directory so it inherit UMSDOS semantic. 695 */ 696 structinode *subdir;
697 ret = umsdos_real_lookup (dir,info.fake.fname 698 ,info.fake.len,&subdir);
699 if (ret == 0){ 700 structinode *result;
701 ret = msdos_create (subdir,UMSDOS_EMD_FILE 702 ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
703 subdir = NULL;
704 iput (result);
705 } 706 if (ret < 0){ 707 printk ("UMSDOS: Can't create empty --linux-.---\n");
708 } 709 iput (subdir);
710 } 711 } 712 umsdos_unlockcreate(dir);
713 } 714 } 715 PRINTK (("umsdos_mkdir %d\n",ret));
716 iput (dir);
717 returnret;
718 } 719 /* 720 Add a new device special file into a directory. 721 */ 722 intUMSDOS_mknod(
/* */ 723 structinode * dir,
724 constchar * name,
725 intlen,
726 intmode,
727 intrdev)
728 { 729 /* #Specification: Special files / strategy 730 Device special file, pipes, etc ... are created like normal 731 file in the msdos file system. Of course they remain empty. 732
733 One strategy was to create those files only in the EMD file 734 since they were not important for MSDOS. The problem with 735 that, is that there were not getting inode number allocated. 736 The MSDOS filesystems is playing a nice game to fake inode 737 number, so why not use it. 738
739 The absence of inode number compatible with those allocated 740 for ordinary files was causing major trouble with hard link 741 in particular and other parts of the kernel I guess. 742 */ 743 structinode *inode;
744 intret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
745 iput (inode);
746 returnret;
747 } 748
749 /* 750 Remove a sub-directory. 751 */ 752 intUMSDOS_rmdir(
/* */ 753 structinode * dir,
754 constchar * name,
755 intlen)
756 { 757 /* #Specification: style / iput strategy 758 In the UMSDOS project, I am trying to apply a single 759 programming style regarding inode management. Many 760 entry point are receiving an inode to act on, and must 761 do an iput() as soon as they are finished with 762 the inode. 763
764 For simple case, there is no problem. When you introduce 765 error checking, you end up with many iput placed around the 766 code. 767
768 The coding style I use all around is one where I am trying 769 to provide independent flow logic (I don't know how to 770 name this). With this style, code is easier to understand 771 but you rapidly get iput() all around. Here is an exemple 772 of what I am trying to avoid. 773
774 # 775 if (a){ 776 ... 777 if(b){ 778 ... 779 } 780 ... 781 if (c){ 782 // Complex state. Was b true ? 783 ... 784 } 785 ... 786 } 787 // Weird state 788 if (d){ 789 // ... 790 } 791 // Was iput finally done ? 792 return status; 793 # 794
795 Here is the style I am using. Still sometime I do the 796 first when things are very simple (or very complicated :-( ) 797
798 # 799 if (a){ 800 if (b){ 801 ... 802 }else if (c){ 803 // A single state gets here 804 } 805 }else if (d){ 806 ... 807 } 808 return status; 809 # 810
811 Again, while this help clarifying the code, I often get a lot 812 of iput(), unlike the first style, where I can place few 813 "strategic" iput(). "strategic" also mean, more difficult 814 to place. 815
816 So here is the style I will be using from now on in this project. 817 There is always an iput() at the end of a function (which has 818 to do an iput()). One iput by inode. There is also one iput() 819 at the places where a successful operation is achieved. This 820 iput() is often done by a sub-function (often from the msdos 821 file system). So I get one too many iput() ? At the place 822 where an iput() is done, the inode is simply nulled, disabling 823 the last one. 824
825 # 826 if (a){ 827 if (b){ 828 ... 829 }else if (c){ 830 msdos_rmdir(dir,...); 831 dir = NULL; 832 } 833 }else if (d){ 834 ... 835 } 836 iput (dir); 837 return status; 838 # 839
840 Note that the umsdos_lockcreate() and umsdos_unlockcreate() function 841 pair goes against this practice of "forgetting" the inode as soon 842 as possible. 843 */ 844 intret = umsdos_nevercreat(dir,name,len,-EPERM);
845 if (ret == 0){ 846 structinode *sdir;
847 dir->i_count++;
848 ret = UMSDOS_lookup (dir,name,len,&sdir);
849 PRINTK (("rmdir lookup %d ",ret));
850 if (ret == 0){ 851 intempty;
852 umsdos_lockcreate(dir);
853 if (sdir->i_count > 1){ 854 ret = -EBUSY;
855 }elseif ((empty = umsdos_isempty (sdir)) != 0){ 856 PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
857 if (empty == 1){ 858 /* We have to removed the EMD file */ 859 ret = msdos_unlink(sdir,UMSDOS_EMD_FILE 860 ,UMSDOS_EMD_NAMELEN);
861 sdir = NULL;
862 } 863 /* sdir must be free before msdos_rmdir() */ 864 iput (sdir);
865 sdir = NULL;
866 PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
867 if (ret == 0){ 868 structumsdos_infoinfo;
869 dir->i_count++;
870 umsdos_parse (name,len,&info);
871 /* The findentry is there only to complete */ 872 /* the mangling */ 873 umsdos_findentry (dir,&info,2);
874 ret = msdos_rmdir (dir,info.fake.fname 875 ,info.fake.len);
876 if (ret == 0){ 877 ret = umsdos_delentry (dir,&info,1);
878 } 879 } 880 }else{ 881 /* 882 The subdirectory is not empty, so leave it there 883 */ 884 ret = -ENOTEMPTY;
885 } 886 iput(sdir);
887 umsdos_unlockcreate(dir);
888 } 889 } 890 iput (dir);
891 PRINTK (("umsdos_rmdir %d\n",ret));
892 returnret;
893 } 894 /* 895 Remove a file from the directory. 896 */ 897 intUMSDOS_unlink (
/* */ 898 structinode * dir,
899 constchar * name,
900 intlen)
901 { 902 structumsdos_infoinfo;
903 intret = umsdos_nevercreat(dir,name,len,-EPERM);
904 if (ret == 0){ 905 ret = umsdos_parse (name,len,&info);
906 if (ret == 0){ 907 umsdos_lockcreate(dir);
908 ret = umsdos_findentry(dir,&info,1);
909 if (ret == 0){ 910 PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
911 if (info.entry.flags & UMSDOS_HLINK){ 912 /* #Specification: hard link / deleting a link 913 When we deletes a file, and this file is a link 914 we must subtract 1 to the nlink field of the 915 hidden link. 916
917 If the count goes to 0, we delete this hidden 918 link too. 919 */ 920 /* 921 First, get the inode of the hidden link 922 using the standard lookup function. 923 */ 924 structinode *inode;
925 dir->i_count++;
926 ret = UMSDOS_lookup (dir,name,len,&inode);
927 if (ret == 0){ 928 PRINTK (("unlink nlink = %d ",inode->i_nlink));
929 inode->i_nlink--;
930 if (inode->i_nlink == 0){ 931 structinode *hdir = iget(inode->i_sb 932 ,inode->u.umsdos_i.i_dir_owner);
933 structumsdos_dirententry;
934 ret = umsdos_inode2entry (hdir,inode,&entry);
935 if (ret == 0){ 936 ret = UMSDOS_unlink (hdir,entry.name 937 ,entry.name_len);
938 }else{ 939 iput (hdir);
940 } 941 }else{ 942 structiattrnewattrs;
943 newattrs.ia_valid = 0;
944 ret = UMSDOS_notify_change (inode, &newattrs);
945 } 946 iput (inode);
947 } 948 } 949 if (ret == 0){ 950 ret = umsdos_delentry (dir,&info,0);
951 if (ret == 0){ 952 PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
953 dir->i_count++;
954 ret = msdos_unlink_umsdos (dir,info.fake.fname 955 ,info.fake.len);
956 PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname 957 ,info.entry.mode,ret));
958 } 959 } 960 } 961 umsdos_unlockcreate(dir);
962 } 963 } 964 iput (dir);
965 PRINTK (("umsdos_unlink %d\n",ret));
966 returnret;
967 } 968
969 /* 970 Rename a file (move) in the file system. 971 */ 972 intUMSDOS_rename(
/* */ 973 structinode * old_dir,
974 constchar * old_name,
975 intold_len,
976 structinode * new_dir,
977 constchar * new_name,
978 intnew_len)
979 { 980 /* #Specification: weakness / rename 981 There is a case where UMSDOS rename has a different behavior 982 than normal UNIX file system. Renaming an open file across 983 directory boundary does not work. Renaming an open file within 984 a directory does work however. 985
986 The problem (not sure) is in the linux VFS msdos driver. 987 I believe this is not a bug but a design feature, because 988 an inode number represent some sort of directory address 989 in the MSDOS directory structure. So moving the file into 990 another directory does not preserve the inode number. 991 */ 992 intret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
993 if (ret == 0){ 994 /* umsdos_rename_f eat the inode and we may need those later */ 995 old_dir->i_count++;
996 new_dir->i_count++;
997 ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name 998 ,new_len,0);
999 if (ret == -EEXIST){1000 /* #Specification: rename / new name exist1001 If the destination name already exist, it will1002 silently be removed. EXT2 does it this way1003 and this is the spec of SUNOS. So does UMSDOS.1004
1005 If the destination is an empty directory it will1006 also be removed.1007 */1008 /* #Specification: rename / new name exist / possible flaw1009 The code to handle the deletion of the target (file1010 and directory) use to be in umsdos_rename_f, surrounded1011 by proper directory locking. This was insuring that only1012 one process could achieve a rename (modification) operation1013 in the source and destination directory. This was also1014 insuring the operation was "atomic".1015
1016 This has been changed because this was creating a kernel1017 stack overflow (stack is only 4k in the kernel). To avoid1018 the code doing the deletion of the target (if exist) has1019 been moved to a upper layer. umsdos_rename_f is tried1020 once and if it fails with EEXIST, the target is removed1021 and umsdos_rename_f is done again.1022
1023 This makes the code cleaner and (not sure) solve a1024 deadlock problem one tester was experiencing.1025
1026 The point is to mention that possibly, the semantic of1027 "rename" may be wrong. Anyone dare to check that :-)1028 Be aware that IF it is wrong, to produce the problem you1029 will need two process trying to rename a file to the1030 same target at the same time. Again, I am not sure it1031 is a problem at all.1032 */1033 /* This is not super efficient but should work */1034 new_dir->i_count++;
1035 ret = UMSDOS_unlink (new_dir,new_name,new_len);
1036 chkstk();
1037 PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
1038 if (ret == -EISDIR){1039 new_dir->i_count++;
1040 ret = UMSDOS_rmdir (new_dir,new_name,new_len);
1041 chkstk();
1042 PRINTK (("rename rmdir ret %d -- ",ret));
1043 }1044 if (ret == 0){1045 ret = umsdos_rename_f (old_dir,old_name,old_len1046 ,new_dir,new_name,new_len,0);
1047 new_dir = old_dir = NULL;
1048 }1049 }1050 }1051 iput (new_dir);
1052 iput (old_dir);
1053 returnret;
1054 }1055