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
10 #include <linux/errno.h>
11 #include <linux/kernel.h>
12 #include <linux/sched.h>
13 #include <linux/types.h>
14 #include <linux/fcntl.h>
15 #include <linux/stat.h>
16 #include <linux/string.h>
17 #include <linux/msdos_fs.h>
18 #include <linux/umsdos_fs.h>
19 #include <linux/malloc.h>
20
21 #definePRINTK(x)
22 #definePrintk(x) printkx 23
24 #if 1
25 /* 26 Wait for creation exclusivity. 27 Return 0 if the dir was already available. 28 Return 1 if a wait was necessary. 29 When 1 is return, it means a wait was done. It does not 30 mean the directory is available. 31 */ 32 staticintumsdos_waitcreate(structinode *dir)
/* */ 33 { 34 intret = 0;
35 if (dir->u.umsdos_i.u.dir_info.creating 36 && dir->u.umsdos_i.u.dir_info.pid != current->pid){ 37 sleep_on(&dir->u.umsdos_i.u.dir_info.p);
38 ret = 1;
39 } 40 returnret;
41 } 42 /* 43 Wait for any lookup process to finish 44 */ 45 staticvoidumsdos_waitlookup (structinode *dir)
/* */ 46 { 47 while (dir->u.umsdos_i.u.dir_info.looking){ 48 sleep_on(&dir->u.umsdos_i.u.dir_info.p);
49 } 50 } 51 /* 52 Lock all other process out of this directory. 53 */ 54 voidumsdos_lockcreate (structinode *dir)
/* */ 55 { 56 /* #Specification: file creation / not atomic 57 File creation is a two step process. First we create (allocate) 58 an entry in the EMD file and then (using the entry offset) we 59 build a unique name for MSDOS. We create this name in the msdos 60 space. 61
62 We have to use semaphore (sleep_on/wake_up) to prevent lookup 63 into a directory when we create a file or directory and to 64 prevent creation while a lookup is going on. Since many lookup 65 may happen at the same time, the semaphore is a counter. 66
67 Only one creation is allowed at the same time. This protection 68 may not be necessary. The problem arise mainly when a lookup 69 or a readdir is done while a file is partially created. The 70 lookup process see that as a "normal" problem and silently 71 erase the file from the EMD file. Normal because a file 72 may be erased during a MSDOS session, but not removed from 73 the EMD file. 74
75 The locking is done on a directory per directory basis. Each 76 directory inode has its wait_queue. 77
78 For some operation like hard link, things even get worse. Many 79 creation must occur at once (atomic). To simplify the design 80 a process is allowed to recursively lock the directory for 81 creation. The pid of the locking process is kept along with 82 a counter so a second level of locking is granted or not. 83 */ 84 /* 85 Wait for any creation process to finish except 86 if we (the process) own the lock 87 */ 88 while (umsdos_waitcreate(dir)!=0);
89 dir->u.umsdos_i.u.dir_info.creating++;
90 dir->u.umsdos_i.u.dir_info.pid = current->pid;
91 umsdos_waitlookup (dir);
92 } 93 /* 94 Lock all other process out of those two directories. 95 */ 96 staticvoidumsdos_lockcreate2 (structinode *dir1, structinode *dir2)
/* */ 97 { 98 /* 99 We must check that both directory are available before 100 locking anyone of them. This is to avoid some deadlock. 101 Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing 102 this to me. 103 */ 104 while (1){ 105 if (umsdos_waitcreate(dir1)==0
106 && umsdos_waitcreate(dir2)==0){ 107 /* We own both now */ 108 dir1->u.umsdos_i.u.dir_info.creating++;
109 dir1->u.umsdos_i.u.dir_info.pid = current->pid;
110 dir2->u.umsdos_i.u.dir_info.creating++;
111 dir2->u.umsdos_i.u.dir_info.pid = current->pid;
112 break;
113 } 114 } 115 umsdos_waitlookup(dir1);
116 umsdos_waitlookup(dir2);
117 } 118 /* 119 Wait until creation is finish in this directory. 120 */ 121 voidumsdos_startlookup (structinode *dir)
/* */ 122 { 123 while (umsdos_waitcreate (dir) != 0);
124 dir->u.umsdos_i.u.dir_info.looking++;
125 } 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 /* check sticky bit on old_dir */ 334 if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
335 current->fsuid == old_info.entry.uid ||
336 current->fsuid == old_dir->i_uid ) { 337 /* Does new_name already exist? */ 338 PRINTK(("new findentry "));
339 ret = umsdos_findentry(new_dir,&new_info,0);
340 if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */ 341 !(new_dir->i_mode & S_ISVTX) || fsuser() ||
342 current->fsuid == new_info.entry.uid ||
343 current->fsuid == new_dir->i_uid ) { 344 PRINTK (("new newentry "));
345 umsdos_ren_init(&new_info,&old_info,flags);
346 ret = umsdos_newentry (new_dir,&new_info);
347 chkstk();
348 PRINTK (("ret %d %d ",ret,new_info.fake.len));
349 if (ret == 0){ 350 PRINTK (("msdos_rename "));
351 old_dir->i_count++;
352 new_dir->i_count++; /* Both inode are needed later */ 353 ret = msdos_rename (old_dir 354 ,old_info.fake.fname,old_info.fake.len 355 ,new_dir 356 ,new_info.fake.fname,new_info.fake.len);
357 chkstk();
358 PRINTK (("after m_rename ret %d ",ret));
359 if (ret != 0){ 360 umsdos_delentry (new_dir,&new_info 361 ,S_ISDIR(new_info.entry.mode));
362 chkstk();
363 }else{ 364 ret = umsdos_delentry (old_dir,&old_info 365 ,S_ISDIR(old_info.entry.mode));
366 chkstk();
367 if (ret == 0){ 368 /* 369 This UMSDOS_lookup does not look very useful. 370 It makes sure that the inode of the file will 371 be correctly setup (umsdos_patch_inode()) in 372 case it is already in use. 373 374 Not very efficient ... 375 */ 376 structinode *inode;
377 new_dir->i_count++;
378 PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
379 ret = UMSDOS_lookup (new_dir,new_name,new_len 380 ,&inode);
381 chkstk();
382 if (ret != 0){ 383 printk ("UMSDOS: partial rename for file %s\n"
384 ,new_info.entry.name);
385 }else{ 386 /* 387 Update f_pos so notify_change will succeed 388 if the file was already in use. 389 */ 390 umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
391 chkstk();
392 iput (inode);
393 } 394 } 395 } 396 } 397 }else{ 398 /* sticky bit set on new_dir */ 399 PRINTK(("sticky set on new "));
400 ret = -EPERM;
401 } 402 }else{ 403 /* sticky bit set on old_dir */ 404 PRINTK(("sticky set on old "));
405 ret = -EPERM;
406 } 407 } 408 umsdos_unlockcreate(old_dir);
409 umsdos_unlockcreate(new_dir);
410 } 411 iput (old_dir);
412 iput (new_dir);
413 PRINTK (("\n"));
414 returnret;
415 } 416 /* 417 Setup un Symbolic link or a (pseudo) hard link 418 Return a negative error code or 0 if ok. 419 */ 420 staticintumsdos_symlink_x(
/* */ 421 structinode * dir,
422 constchar * name,
423 intlen,
424 constchar * symname, /* name will point to this path */ 425 intmode,
426 charflags)
427 { 428 /* #Specification: symbolic links / strategy 429 A symbolic link is simply a file which hold a path. It is 430 implemented as a normal MSDOS file (not very space efficient :-() 431
432 I see 2 different way to do it. One is to place the link data 433 in unused entry of the EMD file. The other is to have a separate 434 file dedicated to hold all symbolic links data. 435
436 Lets go for simplicity... 437 */ 438 structinode *inode;
439 intret;
440 dir->i_count++; /* We keep the inode in case we need it */ 441 /* later */ 442 ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
443 PRINTK (("umsdos_symlink ret %d ",ret));
444 if (ret == 0){ 445 intlen = strlen(symname);
446 structfilefilp;
447 filp.f_pos = 0;
448 /* Make the inode acceptable to MSDOS */ 449 ret = umsdos_file_write_kmem (inode,&filp,symname,len);
450 iput (inode);
451 if (ret >= 0){ 452 if (ret != len){ 453 ret = -EIO;
454 printk ("UMSDOS: "
455 "Can't write symbolic link data\n");
456 }else{ 457 ret = 0;
458 } 459 } 460 if (ret != 0){ 461 UMSDOS_unlink (dir,name,len);
462 dir = NULL;
463 } 464 } 465 iput (dir);
466 PRINTK (("\n"));
467 returnret;
468 } 469 /* 470 Setup un Symbolic link. 471 Return a negative error code or 0 if ok. 472 */ 473 intUMSDOS_symlink(
/* */ 474 structinode * dir,
475 constchar * name,
476 intlen,
477 constchar * symname) /* name will point to this path */ 478 { 479 returnumsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
480 } 481 /* 482 Add a link to an inode in a directory 483 */ 484 intUMSDOS_link (
/* */ 485 structinode * oldinode,
486 structinode * dir,
487 constchar * name,
488 intlen)
489 { 490 /* #Specification: hard link / strategy 491 Well ... hard link are difficult to implement on top of an 492 MsDOS fat file system. Unlike UNIX file systems, there are no 493 inode. A directory entry hold the functionality of the inode 494 and the entry. 495
496 We will used the same strategy as a normal Unix file system 497 (with inode) except we will do it symbolically (using paths). 498
499 Because anything can happen during a DOS session (defragment, 500 directory sorting, etc...), we can't rely on MsDOS pseudo 501 inode number to record the link. For this reason, the link 502 will be done using hidden symbolic links. The following 503 scenario illustrate how it work. 504 505 Given a file /foo/file 506
507 # 508 ln /foo/file /tmp/file2 509
510 become internally 511
512 mv /foo/file /foo/-LINK1 513 ln -s /foo/-LINK1 /foo/file 514 ln -s /foo/-LINK1 /tmp/file2 515 # 516
517 Using this strategy, we can operate on /foo/file or /foo/file2. 518 We can remove one and keep the other, like a normal Unix hard link. 519 We can rename /foo/file or /tmp/file2 independently. 520 521 The entry -LINK1 will be hidden. It will hold a link count. 522 When all link are erased, the hidden file is erased too. 523 */ 524 /* #Specification: weakness / hard link 525 The strategy for hard link introduces a side effect that 526 may or may not be acceptable. Here is the sequence 527
528 # 529 mkdir subdir1 530 touch subdir1/file 531 mkdir subdir2 532 ln subdir1/file subdir2/file 533 rm subdir1/file 534 rmdir subdir1 535 rmdir: subdir1: Directory not empty 536 # 537
538 This happen because there is an invisible file (--link) in 539 subdir1 which is referenced by subdir2/file. 540
541 Any idea ? 542 */ 543 /* #Specification: weakness / hard link / rename directory 544 Another weakness of hard link come from the fact that 545 it is based on hidden symbolic links. Here is an example. 546
547 # 548 mkdir /subdir1 549 touch /subdir1/file 550 mkdir /subdir2 551 ln /subdir1/file subdir2/file 552 mv /subdir1 subdir3 553 ls -l /subdir2/file 554 # 555
556 Since /subdir2/file is a hidden symbolic link 557 to /subdir1/..hlinkNNN, accessing it will fail since 558 /subdir1 does not exist anymore (has been renamed). 559 */ 560 intret = 0;
561 if (S_ISDIR(oldinode->i_mode)){ 562 /* #Specification: hard link / directory 563 A hard link can't be made on a directory. EPERM is returned 564 in this case. 565 */ 566 ret = -EPERM;
567 }elseif ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){ 568 structinode *olddir;
569 ret = umsdos_get_dirowner(oldinode,&olddir);
570 PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
571 ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
572 if (ret == 0){ 573 structumsdos_dirententry;
574 umsdos_lockcreate2(dir,olddir);
575 ret = umsdos_inode2entry (olddir,oldinode,&entry);
576 if (ret == 0){ 577 PRINTK (("umsdos_link :%s: ino %d flags %d "
578 ,entry.name 579 ,oldinode->i_ino,entry.flags));
580 if (!(entry.flags & UMSDOS_HIDDEN)){ 581 /* #Specification: hard link / first hard link 582 The first time a hard link is done on a file, this 583 file must be renamed and hidden. Then an internal 584 symbolic link must be done on the hidden file. 585
586 The second link is done after on this hidden file. 587
588 It is expected that the Linux MSDOS file system 589 keeps the same pseudo inode when a rename operation 590 is done on a file in the same directory. 591 */ 592 structumsdos_infoinfo;
593 ret = umsdos_newhidden (olddir,&info);
594 if (ret == 0){ 595 olddir->i_count+=2;
596 PRINTK (("olddir[%d] ",olddir->i_count));
597 ret = umsdos_rename_f (olddir,entry.name 598 ,entry.name_len 599 ,olddir,info.entry.name,info.entry.name_len 600 ,UMSDOS_HIDDEN);
601 if (ret == 0){ 602 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
603 if (path == NULL){ 604 ret = -ENOMEM;
605 }else{ 606 PRINTK (("olddir[%d] ",olddir->i_count));
607 ret = umsdos_locate_path (oldinode,path);
608 PRINTK (("olddir[%d] ",olddir->i_count));
609 if (ret == 0){ 610 olddir->i_count++;
611 ret = umsdos_symlink_x (olddir 612 ,entry.name 613 ,entry.name_len,path 614 ,S_IFREG|0777,UMSDOS_HLINK);
615 if (ret == 0){ 616 dir->i_count++;
617 ret = umsdos_symlink_x (dir,name,len 618 ,path 619 ,S_IFREG|0777,UMSDOS_HLINK);
620 } 621 } 622 kfree (path);
623 } 624 } 625 } 626 }else{ 627 char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
628 if (path == NULL){ 629 ret = -ENOMEM;
630 }else{ 631 ret = umsdos_locate_path (oldinode,path);
632 if (ret == 0){ 633 dir->i_count++;
634 ret = umsdos_symlink_x (dir,name,len,path 635 ,S_IFREG|0777,UMSDOS_HLINK);
636 } 637 kfree (path);
638 } 639 } 640 } 641 umsdos_unlockcreate(olddir);
642 umsdos_unlockcreate(dir);
643 } 644 iput (olddir);
645 } 646 if (ret == 0){ 647 structiattrnewattrs;
648 oldinode->i_nlink++;
649 newattrs.ia_valid = 0;
650 ret = UMSDOS_notify_change(oldinode, &newattrs);
651 } 652 iput (oldinode);
653 iput (dir);
654 PRINTK (("umsdos_link %d\n",ret));
655 returnret;
656 } 657 /* 658 Add a new file into the alternate directory. 659 The file is added to the real MSDOS directory. If successful, it 660 is then added to the EDM file. 661
662 Return the status of the operation. 0 mean success. 663 */ 664 intUMSDOS_create (
/* */ 665 structinode *dir,
666 constchar *name, /* Name of the file to add */ 667 intlen, /* Length of the name */ 668 intmode, /* Permission bit + file type ??? */ 669 structinode **result) /* Will hold the inode of the newly created */ 670 /* file */ 671 { 672 returnumsdos_create_any (dir,name,len,mode,0,0,result);
673 } 674 /* 675 Add a sub-directory in a directory 676 */ 677 intUMSDOS_mkdir(
/* */ 678 structinode * dir,
679 constchar * name,
680 intlen,
681 intmode)
682 { 683 intret = umsdos_nevercreat(dir,name,len,-EEXIST);
684 if (ret == 0){ 685 structumsdos_infoinfo;
686 ret = umsdos_parse (name,len,&info);
687 PRINTK (("umsdos_mkdir %d\n",ret));
688 if (ret == 0){ 689 info.entry.mode = mode | S_IFDIR;
690 info.entry.rdev = 0;
691 info.entry.uid = current->fsuid;
692 info.entry.gid = (dir->i_mode & S_ISGID)
693 ? dir->i_gid : current->fsgid;
694 info.entry.ctime = info.entry.atime = info.entry.mtime 695 = CURRENT_TIME;
696 info.entry.flags = 0;
697 umsdos_lockcreate(dir);
698 info.entry.nlink = 1;
699 ret = umsdos_newentry (dir,&info);
700 PRINTK (("newentry %d ",ret));
701 if (ret == 0){ 702 dir->i_count++;
703 ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
704 if (ret != 0){ 705 umsdos_delentry (dir,&info,1);
706 /* #Specification: mkdir / Directory already exist in DOS 707 We do the same thing as for file creation. 708 For all user it is an error. 709 */ 710 }else{ 711 /* #Specification: mkdir / umsdos directory / create EMD 712 When we created a new sub-directory in a UMSDOS 713 directory (one with full UMSDOS semantic), we 714 create immediately an EMD file in the new 715 sub-directory so it inherit UMSDOS semantic. 716 */ 717 structinode *subdir;
718 ret = umsdos_real_lookup (dir,info.fake.fname 719 ,info.fake.len,&subdir);
720 if (ret == 0){ 721 structinode *result;
722 ret = msdos_create (subdir,UMSDOS_EMD_FILE 723 ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
724 subdir = NULL;
725 iput (result);
726 } 727 if (ret < 0){ 728 printk ("UMSDOS: Can't create empty --linux-.---\n");
729 } 730 iput (subdir);
731 } 732 } 733 umsdos_unlockcreate(dir);
734 } 735 } 736 PRINTK (("umsdos_mkdir %d\n",ret));
737 iput (dir);
738 returnret;
739 } 740 /* 741 Add a new device special file into a directory. 742 */ 743 intUMSDOS_mknod(
/* */ 744 structinode * dir,
745 constchar * name,
746 intlen,
747 intmode,
748 intrdev)
749 { 750 /* #Specification: Special files / strategy 751 Device special file, pipes, etc ... are created like normal 752 file in the msdos file system. Of course they remain empty. 753
754 One strategy was to create those files only in the EMD file 755 since they were not important for MSDOS. The problem with 756 that, is that there were not getting inode number allocated. 757 The MSDOS filesystems is playing a nice game to fake inode 758 number, so why not use it. 759
760 The absence of inode number compatible with those allocated 761 for ordinary files was causing major trouble with hard link 762 in particular and other parts of the kernel I guess. 763 */ 764 structinode *inode;
765 intret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
766 iput (inode);
767 returnret;
768 } 769
770 /* 771 Remove a sub-directory. 772 */ 773 intUMSDOS_rmdir(
/* */ 774 structinode * dir,
775 constchar * name,
776 intlen)
777 { 778 /* #Specification: style / iput strategy 779 In the UMSDOS project, I am trying to apply a single 780 programming style regarding inode management. Many 781 entry point are receiving an inode to act on, and must 782 do an iput() as soon as they are finished with 783 the inode. 784
785 For simple case, there is no problem. When you introduce 786 error checking, you end up with many iput placed around the 787 code. 788
789 The coding style I use all around is one where I am trying 790 to provide independent flow logic (I don't know how to 791 name this). With this style, code is easier to understand 792 but you rapidly get iput() all around. Here is an exemple 793 of what I am trying to avoid. 794
795 # 796 if (a){ 797 ... 798 if(b){ 799 ... 800 } 801 ... 802 if (c){ 803 // Complex state. Was b true ? 804 ... 805 } 806 ... 807 } 808 // Weird state 809 if (d){ 810 // ... 811 } 812 // Was iput finally done ? 813 return status; 814 # 815
816 Here is the style I am using. Still sometime I do the 817 first when things are very simple (or very complicated :-( ) 818
819 # 820 if (a){ 821 if (b){ 822 ... 823 }else if (c){ 824 // A single state gets here 825 } 826 }else if (d){ 827 ... 828 } 829 return status; 830 # 831
832 Again, while this help clarifying the code, I often get a lot 833 of iput(), unlike the first style, where I can place few 834 "strategic" iput(). "strategic" also mean, more difficult 835 to place. 836
837 So here is the style I will be using from now on in this project. 838 There is always an iput() at the end of a function (which has 839 to do an iput()). One iput by inode. There is also one iput() 840 at the places where a successful operation is achieved. This 841 iput() is often done by a sub-function (often from the msdos 842 file system). So I get one too many iput() ? At the place 843 where an iput() is done, the inode is simply nulled, disabling 844 the last one. 845
846 # 847 if (a){ 848 if (b){ 849 ... 850 }else if (c){ 851 msdos_rmdir(dir,...); 852 dir = NULL; 853 } 854 }else if (d){ 855 ... 856 } 857 iput (dir); 858 return status; 859 # 860
861 Note that the umsdos_lockcreate() and umsdos_unlockcreate() function 862 pair goes against this practice of "forgetting" the inode as soon 863 as possible. 864 */ 865 intret = umsdos_nevercreat(dir,name,len,-EPERM);
866 if (ret == 0){ 867 structinode *sdir;
868 dir->i_count++;
869 ret = UMSDOS_lookup (dir,name,len,&sdir);
870 PRINTK (("rmdir lookup %d ",ret));
871 if (ret == 0){ 872 intempty;
873 umsdos_lockcreate(dir);
874 if (sdir->i_count > 1){ 875 ret = -EBUSY;
876 }elseif ((empty = umsdos_isempty (sdir)) != 0){ 877 PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
878 /* check sticky bit */ 879 if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
880 current->fsuid == sdir->i_uid ||
881 current->fsuid == dir->i_uid ) { 882 if (empty == 1){ 883 /* We have to removed the EMD file */ 884 ret = msdos_unlink(sdir,UMSDOS_EMD_FILE 885 ,UMSDOS_EMD_NAMELEN);
886 sdir = NULL;
887 } 888 /* sdir must be free before msdos_rmdir() */ 889 iput (sdir);
890 sdir = NULL;
891 PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
892 if (ret == 0){ 893 structumsdos_infoinfo;
894 dir->i_count++;
895 umsdos_parse (name,len,&info);
896 /* The findentry is there only to complete */ 897 /* the mangling */ 898 umsdos_findentry (dir,&info,2);
899 ret = msdos_rmdir (dir,info.fake.fname 900 ,info.fake.len);
901 if (ret == 0){ 902 ret = umsdos_delentry (dir,&info,1);
903 } 904 } 905 }else{ 906 /* sticky bit set and we don't have permission */ 907 PRINTK(("sticky set "));
908 ret = -EPERM;
909 } 910 }else{ 911 /* 912 The subdirectory is not empty, so leave it there 913 */ 914 ret = -ENOTEMPTY;
915 } 916 iput(sdir);
917 umsdos_unlockcreate(dir);
918 } 919 } 920 iput (dir);
921 PRINTK (("umsdos_rmdir %d\n",ret));
922 returnret;
923 } 924 /* 925 Remove a file from the directory. 926 */ 927 intUMSDOS_unlink (
/* */ 928 structinode * dir,
929 constchar * name,
930 intlen)
931 { 932 intret = umsdos_nevercreat(dir,name,len,-EPERM);
933 if (ret == 0){ 934 structumsdos_infoinfo;
935 ret = umsdos_parse (name,len,&info);
936 if (ret == 0){ 937 umsdos_lockcreate(dir);
938 ret = umsdos_findentry(dir,&info,1);
939 if (ret == 0){ 940 PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
941 /* check sticky bit */ 942 if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
943 current->fsuid == info.entry.uid ||
944 current->fsuid == dir->i_uid ) { 945 if (info.entry.flags & UMSDOS_HLINK){ 946 /* #Specification: hard link / deleting a link 947 When we deletes a file, and this file is a link 948 we must subtract 1 to the nlink field of the 949 hidden link. 950 951 If the count goes to 0, we delete this hidden 952 link too. 953 */ 954 /* 955 First, get the inode of the hidden link 956 using the standard lookup function. 957 */ 958 structinode *inode;
959 dir->i_count++;
960 ret = UMSDOS_lookup (dir,name,len,&inode);
961 if (ret == 0){ 962 PRINTK (("unlink nlink = %d ",inode->i_nlink));
963 inode->i_nlink--;
964 if (inode->i_nlink == 0){ 965 structinode *hdir = iget(inode->i_sb 966 ,inode->u.umsdos_i.i_dir_owner);
967 structumsdos_dirententry;
968 ret = umsdos_inode2entry (hdir,inode,&entry);
969 if (ret == 0){ 970 ret = UMSDOS_unlink (hdir,entry.name 971 ,entry.name_len);
972 }else{ 973 iput (hdir);
974 } 975 }else{ 976 structiattrnewattrs;
977 newattrs.ia_valid = 0;
978 ret = UMSDOS_notify_change (inode, &newattrs);
979 } 980 iput (inode);
981 } 982 } 983 if (ret == 0){ 984 ret = umsdos_delentry (dir,&info,0);
985 if (ret == 0){ 986 PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
987 dir->i_count++;
988 ret = msdos_unlink_umsdos (dir,info.fake.fname 989 ,info.fake.len);
990 PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname 991 ,info.entry.mode,ret));
992 } 993 } 994 }else{ 995 /* sticky bit set and we've not got permission */ 996 PRINTK(("sticky set "));
997 ret = -EPERM;
998 } 999 }1000 umsdos_unlockcreate(dir);
1001 }1002 }1003 iput (dir);
1004 PRINTK (("umsdos_unlink %d\n",ret));
1005 returnret;
1006 }1007
1008 /*1009 Rename a file (move) in the file system.1010 */1011 intUMSDOS_rename(
/* */1012 structinode * old_dir,
1013 constchar * old_name,
1014 intold_len,
1015 structinode * new_dir,
1016 constchar * new_name,
1017 intnew_len)
1018 {1019 /* #Specification: weakness / rename1020 There is a case where UMSDOS rename has a different behavior1021 than normal UNIX file system. Renaming an open file across1022 directory boundary does not work. Renaming an open file within1023 a directory does work however.1024
1025 The problem (not sure) is in the linux VFS msdos driver.1026 I believe this is not a bug but a design feature, because1027 an inode number represent some sort of directory address1028 in the MSDOS directory structure. So moving the file into1029 another directory does not preserve the inode number.1030 */1031 intret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
1032 if (ret == 0){1033 /* umsdos_rename_f eat the inode and we may need those later */1034 old_dir->i_count++;
1035 new_dir->i_count++;
1036 ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name1037 ,new_len,0);
1038 if (ret == -EEXIST){1039 /* #Specification: rename / new name exist1040 If the destination name already exist, it will1041 silently be removed. EXT2 does it this way1042 and this is the spec of SUNOS. So does UMSDOS.1043
1044 If the destination is an empty directory it will1045 also be removed.1046 */1047 /* #Specification: rename / new name exist / possible flaw1048 The code to handle the deletion of the target (file1049 and directory) use to be in umsdos_rename_f, surrounded1050 by proper directory locking. This was insuring that only1051 one process could achieve a rename (modification) operation1052 in the source and destination directory. This was also1053 insuring the operation was "atomic".1054
1055 This has been changed because this was creating a kernel1056 stack overflow (stack is only 4k in the kernel). To avoid1057 the code doing the deletion of the target (if exist) has1058 been moved to a upper layer. umsdos_rename_f is tried1059 once and if it fails with EEXIST, the target is removed1060 and umsdos_rename_f is done again.1061
1062 This makes the code cleaner and (not sure) solve a1063 deadlock problem one tester was experiencing.1064
1065 The point is to mention that possibly, the semantic of1066 "rename" may be wrong. Anyone dare to check that :-)1067 Be aware that IF it is wrong, to produce the problem you1068 will need two process trying to rename a file to the1069 same target at the same time. Again, I am not sure it1070 is a problem at all.1071 */1072 /* This is not super efficient but should work */1073 new_dir->i_count++;
1074 ret = UMSDOS_unlink (new_dir,new_name,new_len);
1075 chkstk();
1076 PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
1077 if (ret == -EISDIR){1078 new_dir->i_count++;
1079 ret = UMSDOS_rmdir (new_dir,new_name,new_len);
1080 chkstk();
1081 PRINTK (("rename rmdir ret %d -- ",ret));
1082 }1083 if (ret == 0){1084 ret = umsdos_rename_f (old_dir,old_name,old_len1085 ,new_dir,new_name,new_len,0);
1086 new_dir = old_dir = NULL;
1087 }1088 }1089 }1090 iput (new_dir);
1091 iput (old_dir);
1092 returnret;
1093 }1094