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