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

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