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                 struct iattr newattrs;
 621                 oldinode->i_nlink++;
 622                 newattrs.ia_valid = 0;
 623                 ret = UMSDOS_notify_change(oldinode, &newattrs);
 624         }
 625         iput (oldinode);
 626         iput (dir);
 627         PRINTK (("umsdos_link %d\n",ret));
 628         return ret;
 629 }
 630 /*
 631         Add a new file into the alternate directory.
 632         The file is added to the real MSDOS directory. If successful, it
 633         is then added to the EDM file.
 634 
 635         Return the status of the operation. 0 mean success.
 636 */
 637 int UMSDOS_create (
     /* [previous][next][first][last][top][bottom][index][help] */
 638         struct inode *dir,
 639         const char *name,               /* Name of the file to add */
 640         int len,                                /* Length of the name */
 641         int mode,                               /* Permission bit + file type ??? */
 642         struct inode **result)  /* Will hold the inode of the newly created */
 643                                                         /* file */
 644 {
 645         return umsdos_create_any (dir,name,len,mode,0,0,result);
 646 }
 647 /*
 648         Add a sub-directory in a directory
 649 */
 650 int UMSDOS_mkdir(
     /* [previous][next][first][last][top][bottom][index][help] */
 651         struct inode * dir,
 652         const char * name,
 653         int len,
 654         int mode)
 655 {
 656         int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
 657         if (ret == 0){
 658                 struct umsdos_info info;
 659                 ret = umsdos_parse (name,len,&info);
 660                 PRINTK (("umsdos_mkdir %d\n",ret));
 661                 if (ret == 0){
 662                         info.entry.mode = mode | S_IFDIR;
 663                         info.entry.rdev = 0;
 664                         info.entry.uid = current->fsuid;
 665                         info.entry.gid = (dir->i_mode & S_ISGID)
 666                                 ? dir->i_gid : current->fsgid;
 667                         info.entry.ctime = info.entry.atime = info.entry.mtime
 668                                 = CURRENT_TIME;
 669                         info.entry.flags = 0;
 670                         umsdos_lockcreate(dir);
 671                         info.entry.nlink = 1;
 672                         ret = umsdos_newentry (dir,&info);
 673                         PRINTK (("newentry %d ",ret));
 674                         if (ret == 0){
 675                                 dir->i_count++;
 676                                 ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
 677                                 if (ret != 0){
 678                                         umsdos_delentry (dir,&info,1);
 679                                         /* #Specification: mkdir / Directory already exist in DOS
 680                                                 We do the same thing as for file creation.
 681                                                 For all user it is an error.
 682                                         */
 683                                 }else{
 684                                         /* #Specification: mkdir / umsdos directory / create EMD
 685                                                 When we created a new sub-directory in a UMSDOS
 686                                                 directory (one with full UMSDOS semantic), we
 687                                                 create immediately an EMD file in the new
 688                                                 sub-directory so it inherit UMSDOS semantic.
 689                                         */
 690                                         struct inode *subdir;
 691                                         ret = umsdos_real_lookup (dir,info.fake.fname
 692                                                 ,info.fake.len,&subdir);
 693                                         if (ret == 0){
 694                                                 struct inode *result;
 695                                                 ret = msdos_create (subdir,UMSDOS_EMD_FILE
 696                                                         ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
 697                                                 subdir = NULL;
 698                                                 iput (result);
 699                                         }
 700                                         if (ret < 0){
 701                                                 printk ("UMSDOS: Can't create empty --linux-.---\n");
 702                                         }
 703                                         iput (subdir);
 704                                 }
 705                         }
 706                         umsdos_unlockcreate(dir);
 707                 }
 708         }
 709         PRINTK (("umsdos_mkdir %d\n",ret));
 710         iput (dir);
 711         return ret;
 712 }
 713 /*
 714         Add a new device special file into a directory.
 715 */
 716 int UMSDOS_mknod(
     /* [previous][next][first][last][top][bottom][index][help] */
 717         struct inode * dir,
 718         const char * name,
 719         int len,
 720         int mode,
 721         int rdev)
 722 {
 723         /* #Specification: Special files / strategy
 724                 Device special file, pipes, etc ... are created like normal
 725                 file in the msdos file system. Of course they remain empty.
 726 
 727                 One strategy was to create those files only in the EMD file
 728                 since they were not important for MSDOS. The problem with
 729                 that, is that there were not getting inode number allocated.
 730                 The MSDOS filesystems is playing a nice game to fake inode
 731                 number, so why not use it.
 732 
 733                 The absence of inode number compatible with those allocated
 734                 for ordinary files was causing major trouble with hard link
 735                 in particular and other parts of the kernel I guess.
 736         */
 737         struct inode *inode;
 738         int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
 739         iput (inode);
 740         return ret;
 741 }
 742 
 743 /*
 744         Remove a sub-directory.
 745 */
 746 int UMSDOS_rmdir(
     /* [previous][next][first][last][top][bottom][index][help] */
 747         struct inode * dir,
 748         const char * name,
 749         int len)
 750 {
 751         /* #Specification: style / iput strategy
 752                 In the UMSDOS project, I am trying to apply a single
 753                 programming style regarding inode management. Many
 754                 entry point are receiving an inode to act on, and must
 755                 do an iput() as soon as they are finished with
 756                 the inode.
 757 
 758                 For simple case, there is no problem. When you introduce
 759                 error checking, you end up with many iput placed around the
 760                 code.
 761 
 762                 The coding style I use all around is one where I am trying
 763                 to provide independent flow logic (I don't know how to
 764                 name this). With this style, code is easier to understand
 765                 but you rapidly get iput() all around. Here is an exemple
 766                 of what I am trying to avoid.
 767 
 768                 if (a){
 769                         ...
 770                         if(b){
 771                                 ...
 772                         }
 773                         ...
 774                         if (c){
 775                                 // Complex state. Was b true ? 
 776                                 ...
 777                         }
 778                         ...
 779                 }
 780                 // Weird state
 781                 if (d){
 782                         // ...
 783                 }
 784                 // Was iput finally done ?
 785                 return status;
 786 
 787                 Here is the style I am using. Still sometime I do the
 788                 first when things are very simple (or very complicated :-( )
 789 
 790                 if (a){
 791                         if (b){
 792                                 ...
 793                         }else if (c){
 794                                 // A single state gets here
 795                         }
 796                 }else if (d){
 797                         ...
 798                 }
 799                 return status;
 800 
 801                 Again, while this help clarifying the code, I often get a lot
 802                 of iput(), unlike the first style, where I can place few 
 803                 "strategic" iput(). "strategic" also mean, more difficult
 804                 to place.
 805 
 806                 So here is the style I will be using from now on in this project.
 807                 There is always an iput() at the end of a function (which has
 808                 to do an iput()). One iput by inode. There is also one iput()
 809                 at the places where a successful operation is achieved. This
 810                 iput() is often done by a sub-function (often from the msdos
 811                 file system). So I get one too many iput() ? At the place
 812                 where an iput() is done, the inode is simply nulled, disabling
 813                 the last one.
 814 
 815                 if (a){
 816                         if (b){
 817                                 ...
 818                         }else if (c){
 819                                 msdos_rmdir(dir,...);
 820                                 dir = NULL;
 821                         }
 822                 }else if (d){
 823                         ...
 824                 }
 825                 iput (dir);
 826                 return status;
 827 
 828                 Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
 829                 pair goes against this practice of "forgetting" the inode as soon
 830                 as possible.
 831         */              
 832         int ret = umsdos_nevercreat(dir,name,len,-EPERM);
 833         if (ret == 0){
 834                 struct inode *sdir;
 835                 dir->i_count++;
 836                 ret = UMSDOS_lookup (dir,name,len,&sdir);
 837                 PRINTK (("rmdir lookup %d ",ret));
 838                 if (ret == 0){
 839                         int empty;
 840                         umsdos_lockcreate(dir);
 841                         if (sdir->i_count > 1){
 842                                 ret = -EBUSY;
 843                         }else if ((empty = umsdos_isempty (sdir)) != 0){
 844                                 PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
 845                                 if (empty == 1){
 846                                         /* We have to removed the EMD file */
 847                                         ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
 848                                                 ,UMSDOS_EMD_NAMELEN);
 849                                         sdir = NULL;
 850                                 }
 851                                 /* sdir must be free before msdos_rmdir() */
 852                                 iput (sdir);
 853                                 sdir = NULL;
 854                                 PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
 855                                 if (ret == 0){
 856                                         struct umsdos_info info;
 857                                         dir->i_count++;
 858                                         umsdos_parse (name,len,&info);
 859                                         /* The findentry is there only to complete */
 860                                         /* the mangling */
 861                                         umsdos_findentry (dir,&info,2);
 862                                         ret = msdos_rmdir (dir,info.fake.fname
 863                                                 ,info.fake.len);
 864                                         if (ret == 0){
 865                                                 ret = umsdos_delentry (dir,&info,1);
 866                                         }
 867                                 }
 868                         }else{  
 869                                 /*
 870                                         The subdirectory is not empty, so leave it there
 871                                 */
 872                                 ret = -ENOTEMPTY;
 873                         }
 874                         iput(sdir);
 875                         umsdos_unlockcreate(dir);
 876                 }       
 877         }
 878         iput (dir);
 879         PRINTK (("umsdos_rmdir %d\n",ret));
 880         return ret;
 881 }
 882 /*
 883         Remove a file from the directory.
 884 */
 885 int UMSDOS_unlink (
     /* [previous][next][first][last][top][bottom][index][help] */
 886         struct inode * dir,
 887         const char * name,
 888         int len)
 889 {
 890         struct umsdos_info info;
 891         int ret = umsdos_nevercreat(dir,name,len,-EPERM);
 892         if (ret == 0){
 893                 ret = umsdos_parse (name,len,&info);
 894                 if (ret == 0){
 895                         umsdos_lockcreate(dir);
 896                         ret = umsdos_findentry(dir,&info,1);
 897                         if (ret == 0){
 898                                 PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
 899                                 if (info.entry.flags & UMSDOS_HLINK){
 900                                         /* #Specification: hard link / deleting a link
 901                                                 When we deletes a file, and this file is a link
 902                                                 we must subtract 1 to the nlink field of the
 903                                                 hidden link.
 904 
 905                                                 If the count goes to 0, we delete this hidden
 906                                                 link too.
 907                                         */
 908                                         /*
 909                                                 First, get the inode of the hidden link
 910                                                 using the standard lookup function.
 911                                         */
 912                                         struct inode *inode;
 913                                         dir->i_count++;
 914                                         ret = UMSDOS_lookup (dir,name,len,&inode);
 915                                         if (ret == 0){
 916                                                 PRINTK (("unlink nlink = %d ",inode->i_nlink));
 917                                                 inode->i_nlink--;
 918                                                 if (inode->i_nlink == 0){
 919                                                         struct inode *hdir = iget(inode->i_sb
 920                                                                 ,inode->u.umsdos_i.i_dir_owner);
 921                                                         struct umsdos_dirent entry;
 922                                                         ret = umsdos_inode2entry (hdir,inode,&entry);
 923                                                         if (ret == 0){
 924                                                                 ret = UMSDOS_unlink (hdir,entry.name
 925                                                                         ,entry.name_len);
 926                                                         }else{
 927                                                                 iput (hdir);
 928                                                         }
 929                                                 }else{
 930                                                         struct iattr newattrs;
 931                                                         newattrs.ia_valid = 0;
 932                                                         ret = UMSDOS_notify_change (inode, &newattrs);
 933                                                 }
 934                                                 iput (inode);
 935                                         }
 936                                 }
 937                                 if (ret == 0){
 938                                         ret = umsdos_delentry (dir,&info,0);
 939                                         if (ret == 0){
 940                                                 PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
 941                                                 dir->i_count++;
 942                                                 ret = msdos_unlink_umsdos (dir,info.fake.fname
 943                                                         ,info.fake.len);
 944                                                 PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
 945                                                         ,info.entry.mode,ret));
 946                                         }
 947                                 }
 948                         }
 949                         umsdos_unlockcreate(dir);
 950                 }
 951         }       
 952         iput (dir);
 953         PRINTK (("umsdos_unlink %d\n",ret));
 954         return ret;
 955 }
 956 
 957 /*
 958         Rename a file (move) in the file system.
 959 */
 960 int UMSDOS_rename(
     /* [previous][next][first][last][top][bottom][index][help] */
 961         struct inode * old_dir,
 962         const char * old_name,
 963         int old_len,
 964         struct inode * new_dir,
 965         const char * new_name,
 966         int new_len)
 967 {
 968         /* #Specification: weakness / rename
 969                 There is a case where UMSDOS rename has a different behavior
 970                 than normal UNIX file system. Renaming an open file across
 971                 directory boundary does not work. Renaming an open file within
 972                 a directory does work however.
 973 
 974                 The problem (not sure) is in the linux VFS msdos driver.
 975                 I believe this is not a bug but a design feature, because
 976                 an inode number represent some sort of directory address
 977                 in the MSDOS directory structure. So moving the file into
 978                 another directory does not preserve the inode number.
 979         */
 980         int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
 981         if (ret == 0){
 982                 /* umsdos_rename_f eat the inode and we may need those later */
 983                 old_dir->i_count++;
 984                 new_dir->i_count++;
 985                 ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
 986                         ,new_len,0);
 987                 if (ret == -EEXIST){
 988                         /* #Specification: rename / new name exist
 989                                 If the destination name already exist, it will
 990                                 silently be removed. EXT2 does it this way
 991                                 and this is the spec of SUNOS. So does UMSDOS.
 992 
 993                                 If the destination is an empty directory it will
 994                                 also be removed.
 995                         */
 996                         /* #Specification: rename / new name exist / possible flaw
 997                                 The code to handle the deletion of the target (file
 998                                 and directory) use to be in umsdos_rename_f, surrounded
 999                                 by proper directory locking. This was insuring that only
1000                                 one process could achieve a rename (modification) operation
1001                                 in the source and destination directory. This was also
1002                                 insuring the operation was "atomic".
1003 
1004                                 This has been changed because this was creating a kernel
1005                                 stack overflow (stack is only 4k in the kernel). To avoid
1006                                 the code doing the deletion of the target (if exist) has
1007                                 been moved to a upper layer. umsdos_rename_f is tried
1008                                 once and if it fails with EEXIST, the target is removed
1009                                 and umsdos_rename_f is done again.
1010 
1011                                 This makes the code cleaner and (not sure) solve a
1012                                 deadlock problem one tester was experiencing.
1013 
1014                                 The point is to mention that possibly, the semantic of
1015                                 "rename" may be wrong. Anyone dare to check that :-)
1016                                 Be aware that IF it is wrong, to produce the problem you
1017                                 will need two process trying to rename a file to the
1018                                 same target at the same time. Again, I am not sure it
1019                                 is a problem at all.
1020                         */
1021                         /* This is not super efficient but should work */
1022                         new_dir->i_count++;
1023                         ret = UMSDOS_unlink (new_dir,new_name,new_len);
1024 chkstk();
1025                         PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
1026                         if (ret == -EISDIR){
1027                                 new_dir->i_count++;
1028                                 ret = UMSDOS_rmdir (new_dir,new_name,new_len);
1029 chkstk();
1030                                 PRINTK (("rename rmdir ret %d -- ",ret));
1031                         }
1032                         if (ret == 0){
1033                                 ret = umsdos_rename_f (old_dir,old_name,old_len
1034                                         ,new_dir,new_name,new_len,0);
1035                                 new_dir = old_dir = NULL;
1036                         }
1037                 }
1038         }
1039         iput (new_dir);
1040         iput (old_dir);
1041         return ret;
1042 }
1043 

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