The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/umsdos/namei.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/umsdos/namei.c
    3  *
    4  *      Written 1993 by Jacques Gelinas 
    5  *      Inspired from linux/fs/msdos/... by Werner Almesberger
    6  *
    7  * Maintain and access the --linux alternate directory file.
    8  */
    9  /*
   10   * You are in the maze of twisted functions - half of them shouldn't
   11   * be here...
   12   */
   13 
   14 #include <linux/errno.h>
   15 #include <linux/kernel.h>
   16 #include <linux/sched.h>
   17 #include <linux/types.h>
   18 #include <linux/fcntl.h>
   19 #include <linux/stat.h>
   20 #include <linux/string.h>
   21 #include <linux/msdos_fs.h>
   22 #include <linux/umsdos_fs.h>
   23 #include <linux/slab.h>
   24 
   25 #define UMSDOS_DIR_LOCK
   26 
   27 #ifdef UMSDOS_DIR_LOCK
   28 
   29 static inline void u_sleep_on (struct inode *dir)
   30 {
   31         sleep_on (&dir->u.umsdos_i.dir_info.p);
   32 }
   33 
   34 static inline void u_wake_up (struct inode *dir)
   35 {
   36         wake_up (&dir->u.umsdos_i.dir_info.p);
   37 }
   38 
   39 /*
   40  * Wait for creation exclusivity.
   41  * Return 0 if the dir was already available.
   42  * Return 1 if a wait was necessary.
   43  * When 1 is return, it means a wait was done. It does not
   44  * mean the directory is available.
   45  */
   46 static int umsdos_waitcreate (struct inode *dir)
   47 {
   48         int ret = 0;
   49 
   50         if (dir->u.umsdos_i.dir_info.creating
   51             && dir->u.umsdos_i.dir_info.pid != current->pid) {
   52                 PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", dir->u.umsdos_i.dir_info.pid, current->pid));
   53                 u_sleep_on (dir);
   54                 ret = 1;
   55         }
   56         return ret;
   57 }
   58 
   59 /*
   60  * Wait for any lookup process to finish
   61  */
   62 static void umsdos_waitlookup (struct inode *dir)
   63 {
   64         while (dir->u.umsdos_i.dir_info.looking) {
   65                 u_sleep_on (dir);
   66         }
   67 }
   68 
   69 /*
   70  * Lock all other process out of this directory.
   71  */
   72 /* #Specification: file creation / not atomic
   73  * File creation is a two step process. First we create (allocate)
   74  * an entry in the EMD file and then (using the entry offset) we
   75  * build a unique name for MSDOS. We create this name in the msdos
   76  * space.
   77  * 
   78  * We have to use semaphore (sleep_on/wake_up) to prevent lookup
   79  * into a directory when we create a file or directory and to
   80  * prevent creation while a lookup is going on. Since many lookup
   81  * may happen at the same time, the semaphore is a counter.
   82  * 
   83  * Only one creation is allowed at the same time. This protection
   84  * may not be necessary. The problem arise mainly when a lookup
   85  * or a readdir is done while a file is partially created. The
   86  * lookup process see that as a "normal" problem and silently
   87  * erase the file from the EMD file. Normal because a file
   88  * may be erased during a MSDOS session, but not removed from
   89  * the EMD file.
   90  * 
   91  * The locking is done on a directory per directory basis. Each
   92  * directory inode has its wait_queue.
   93  * 
   94  * For some operation like hard link, things even get worse. Many
   95  * creation must occur at once (atomic). To simplify the design
   96  * a process is allowed to recursively lock the directory for
   97  * creation. The pid of the locking process is kept along with
   98  * a counter so a second level of locking is granted or not.
   99  */
  100 void umsdos_lockcreate (struct inode *dir)
  101 {
  102         /*
  103          * Wait for any creation process to finish except
  104          * if we (the process) own the lock
  105          */
  106         while (umsdos_waitcreate (dir) != 0);
  107         dir->u.umsdos_i.dir_info.creating++;
  108         dir->u.umsdos_i.dir_info.pid = current->pid;
  109         umsdos_waitlookup (dir);
  110 }
  111 
  112 /*
  113  * Lock all other process out of those two directories.
  114  */
  115 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
  116 {
  117         /*
  118          * We must check that both directory are available before
  119          * locking anyone of them. This is to avoid some deadlock.
  120          * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
  121          * this to me.
  122          */
  123         while (1) {
  124                 if (umsdos_waitcreate (dir1) == 0
  125                     && umsdos_waitcreate (dir2) == 0) {
  126                         /* We own both now */
  127                         dir1->u.umsdos_i.dir_info.creating++;
  128                         dir1->u.umsdos_i.dir_info.pid = current->pid;
  129                         dir2->u.umsdos_i.dir_info.creating++;
  130                         dir2->u.umsdos_i.dir_info.pid = current->pid;
  131                         break;
  132                 }
  133         }
  134         umsdos_waitlookup (dir1);
  135         umsdos_waitlookup (dir2);
  136 }
  137 
  138 /*
  139  * Wait until creation is finish in this directory.
  140  */
  141 void umsdos_startlookup (struct inode *dir)
  142 {
  143         while (umsdos_waitcreate (dir) != 0);
  144         dir->u.umsdos_i.dir_info.looking++;
  145 }
  146 
  147 /*
  148  * Unlock the directory.
  149  */
  150 void umsdos_unlockcreate (struct inode *dir)
  151 {
  152         dir->u.umsdos_i.dir_info.creating--;
  153         if (dir->u.umsdos_i.dir_info.creating < 0) {
  154                 printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"
  155                         ,dir->u.umsdos_i.dir_info.creating);
  156         }
  157         u_wake_up (dir);
  158 }
  159 
  160 /*
  161  * Tell directory lookup is over.
  162  */
  163 void umsdos_endlookup (struct inode *dir)
  164 {
  165         dir->u.umsdos_i.dir_info.looking--;
  166         if (dir->u.umsdos_i.dir_info.looking < 0) {
  167                 printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"
  168                         ,dir->u.umsdos_i.dir_info.looking);
  169         }
  170         u_wake_up (dir);
  171 }
  172 
  173 #else
  174 static void umsdos_lockcreate (struct inode *dir)
  175 {
  176 }
  177 static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
  178 {
  179 }
  180 void umsdos_startlookup (struct inode *dir)
  181 {
  182 }
  183 static void umsdos_unlockcreate (struct inode *dir)
  184 {
  185 }
  186 void umsdos_endlookup (struct inode *dir)
  187 {
  188 }
  189 
  190 #endif
  191 
  192 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
  193                                 int errcod)
  194 {
  195         int ret = 0;
  196 
  197         if (umsdos_is_pseudodos (dir, dentry)) {
  198                 /* #Specification: pseudo root / any file creation /DOS
  199                  * The pseudo sub-directory /DOS can't be created!
  200                  * EEXIST is returned.
  201                  * 
  202                  * The pseudo sub-directory /DOS can't be removed!
  203                  * EPERM is returned.
  204                  */
  205                 ret = errcod;
  206         }
  207         return ret;
  208 }
  209 
  210 /*
  211  * Add a new file (ordinary or special) into the alternate directory.
  212  * The file is added to the real MSDOS directory. If successful, it
  213  * is then added to the EMD file.
  214  * 
  215  * Return the status of the operation. 0 mean success.
  216  *
  217  * #Specification: create / file exists in DOS
  218  * Here is a situation: we are trying to create a file with
  219  * UMSDOS. The file is unknown to UMSDOS but already
  220  * exists in the DOS directory.
  221  * 
  222  * Here is what we are NOT doing:
  223  * 
  224  * We could silently assume that everything is fine
  225  * and allows the creation to succeed.
  226  * 
  227  * It is possible not all files in the partition
  228  * are meant to be visible from linux. By trying to create
  229  * those file in some directory, one user may get access
  230  * to those file without proper permissions. Looks like
  231  * a security hole to me. Off course sharing a file system
  232  * with DOS is some kind of security hole :-)
  233  * 
  234  * So ?
  235  * 
  236  * We return EEXIST in this case.
  237  * The same is true for directory creation.
  238  */
  239 static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
  240                                 int mode, int rdev, char flags)
  241 {
  242         struct dentry *fake;
  243         struct inode *inode;
  244         int ret;
  245         struct umsdos_info info;
  246 
  247         ret = umsdos_nevercreat (dir, dentry, -EEXIST);
  248         if (ret)
  249                 goto out;
  250 
  251         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  252         if (ret)
  253                 goto out;
  254 
  255         info.entry.mode = mode;
  256         info.entry.rdev = rdev;
  257         info.entry.flags = flags;
  258         info.entry.uid = current->fsuid;
  259         info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
  260         info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
  261         info.entry.nlink = 1;
  262         ret = umsdos_newentry (dentry->d_parent, &info);
  263         if (ret)
  264                 goto out;
  265 
  266         /* do a real lookup to get the short name dentry */
  267         fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  268         ret = PTR_ERR(fake);
  269         if (IS_ERR(fake))
  270                 goto out_remove;
  271 
  272         /* should not exist yet ... */
  273         ret = -EEXIST;
  274         if (fake->d_inode)
  275                 goto out_remove_dput;
  276 
  277         ret = msdos_create (dir, fake, S_IFREG | 0777);
  278         if (ret)
  279                 goto out_remove_dput;
  280 
  281         inode = fake->d_inode;
  282         atomic_inc(&inode->i_count);
  283         d_instantiate (dentry, inode);
  284         dput(fake);
  285         if (atomic_read(&inode->i_count) > 1) {
  286                 printk(KERN_WARNING
  287                         "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n",
  288                         dentry->d_parent->d_name.name, dentry->d_name.name,
  289                         inode->i_ino, atomic_read(&inode->i_count));
  290         }
  291         umsdos_lookup_patch_new(dentry, &info);
  292 
  293 out:
  294         return ret;
  295 
  296         /* Creation failed ... remove the EMD entry */
  297 out_remove_dput:
  298         dput(fake);
  299 out_remove:
  300         if (ret == -EEXIST)
  301                 printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
  302                         dentry->d_parent->d_name.name, info.fake.fname);
  303         umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
  304         goto out;
  305 }
  306 
  307 /*
  308  * Add a new file into the alternate directory.
  309  * The file is added to the real MSDOS directory. If successful, it
  310  * is then added to the EMD file.
  311  * 
  312  * Return the status of the operation. 0 mean success.
  313  */
  314 int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
  315 {
  316         return umsdos_create_any (dir, dentry, mode, 0, 0);
  317 }
  318 
  319 
  320 /*
  321  * Initialise the new_entry from the old for a rename operation.
  322  * (Only useful for umsdos_rename_f() below).
  323  */
  324 static void umsdos_ren_init (struct umsdos_info *new_info,
  325                              struct umsdos_info *old_info)
  326 {
  327         new_info->entry.mode = old_info->entry.mode;
  328         new_info->entry.rdev = old_info->entry.rdev;
  329         new_info->entry.uid = old_info->entry.uid;
  330         new_info->entry.gid = old_info->entry.gid;
  331         new_info->entry.ctime = old_info->entry.ctime;
  332         new_info->entry.atime = old_info->entry.atime;
  333         new_info->entry.mtime = old_info->entry.mtime;
  334         new_info->entry.flags = old_info->entry.flags;
  335         new_info->entry.nlink = old_info->entry.nlink;
  336 }
  337 
  338 /*
  339  * Rename a file (move) in the file system.
  340  */
  341  
  342 static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
  343                             struct inode *new_dir, struct dentry *new_dentry,
  344                             int flags)
  345 {
  346         struct inode *old_inode = old_dentry->d_inode;
  347         struct dentry *old, *new, *old_emd;
  348         int err, ret;
  349         struct umsdos_info old_info;
  350         struct umsdos_info new_info;
  351 
  352         ret = -EPERM;
  353         err = umsdos_parse (old_dentry->d_name.name,
  354                                 old_dentry->d_name.len, &old_info);
  355         if (err)
  356                 goto out;
  357         err = umsdos_parse (new_dentry->d_name.name,
  358                                 new_dentry->d_name.len, &new_info);
  359         if (err)
  360                 goto out;
  361 
  362         /* Get the EMD dentry for the old parent */
  363         old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
  364         ret = PTR_ERR(old_emd);
  365         if (IS_ERR(old_emd))
  366                 goto out;
  367 
  368         umsdos_lockcreate2 (old_dir, new_dir);
  369 
  370         ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
  371         if (ret)
  372                 goto out_unlock;
  373 
  374         err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
  375         if (err == 0) {
  376                 /* check whether it _really_ exists ... */
  377                 ret = -EEXIST;
  378                 if (new_dentry->d_inode)
  379                         goto out_unlock;
  380 
  381                 /* bogus lookup? complain and fix up the EMD ... */
  382                 printk(KERN_WARNING
  383                         "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
  384                         new_dentry->d_parent->d_name.name, new_info.entry.name);
  385                 err = umsdos_delentry(new_dentry->d_parent, &new_info,
  386                                         S_ISDIR(new_info.entry.mode));
  387         }
  388 
  389         umsdos_ren_init (&new_info, &old_info);
  390         if (flags)
  391                 new_info.entry.flags = flags;
  392         ret = umsdos_newentry (new_dentry->d_parent, &new_info);
  393         if (ret)
  394                 goto out_unlock;
  395 
  396         /* If we're moving a hardlink, drop it first */
  397         if (old_info.entry.flags & UMSDOS_HLINK) {
  398                 d_drop(old_dentry);
  399         }
  400 
  401         old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname, 
  402                                         old_info.fake.len);
  403         ret = PTR_ERR(old);
  404         if (IS_ERR(old))
  405                 goto out_unlock;
  406         /* make sure it's the same inode! */
  407         ret = -ENOENT;
  408         /*
  409          * note: for hardlinks they will be different!
  410          *  old_inode will contain inode of .LINKxxx file containing data, and
  411          *  old->d_inode will contain inode of file containing path to .LINKxxx file
  412          */
  413         if (!(old_info.entry.flags & UMSDOS_HLINK)) {
  414                 if (old->d_inode != old_inode)
  415                         goto out_dput;
  416         }
  417 
  418         new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname, 
  419                                         new_info.fake.len);
  420         ret = PTR_ERR(new);
  421         if (IS_ERR(new))
  422                 goto out_dput;
  423 
  424         /* Do the msdos-level rename */
  425         ret = msdos_rename (old_dir, old, new_dir, new);
  426 
  427         dput(new);
  428 
  429         /* If the rename failed, remove the new EMD entry */
  430         if (ret != 0) {
  431                 umsdos_delentry (new_dentry->d_parent, &new_info,
  432                                  S_ISDIR (new_info.entry.mode));
  433                 goto out_dput;
  434         }
  435 
  436         /*
  437          * Rename successful ... remove the old name from the EMD.
  438          * Note that we use the EMD parent here, as the old dentry
  439          * may have moved to a new parent ...
  440          */
  441         err = umsdos_delentry (old_emd->d_parent, &old_info,
  442                                 S_ISDIR (old_info.entry.mode));
  443         if (err) {
  444                 /* Failed? Complain a bit, but don't fail the operation */
  445                 printk(KERN_WARNING 
  446                         "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
  447                         old_emd->d_parent->d_name.name, old_info.entry.name,
  448                         err);
  449         }
  450 
  451         /*
  452          * Update f_pos so notify_change will succeed
  453          * if the file was already in use.
  454          */
  455         umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
  456 
  457         /* dput() the dentry if we haven't already */
  458 out_dput:
  459         dput(old);
  460 
  461 out_unlock:
  462         dput(old_emd);
  463         umsdos_unlockcreate (old_dir);
  464         umsdos_unlockcreate (new_dir);
  465 
  466 out:
  467         Printk ((" _ret=%d\n", ret));
  468         return ret;
  469 }
  470 
  471 /*
  472  * Setup a Symbolic link or a (pseudo) hard link
  473  * Return a negative error code or 0 if OK.
  474  */
  475 /* #Specification: symbolic links / strategy
  476  * A symbolic link is simply a file which holds a path. It is
  477  * implemented as a normal MSDOS file (not very space efficient :-()
  478  * 
  479  * I see two different ways to do this: One is to place the link data
  480  * in unused entries of the EMD file; the other is to have a separate
  481  * file dedicated to hold all symbolic links data.
  482  * 
  483  * Let's go for simplicity...
  484  */
  485 
  486 /*
  487  * AV. Should be called with dir->i_sem down.
  488  */
  489 static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
  490                         const char *symname, int mode, char flags)
  491 {
  492         int ret, len;
  493 
  494         ret = umsdos_create_any (dir, dentry, mode, 0, flags);
  495         if (ret) {
  496                 printk(KERN_WARNING
  497                         "umsdos_symlink: create failed, ret=%d\n", ret);
  498                 goto out;
  499         }
  500 
  501         len = strlen (symname) + 1;
  502         ret = block_symlink(dentry->d_inode, symname, len);
  503         if (ret < 0)
  504                 goto out_unlink;
  505 out:
  506         return ret;
  507 
  508 out_unlink:
  509         printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
  510         UMSDOS_unlink (dir, dentry);
  511         d_drop(dentry);
  512         goto out;
  513 }
  514 
  515 /*
  516  * Setup a Symbolic link.
  517  * Return a negative error code or 0 if OK.
  518  */
  519 int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
  520                  const char *symname)
  521 {
  522         return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
  523 }
  524 
  525 /*
  526  * Add a link to an inode in a directory
  527  */
  528 int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
  529                  struct dentry *dentry)
  530 {
  531         struct inode *oldinode = olddentry->d_inode;
  532         struct inode *olddir = olddentry->d_parent->d_inode;
  533         struct dentry *temp;
  534         char *path;
  535         unsigned long buffer;
  536         int ret;
  537         struct umsdos_info old_info;
  538         struct umsdos_info hid_info;
  539 
  540 #ifdef UMSDOS_DEBUG_VERBOSE
  541 printk("umsdos_link: new %s/%s -> %s/%s\n",
  542 dentry->d_parent->d_name.name, dentry->d_name.name, 
  543 olddentry->d_parent->d_name.name, olddentry->d_name.name);
  544 #endif
  545  
  546         ret = -EPERM;
  547         if (S_ISDIR (oldinode->i_mode))
  548                 goto out;
  549 
  550         ret = umsdos_nevercreat (dir, dentry, -EPERM);
  551         if (ret)
  552                 goto out;
  553 
  554         ret = -ENOMEM;
  555         buffer = get_free_page(GFP_KERNEL);
  556         if (!buffer)
  557                 goto out;
  558 
  559         /*
  560          * Lock the link parent if it's not the same directory.
  561          */
  562         ret = -EDEADLOCK;
  563         if (olddir != dir) {
  564                 if (atomic_read(&olddir->i_sem.count) < 1)
  565                         goto out_free;
  566                 down(&olddir->i_sem);
  567         }
  568 
  569         /*
  570          * Parse the name and get the visible directory entry.
  571          */
  572         ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
  573                                 &old_info);
  574         if (ret)
  575                 goto out_unlock;
  576         ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
  577         if (ret) {
  578 printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
  579 olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
  580                 goto out_unlock;
  581         }
  582 
  583         /*
  584          * If the visible dentry is a pseudo-hardlink, the original
  585          * file must be already hidden.
  586          */
  587         if (!(old_info.entry.flags & UMSDOS_HLINK)) {
  588                 int err;
  589 
  590                 /* create a hidden link name */
  591                 ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
  592                 if (ret) {
  593 printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
  594 olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
  595                         goto out_unlock;
  596                 }
  597 
  598                 /*
  599                  * Make a dentry and rename the original file ...
  600                  */
  601                 temp = umsdos_lookup_dentry(olddentry->d_parent,
  602                                                 hid_info.entry.name,
  603                                                 hid_info.entry.name_len, 0); 
  604                 ret = PTR_ERR(temp);
  605                 if (IS_ERR(temp)) {
  606 printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
  607 dentry->d_parent->d_name.name, hid_info.entry.name, ret);
  608                         goto cleanup;
  609                 }
  610                 /* rename the link to the hidden location ... */
  611                 ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
  612                                         UMSDOS_HIDDEN);
  613                 d_move(olddentry, temp);
  614                 dput(temp);
  615                 if (ret) {
  616 printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
  617 temp->d_parent->d_name.name, temp->d_name.name, ret);
  618                         goto cleanup;
  619                 }
  620                 /*
  621                  * Capture the path to the hidden link.
  622                  */
  623                 path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
  624                 if (IS_ERR(path)) {
  625                         ret = PTR_ERR(path);
  626                         goto cleanup;
  627                 }
  628 Printk(("umsdos_link: hidden link path=%s\n", path));
  629 
  630                 /* mark the inode as a hardlink */
  631                 oldinode->u.umsdos_i.i_is_hlink = 1;
  632 
  633                 /*
  634                  * Recreate a dentry for the original name and symlink it,
  635                  * then symlink the new dentry. Don't give up if one fails,
  636                  * or we'll lose the file completely!
  637                  *
  638                  * Note: this counts as the "original" reference, so we 
  639                  * don't increment i_nlink for this one.
  640                  */ 
  641                 temp = umsdos_lookup_dentry(olddentry->d_parent,
  642                                                 old_info.entry.name,
  643                                                 old_info.entry.name_len, 0); 
  644                 ret = PTR_ERR(temp);
  645                 if (!IS_ERR(temp)) {
  646                         ret = umsdos_symlink_x (olddir, temp, path, 
  647                                                 S_IFREG | 0777, UMSDOS_HLINK);
  648                         dput(temp);
  649                 }
  650 
  651                 /* This symlink increments i_nlink (see below.) */
  652                 err = umsdos_symlink_x (dir, dentry, path,
  653                                         S_IFREG | 0777, UMSDOS_HLINK);
  654                 /* fold the two errors */
  655                 if (!ret)
  656                         ret = err;
  657                 goto out_unlock;
  658 
  659                 /* creation failed ... remove the link entry */
  660         cleanup:
  661 printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
  662 ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
  663                 err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
  664                 goto out_unlock;
  665         }
  666 
  667 Printk(("UMSDOS_link: %s/%s already hidden\n",
  668 olddentry->d_parent->d_name.name, olddentry->d_name.name));
  669         /*
  670          * The original file is already hidden, and we need to get 
  671          * the dentry for its real name, not the visible name.
  672          * N.B. make sure it's the hidden inode ...
  673          */
  674         if (!oldinode->u.umsdos_i.i_is_hlink)
  675                 printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
  676                         olddentry->d_parent->d_name.name,
  677                         olddentry->d_name.name, oldinode->i_ino);
  678 
  679         /*
  680          * In order to get the correct (real) inode, we just drop
  681          * the original dentry.
  682          */ 
  683         d_drop(olddentry);
  684 Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
  685 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
  686 
  687         /* Do a real lookup to get the short name dentry */
  688         temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
  689                                         old_info.fake.len);
  690         ret = PTR_ERR(temp);
  691         if (IS_ERR(temp))
  692                 goto out_unlock;
  693 
  694         /* now resolve the link ... */
  695         temp = umsdos_solve_hlink(temp);
  696         ret = PTR_ERR(temp);
  697         if (IS_ERR(temp))
  698                 goto out_unlock;
  699         path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
  700         dput(temp);
  701         if (IS_ERR(path))
  702                 goto out_unlock;
  703 Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
  704 olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
  705 
  706         /* finally we can symlink it ... */
  707         ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
  708 
  709 out_unlock:
  710         /* remain locked for the call to notify_change ... */
  711         if (ret == 0) {
  712                 struct iattr newattrs;
  713 
  714                 /* Do a real lookup to get the short name dentry */
  715                 temp = umsdos_covered(olddentry->d_parent,
  716                                         old_info.fake.fname,
  717                                         old_info.fake.len);
  718                 ret = PTR_ERR(temp);
  719                 if (IS_ERR(temp))
  720                         goto out_unlock2;
  721 
  722                 /* now resolve the link ... */
  723                 temp = umsdos_solve_hlink(temp);
  724                 ret = PTR_ERR(temp);
  725                 if (IS_ERR(temp))
  726                         goto out_unlock2;
  727 
  728 
  729 #ifdef UMSDOS_PARANOIA
  730 if (!oldinode->u.umsdos_i.i_is_hlink)
  731 printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
  732 olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
  733 #endif
  734                 temp->d_inode->i_nlink++;
  735 Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
  736 olddentry->d_parent->d_name.name, olddentry->d_name.name,
  737 oldinode->i_ino, oldinode->i_nlink));
  738                 newattrs.ia_valid = 0;
  739                 ret = umsdos_notify_change_locked(temp, &newattrs);
  740                 if (ret == 0)
  741                         mark_inode_dirty(temp->d_inode);
  742                 dput(temp);
  743 out_unlock2:    
  744                 if (ret == 0)
  745                         mark_inode_dirty(olddentry->d_inode);
  746         }
  747         if (olddir != dir)
  748                 up(&olddir->i_sem);
  749 
  750 out_free:
  751         free_page(buffer);
  752 out:
  753         Printk (("umsdos_link %d\n", ret));
  754         return ret;
  755 }
  756 
  757 
  758 /*
  759  * Add a sub-directory in a directory
  760  */
  761 /* #Specification: mkdir / Directory already exist in DOS
  762  * We do the same thing as for file creation.
  763  * For all user it is an error.
  764  */
  765 /* #Specification: mkdir / umsdos directory / create EMD
  766  * When we created a new sub-directory in a UMSDOS
  767  * directory (one with full UMSDOS semantics), we
  768  * create immediately an EMD file in the new
  769  * sub-directory so it inherits UMSDOS semantics.
  770  */
  771 int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
  772 {
  773         struct dentry *temp;
  774         struct inode *inode;
  775         int ret, err;
  776         struct umsdos_info info;
  777 
  778         ret = umsdos_nevercreat (dir, dentry, -EEXIST);
  779         if (ret)
  780                 goto out;
  781 
  782         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  783         if (ret)
  784                 goto out;
  785 
  786         info.entry.mode = mode | S_IFDIR;
  787         info.entry.rdev = 0;
  788         info.entry.uid = current->fsuid;
  789         info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
  790         info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
  791         info.entry.flags = 0;
  792         info.entry.nlink = 1;
  793         ret = umsdos_newentry (dentry->d_parent, &info);
  794         if (ret)
  795                 goto out;
  796 
  797         /* lookup the short name dentry */
  798         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  799         ret = PTR_ERR(temp);
  800         if (IS_ERR(temp))
  801                 goto out_remove;
  802 
  803         /* Make sure the short name doesn't exist */
  804         ret = -EEXIST;
  805         if (temp->d_inode) {
  806 printk("umsdos_mkdir: short name %s/%s exists\n",
  807 dentry->d_parent->d_name.name, info.fake.fname);
  808                 goto out_remove_dput;
  809         }
  810 
  811         ret = msdos_mkdir (dir, temp, mode);
  812         if (ret)
  813                 goto out_remove_dput;
  814 
  815         /*
  816          * Lock the inode to protect the EMD creation ...
  817          */
  818         inode = temp->d_inode;
  819         down(&inode->i_sem);
  820 
  821         atomic_inc(&inode->i_count);
  822         d_instantiate(dentry, inode);
  823 
  824         /* N.B. this should have an option to create the EMD ... */
  825         umsdos_lookup_patch_new(dentry, &info);
  826 
  827         /* 
  828          * Create the EMD file, and set up the dir so it is
  829          * promoted to EMD with the EMD file invisible.
  830          *
  831          * N.B. error return if EMD fails?
  832          */
  833         err = umsdos_make_emd(dentry);
  834         umsdos_setup_dir(dentry);
  835 
  836         up(&inode->i_sem);
  837         dput(temp);
  838 
  839 out:
  840         Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
  841                 dentry->d_parent->d_name.name, dentry->d_name.name, ret));
  842         return ret;
  843 
  844         /* an error occurred ... remove EMD entry. */
  845 out_remove_dput:
  846         dput(temp);
  847 out_remove:
  848         umsdos_delentry (dentry->d_parent, &info, 1);
  849         goto out;
  850 }
  851 
  852 /*
  853  * Add a new device special file into a directory.
  854  *
  855  * #Specification: Special files / strategy
  856  * Device special file, pipes, etc ... are created like normal
  857  * file in the msdos file system. Of course they remain empty.
  858  * 
  859  * One strategy was to create those files only in the EMD file
  860  * since they were not important for MSDOS. The problem with
  861  * that, is that there were not getting inode number allocated.
  862  * The MSDOS filesystems is playing a nice game to fake inode
  863  * number, so why not use it.
  864  * 
  865  * The absence of inode number compatible with those allocated
  866  * for ordinary files was causing major trouble with hard link
  867  * in particular and other parts of the kernel I guess.
  868  */
  869 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
  870                  int mode, int rdev)
  871 {
  872         return umsdos_create_any (dir, dentry, mode, rdev, 0);
  873 }
  874 
  875 /*
  876  * Remove a sub-directory.
  877  */
  878 int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
  879 {
  880         struct dentry *temp;
  881         int ret, err, empty;
  882         struct umsdos_info info;
  883 
  884         ret = umsdos_nevercreat (dir, dentry, -EPERM);
  885         if (ret)
  886                 goto out;
  887 
  888         ret = -EBUSY;
  889         if (!d_unhashed(dentry))
  890                 goto out;
  891 
  892         /* check whether the EMD is empty */
  893         ret = -ENOTEMPTY;
  894         empty = umsdos_isempty (dentry);
  895 
  896         /* Have to remove the EMD file? */
  897         if (empty == 1) {
  898                 struct dentry *demd;
  899 
  900                 demd = umsdos_get_emd_dentry(dentry);
  901                 if (!IS_ERR(demd)) {
  902                         err = -ENOENT;
  903                         if (demd->d_inode)
  904                                 err = msdos_unlink (dentry->d_inode, demd);
  905 Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
  906 #ifdef UMSDOS_PARANOIA
  907 if (err)
  908 printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
  909 demd->d_parent->d_name.name, demd->d_name.name, err);
  910 #endif
  911                         if (!err) {
  912                                 d_delete(demd);
  913                                 ret = 0;
  914                         }
  915                         dput(demd);
  916                 }
  917         } else if (empty == 2)
  918                 ret = 0;
  919         if (ret)
  920                 goto out;
  921 
  922         umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  923         /* Call findentry to complete the mangling */
  924         umsdos_findentry (dentry->d_parent, &info, 2);
  925         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
  926         ret = PTR_ERR(temp);
  927         if (IS_ERR(temp))
  928                 goto out;
  929         /*
  930          * Attempt to remove the msdos name.
  931          */
  932         ret = msdos_rmdir (dir, temp);
  933         if (ret && ret != -ENOENT)
  934                 goto out_dput;
  935 
  936         d_delete(temp);
  937         /* OK so far ... remove the name from the EMD */
  938         ret = umsdos_delentry (dentry->d_parent, &info, 1);
  939 #ifdef UMSDOS_PARANOIA
  940 if (ret)
  941 printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
  942 #endif
  943 
  944         /* dput() temp if we didn't do it above */
  945 out_dput:
  946         dput(temp);
  947 
  948 out:
  949         Printk (("umsdos_rmdir %d\n", ret));
  950         return ret;
  951 }
  952 
  953 
  954 /*
  955  * Remove a file from the directory.
  956  *
  957  * #Specification: hard link / deleting a link
  958  * When we delete a file and this file is a link,
  959  * we must subtract 1 from the nlink field of the
  960  * hidden link.
  961  * 
  962  * If the count goes to 0, we delete this hidden
  963  * link too.
  964  */
  965 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
  966 {
  967         struct dentry *temp, *link = NULL;
  968         struct inode *inode;
  969         int ret;
  970         struct umsdos_info info;
  971 
  972 Printk(("UMSDOS_unlink: entering %s/%s\n",
  973 dentry->d_parent->d_name.name, dentry->d_name.name));
  974 
  975         ret = umsdos_nevercreat (dir, dentry, -EPERM);
  976         if (ret)
  977                 goto out;
  978 
  979         ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
  980         if (ret)
  981                 goto out;
  982 
  983         umsdos_lockcreate (dir);
  984         ret = umsdos_findentry (dentry->d_parent, &info, 1);
  985         if (ret) {
  986 printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
  987 dentry->d_parent->d_name.name, dentry->d_name.name, ret);
  988                 goto out_unlock;
  989         }
  990 
  991 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
  992 
  993         /*
  994          * Note! If this is a hardlink and the names are aliased,
  995          * the short-name lookup will return the hardlink dentry.
  996          * In order to get the correct (real) inode, we just drop
  997          * the original dentry.
  998          */ 
  999         if (info.entry.flags & UMSDOS_HLINK) {
 1000                 d_drop(dentry);
 1001         }
 1002 
 1003         /* Do a real lookup to get the short name dentry */
 1004         temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
 1005         ret = PTR_ERR(temp);
 1006         if (IS_ERR(temp))
 1007                 goto out_unlock;
 1008 
 1009         /*
 1010          * Resolve hardlinks now, but defer processing until later.
 1011          */
 1012         if (info.entry.flags & UMSDOS_HLINK) {
 1013                 link = umsdos_solve_hlink(dget(temp));
 1014         }
 1015 
 1016         /* Delete the EMD entry */
 1017         ret = umsdos_delentry (dentry->d_parent, &info, 0);
 1018         if (ret && ret != -ENOENT) {
 1019                 printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
 1020                         info.entry.name, ret);
 1021                 goto out_dput;
 1022         }
 1023 
 1024         ret = msdos_unlink(dir, temp);
 1025         if (!ret)
 1026                 d_delete(temp);
 1027 #ifdef UMSDOS_PARANOIA
 1028 if (ret)
 1029 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
 1030 temp->d_parent->d_name.name, temp->d_name.name, ret);
 1031 #endif
 1032 
 1033         /* dput() temp if we didn't do it above */
 1034 out_dput:
 1035         dput(temp);
 1036 
 1037 out_unlock:
 1038         umsdos_unlockcreate (dir);
 1039 
 1040         /*
 1041          * Now check for deferred handling of a hardlink.
 1042          */
 1043         if (!link)
 1044                 goto out;
 1045 
 1046         if (IS_ERR(link)) {
 1047 printk("umsdos_unlink: failed to resolve %s/%s\n",
 1048 dentry->d_parent->d_name.name, dentry->d_name.name);
 1049                 if (!ret)
 1050                         ret = PTR_ERR(link);
 1051                 goto out;
 1052         }
 1053 
 1054 Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
 1055 link->d_parent->d_name.name, link->d_name.name, ret));
 1056 
 1057         /* already have an error? */
 1058         if (ret)
 1059                 goto out_cleanup;
 1060 
 1061         /* make sure the link exists ... */
 1062         inode = link->d_inode;
 1063         if (!inode) {
 1064                 printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
 1065                 goto out_cleanup;
 1066         }
 1067 
 1068         /*
 1069          * If this was the last linked reference, delete it now.
 1070          *
 1071          * N.B. Deadlock problem? We should be holding the lock
 1072          * for the hardlink's parent, but another process might
 1073          * be holding that lock waiting for us to finish ...
 1074          */
 1075         if (inode->i_nlink <= 1) {
 1076                 ret = UMSDOS_unlink (link->d_parent->d_inode, link);
 1077                 if (ret) {
 1078                         printk(KERN_WARNING
 1079                                 "umsdos_unlink: link removal failed, ret=%d\n",
 1080                                  ret);
 1081                 } else
 1082                         d_delete(link);
 1083         } else {
 1084                 struct iattr newattrs;
 1085                 inode->i_nlink--;
 1086                 newattrs.ia_valid = 0;
 1087                 ret = umsdos_notify_change_locked(link, &newattrs);
 1088                 if (!ret)
 1089                         mark_inode_dirty(link->d_inode);
 1090         }
 1091 
 1092 out_cleanup:
 1093         d_drop(link);
 1094         dput(link);
 1095 
 1096 out:
 1097         Printk (("umsdos_unlink %d\n", ret));
 1098         return ret;
 1099 }
 1100 
 1101 /*
 1102  * Rename (move) a file.
 1103  */
 1104 int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
 1105                    struct inode *new_dir, struct dentry *new_dentry)
 1106 {
 1107         int ret;
 1108 
 1109         ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
 1110         if (ret)
 1111                 return ret;
 1112 
 1113                 /*
 1114                  * If the target already exists, delete it first.
 1115                  */
 1116         if (new_dentry->d_inode) {
 1117                 dget(new_dentry);
 1118                 if (S_ISDIR(old_dentry->d_inode->i_mode))
 1119                         ret = UMSDOS_rmdir (new_dir, new_dentry);
 1120                 else
 1121                         ret = UMSDOS_unlink (new_dir, new_dentry);
 1122                 if (!ret)
 1123                         d_drop(new_dentry);
 1124                 dput(new_dentry);
 1125                 if (ret)
 1126                         return ret;
 1127         }
 1128         ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
 1129         return ret;
 1130 }

Cache object: 0319345dc269f214b684daac7da63bad


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.