root/fs/umsdos/namei.c

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

DEFINITIONS

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

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

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