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

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