root/fs/umsdos/namei.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. umsdos_waitcreate
  2. umsdos_waitlookup
  3. umsdos_lockcreate
  4. umsdos_lockcreate2
  5. umsdos_startlookup
  6. umsdos_unlockcreate
  7. umsdos_endlookup
  8. umsdos_lockcreate
  9. umsdos_lockcreate2
  10. umsdos_startlookup
  11. umsdos_unlockcreate
  12. umsdos_endlookup
  13. umsdos_nevercreat
  14. umsdos_create_any
  15. umsdos_ren_init
  16. umsdos_rename_f
  17. umsdos_symlink_x
  18. UMSDOS_symlink
  19. UMSDOS_link
  20. UMSDOS_create
  21. UMSDOS_mkdir
  22. UMSDOS_mknod
  23. UMSDOS_rmdir
  24. UMSDOS_unlink
  25. UMSDOS_rename

   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 #ifdef MODULE
  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 #define PRINTK(x)
  25 #define Printk(x)       printk x
  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 static int umsdos_waitcreate(struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         int ret = 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         return ret;
  44 }
  45 /*
  46         Wait for any lookup process to finish
  47 */
  48 static void umsdos_waitlookup (struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 void umsdos_lockcreate (struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 void umsdos_startlookup (struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126         while (umsdos_waitcreate (dir) != 0);
 127         dir->u.umsdos_i.u.dir_info.looking++;
 128 }
 129 void check_page_tables(void);
 130 
 131 /*
 132         Unlock the directory.
 133 */
 134 void umsdos_unlockcreate (struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 void umsdos_endlookup (struct inode *dir)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 static void umsdos_lockcreate (struct inode *dir){}
     /* [previous][next][first][last][top][bottom][index][help] */
 157 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
     /* [previous][next][first][last][top][bottom][index][help] */
 158 void umsdos_startlookup (struct inode *dir){}
     /* [previous][next][first][last][top][bottom][index][help] */
 159 static void umsdos_unlockcreate (struct inode *dir){}
     /* [previous][next][first][last][top][bottom][index][help] */
 160 void umsdos_endlookup (struct inode *dir){}
     /* [previous][next][first][last][top][bottom][index][help] */
 161 #endif
 162 static int umsdos_nevercreat(
     /* [previous][next][first][last][top][bottom][index][help] */
 163         struct inode *dir,
 164         const char *name,               /* Name of the file to add */
 165         int len,
 166         int errcod)                             /* Length of the name */
 167 {
 168         int ret = 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         }else if (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         return ret;
 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 static int umsdos_create_any (
     /* [previous][next][first][last][top][bottom][index][help] */
 204         struct inode *dir,
 205         const char *name,               /* Name of the file to add */
 206         int len,                                /* Length of the name */
 207         int mode,                               /* Permission bit + file type ??? */
 208         int rdev,                               /* major, minor or 0 for ordinary file */
 209                                                         /* and symlinks */
 210         char flags,
 211         struct inode **result)  /* Will hold the inode of the newly created */
 212                                                         /* file */
 213 {
 214         int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
 215         if (ret == 0){
 216                 struct umsdos_info info;
 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                                         struct inode *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         return ret;
 279 }
 280 /*
 281         Initialise the new_entry from the old for a rename operation.
 282         (Only useful for umsdos_rename_f() below).
 283 */
 284 static void umsdos_ren_init(
     /* [previous][next][first][last][top][bottom][index][help] */
 285         struct umsdos_info *new_info,
 286         struct umsdos_info *old_info,
 287         int flags)              /* 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 #define chkstk() \
 302         if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
 303                 printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
 304                 , current->comm,STACK_MAGIC \
 305                 ,*(unsigned long *)current->kernel_stack_page \
 306                 ,__LINE__); \
 307         }
 308         
 309 /*
 310         Rename a file (move) in the file system.
 311 */
 312 static int umsdos_rename_f(
     /* [previous][next][first][last][top][bottom][index][help] */
 313         struct inode * old_dir,
 314         const char * old_name,
 315         int old_len,
 316         struct inode * new_dir,
 317         const char * new_name,
 318         int new_len,
 319         int flags)              /* 0 == copy flags from old_name */
 320                                         /* != 0, this is the value of flags */
 321 {
 322         int ret = EPERM;
 323         struct umsdos_info old_info;
 324         int old_ret = umsdos_parse (old_name,old_len,&old_info);
 325         struct umsdos_info new_info;
 326         int new_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                                                 struct inode *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         return ret;
 398 }
 399 /*
 400         Setup un Symbolic link or a (pseudo) hard link
 401         Return a negative error code or 0 if ok.
 402 */
 403 static int umsdos_symlink_x(
     /* [previous][next][first][last][top][bottom][index][help] */
 404         struct inode * dir,
 405         const char * name,
 406         int len,
 407         const char * symname,   /* name will point to this path */
 408         int mode,
 409         char flags)
 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         struct inode *inode;
 422         int ret;
 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                 int len = strlen(symname);
 429                 struct file filp;
 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         return ret;
 451 }
 452 /*
 453         Setup un Symbolic link.
 454         Return a negative error code or 0 if ok.
 455 */
 456 int UMSDOS_symlink(
     /* [previous][next][first][last][top][bottom][index][help] */
 457         struct inode * dir,
 458         const char * name,
 459         int len,
 460         const char * symname)   /* name will point to this path */
 461 {
 462         return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
 463 }
 464 /*
 465         Add a link to an inode in a directory
 466 */
 467 int UMSDOS_link (
     /* [previous][next][first][last][top][bottom][index][help] */
 468         struct inode * oldinode,
 469         struct inode * dir,
 470         const char * name,
 471         int len)
 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         int ret = 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         }else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){
 551                 struct inode *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                         struct umsdos_dirent entry;
 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                                         struct umsdos_info info;
 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                 struct iattr newattrs;
 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         return ret;
 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 int UMSDOS_create (
     /* [previous][next][first][last][top][bottom][index][help] */
 648         struct inode *dir,
 649         const char *name,               /* Name of the file to add */
 650         int len,                                /* Length of the name */
 651         int mode,                               /* Permission bit + file type ??? */
 652         struct inode **result)  /* Will hold the inode of the newly created */
 653                                                         /* file */
 654 {
 655         return umsdos_create_any (dir,name,len,mode,0,0,result);
 656 }
 657 /*
 658         Add a sub-directory in a directory
 659 */
 660 int UMSDOS_mkdir(
     /* [previous][next][first][last][top][bottom][index][help] */
 661         struct inode * dir,
 662         const char * name,
 663         int len,
 664         int mode)
 665 {
 666         int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
 667         if (ret == 0){
 668                 struct umsdos_info info;
 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                                         struct inode *subdir;
 701                                         ret = umsdos_real_lookup (dir,info.fake.fname
 702                                                 ,info.fake.len,&subdir);
 703                                         if (ret == 0){
 704                                                 struct inode *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         return ret;
 722 }
 723 /*
 724         Add a new device special file into a directory.
 725 */
 726 int UMSDOS_mknod(
     /* [previous][next][first][last][top][bottom][index][help] */
 727         struct inode * dir,
 728         const char * name,
 729         int len,
 730         int mode,
 731         int rdev)
 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         struct inode *inode;
 748         int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
 749         iput (inode);
 750         return ret;
 751 }
 752 
 753 /*
 754         Remove a sub-directory.
 755 */
 756 int UMSDOS_rmdir(
     /* [previous][next][first][last][top][bottom][index][help] */
 757         struct inode * dir,
 758         const char * name,
 759         int len)
 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         int ret = umsdos_nevercreat(dir,name,len,-EPERM);
 849         if (ret == 0){
 850                 struct inode *sdir;
 851                 dir->i_count++;
 852                 ret = UMSDOS_lookup (dir,name,len,&sdir);
 853                 PRINTK (("rmdir lookup %d ",ret));
 854                 if (ret == 0){
 855                         int empty;
 856                         umsdos_lockcreate(dir);
 857                         if (sdir->i_count > 1){
 858                                 ret = -EBUSY;
 859                         }else if ((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                                         struct umsdos_info info;
 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         return ret;
 897 }
 898 /*
 899         Remove a file from the directory.
 900 */
 901 int UMSDOS_unlink (
     /* [previous][next][first][last][top][bottom][index][help] */
 902         struct inode * dir,
 903         const char * name,
 904         int len)
 905 {
 906         struct umsdos_info info;
 907         int ret = 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                                         struct inode *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                                                         struct inode *hdir = iget(inode->i_sb
 936                                                                 ,inode->u.umsdos_i.i_dir_owner);
 937                                                         struct umsdos_dirent entry;
 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                                                         struct iattr newattrs;
 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         return ret;
 971 }
 972 
 973 /*
 974         Rename a file (move) in the file system.
 975 */
 976 int UMSDOS_rename(
     /* [previous][next][first][last][top][bottom][index][help] */
 977         struct inode * old_dir,
 978         const char * old_name,
 979         int old_len,
 980         struct inode * new_dir,
 981         const char * new_name,
 982         int new_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         int ret = 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_name
1002                         ,new_len,0);
1003                 if (ret == -EEXIST){
1004                         /* #Specification: rename / new name exist
1005                                 If the destination name already exist, it will
1006                                 silently be removed. EXT2 does it this way
1007                                 and this is the spec of SUNOS. So does UMSDOS.
1008 
1009                                 If the destination is an empty directory it will
1010                                 also be removed.
1011                         */
1012                         /* #Specification: rename / new name exist / possible flaw
1013                                 The code to handle the deletion of the target (file
1014                                 and directory) use to be in umsdos_rename_f, surrounded
1015                                 by proper directory locking. This was insuring that only
1016                                 one process could achieve a rename (modification) operation
1017                                 in the source and destination directory. This was also
1018                                 insuring the operation was "atomic".
1019 
1020                                 This has been changed because this was creating a kernel
1021                                 stack overflow (stack is only 4k in the kernel). To avoid
1022                                 the code doing the deletion of the target (if exist) has
1023                                 been moved to a upper layer. umsdos_rename_f is tried
1024                                 once and if it fails with EEXIST, the target is removed
1025                                 and umsdos_rename_f is done again.
1026 
1027                                 This makes the code cleaner and (not sure) solve a
1028                                 deadlock problem one tester was experiencing.
1029 
1030                                 The point is to mention that possibly, the semantic of
1031                                 "rename" may be wrong. Anyone dare to check that :-)
1032                                 Be aware that IF it is wrong, to produce the problem you
1033                                 will need two process trying to rename a file to the
1034                                 same target at the same time. Again, I am not sure it
1035                                 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_len
1050                                         ,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         return ret;
1058 }
1059 

/* [previous][next][first][last][top][bottom][index][help] */