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