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

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