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/rdir.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/rdir.c
    3  *
    4  *  Written 1994 by Jacques Gelinas
    5  *
    6  *  Extended MS-DOS directory pure MS-DOS handling functions
    7  *  (For directory without EMD file).
    8  */
    9 
   10 #include <linux/sched.h>
   11 #include <linux/fs.h>
   12 #include <linux/msdos_fs.h>
   13 #include <linux/errno.h>
   14 #include <linux/stat.h>
   15 #include <linux/limits.h>
   16 #include <linux/umsdos_fs.h>
   17 #include <linux/slab.h>
   18 
   19 #include <asm/uaccess.h>
   20 
   21 
   22 extern struct dentry *saved_root;
   23 extern struct inode *pseudo_root;
   24 extern struct dentry_operations umsdos_dentry_operations;
   25 
   26 struct RDIR_FILLDIR {
   27         void *dirbuf;
   28         filldir_t filldir;
   29         int real_root;
   30 };
   31 
   32 static int rdir_filldir (       void *buf,
   33                                 const char *name,
   34                                 int name_len,
   35                                 loff_t offset,
   36                                 ino_t ino,
   37                                 unsigned int d_type)
   38 {
   39         int ret = 0;
   40         struct RDIR_FILLDIR *d = (struct RDIR_FILLDIR *) buf;
   41 
   42         if (d->real_root) {
   43                 PRINTK ((KERN_DEBUG "rdir_filldir /mn/: real root!\n"));
   44                 /* real root of a pseudo_rooted partition */
   45                 if (name_len != UMSDOS_PSDROOT_LEN
   46                     || memcmp (name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) != 0) {
   47                         /* So it is not the /linux directory */
   48                         if (name_len == 2 && name[0] == '.' && name[1] == '.') {
   49                                 /* Make sure the .. entry points back to the pseudo_root */
   50                                 ino = pseudo_root->i_ino;
   51                         }
   52                         ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN);
   53                 }
   54         } else {
   55                 /* Any DOS directory */
   56                 ret = d->filldir (d->dirbuf, name, name_len, offset, ino, DT_UNKNOWN);
   57         }
   58         return ret;
   59 }
   60 
   61 
   62 static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
   63 {
   64         struct inode *dir = filp->f_dentry->d_inode;
   65         struct RDIR_FILLDIR bufk;
   66 
   67         bufk.filldir = filldir;
   68         bufk.dirbuf = dirbuf;
   69         bufk.real_root = pseudo_root && (dir == saved_root->d_inode);
   70         return fat_readdir (filp, &bufk, rdir_filldir);
   71 }
   72 
   73 
   74 /*
   75  * Lookup into a non promoted directory.
   76  * If the result is a directory, make sure we find out if it is
   77  * a promoted one or not (calling umsdos_setup_dir_inode(inode)).
   78  */
   79 /* #Specification: pseudo root / DOS/..
   80  * In the real root directory (c:\), the directory ..
   81  * is the pseudo root (c:\linux).
   82  */
   83 struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
   84 {
   85         struct dentry *ret;
   86 
   87         if (saved_root && dir == saved_root->d_inode && !nopseudo &&
   88             dentry->d_name.len == UMSDOS_PSDROOT_LEN &&
   89             memcmp (dentry->d_name.name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN) == 0) {
   90                 /* #Specification: pseudo root / DOS/linux
   91                  * Even in the real root directory (c:\), the directory
   92                  * /linux won't show
   93                  */
   94                  
   95                 ret = ERR_PTR(-ENOENT);
   96                 goto out;
   97         }
   98 
   99         ret = msdos_lookup (dir, dentry);
  100         if (ret) {
  101                 printk(KERN_WARNING
  102                         "umsdos_rlookup_x: %s/%s failed, ret=%ld\n",
  103                         dentry->d_parent->d_name.name, dentry->d_name.name,
  104                         PTR_ERR(ret));
  105                 goto out;
  106         }
  107         if (dentry->d_inode) {
  108                 /* We must install the proper function table
  109                  * depending on whether this is an MS-DOS or 
  110                  * a UMSDOS directory
  111                  */
  112 Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n",
  113 dentry->d_parent->d_name.name, dentry->d_name.name));
  114 /* only patch if needed (because we get called even for lookup
  115    (not only rlookup) stuff sometimes, like in umsdos_covered() */
  116                 if (dentry->d_inode->u.umsdos_i.i_patched == 0) 
  117                 umsdos_patch_dentry_inode(dentry, 0);
  118 
  119         }
  120 out:
  121         /* always install our dentry ops ... */
  122         dentry->d_op = &umsdos_dentry_operations;
  123         return ret;
  124 }
  125 
  126 
  127 struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
  128 {
  129         return umsdos_rlookup_x (dir, dentry, 0);
  130 }
  131 
  132 
  133 /* #Specification: dual mode / rmdir in a DOS directory
  134  * In a DOS (not EMD in it) directory, we use a reverse strategy
  135  * compared with a UMSDOS directory. We assume that a subdirectory
  136  * of a DOS directory is also a DOS directory. This is not always
  137  * true (umssync may be used anywhere), but makes sense.
  138  * 
  139  * So we call msdos_rmdir() directly. If it failed with a -ENOTEMPTY
  140  * then we check if it is a Umsdos directory. We check if it is
  141  * really empty (only . .. and --linux-.--- in it). If it is true
  142  * we remove the EMD and do a msdos_rmdir() again.
  143  * 
  144  * In a Umsdos directory, we assume all subdirectories are also
  145  * Umsdos directories, so we check the EMD file first.
  146  */
  147 /* #Specification: pseudo root / rmdir /DOS
  148  * The pseudo sub-directory /DOS can't be removed!
  149  * This is done even if the pseudo root is not a Umsdos
  150  * directory anymore (very unlikely), but an accident (under
  151  * MS-DOS) is always possible.
  152  * 
  153  * EPERM is returned.
  154  */
  155 static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
  156 {
  157         int ret, empty;
  158 
  159         ret = -EPERM;
  160         if (umsdos_is_pseudodos (dir, dentry))
  161                 goto out;
  162 
  163         ret = -EBUSY;
  164         if (!d_unhashed(dentry))
  165                 goto out;
  166 
  167         ret = msdos_rmdir (dir, dentry);
  168         if (ret != -ENOTEMPTY)
  169                 goto out;
  170 
  171         empty = umsdos_isempty (dentry);
  172         if (empty == 1) {
  173                 struct dentry *demd;
  174                 /* We have to remove the EMD file. */
  175                 demd = umsdos_get_emd_dentry(dentry);
  176                 ret = PTR_ERR(demd);
  177                 if (!IS_ERR(demd)) {
  178                         ret = 0;
  179                         if (demd->d_inode)
  180                                 ret = msdos_unlink (dentry->d_inode, demd);
  181                         if (!ret)
  182                                 d_delete(demd);
  183                         dput(demd);
  184                 }
  185         }
  186         if (ret)
  187                 goto out;
  188 
  189         /* now retry the original ... */
  190         ret = msdos_rmdir (dir, dentry);
  191 
  192 out:
  193         return ret;
  194 }
  195 
  196 /* #Specification: dual mode / introduction
  197  * One goal of UMSDOS is to allow a practical and simple coexistence
  198  * between MS-DOS and Linux in a single partition. Using the EMD file
  199  * in each directory, UMSDOS adds Unix semantics and capabilities to
  200  * a normal DOS filesystem. To help and simplify coexistence, here is
  201  * the logic related to the EMD file.
  202  * 
  203  * If it is missing, then the directory is managed by the MS-DOS driver.
  204  * The names are limited to DOS limits (8.3). No links, no device special
  205  * and pipe and so on.
  206  * 
  207  * If it is there, it is the directory. If it is there but empty, then
  208  * the directory looks empty. The utility umssync allows synchronisation
  209  * of the real DOS directory and the EMD.
  210  * 
  211  * Whenever umssync is applied to a directory without EMD, one is
  212  * created on the fly.  The directory is promoted to full Unix semantics.
  213  * Of course, the ls command will show exactly the same content as before
  214  * the umssync session.
  215  * 
  216  * It is believed that the user/admin will promote directories to Unix
  217  * semantics as needed.
  218  * 
  219  * The strategy to implement this is to use two function table (struct
  220  * inode_operations). One for true UMSDOS directory and one for directory
  221  * with missing EMD.
  222  * 
  223  * Functions related to the DOS semantic (but aware of UMSDOS) generally
  224  * have a "r" prefix (r for real) such as UMSDOS_rlookup, to differentiate
  225  * from the one with full UMSDOS semantics.
  226  */
  227 struct file_operations umsdos_rdir_operations =
  228 {
  229         read:           generic_read_dir,
  230         readdir:        UMSDOS_rreaddir,
  231         ioctl:          UMSDOS_ioctl_dir,
  232 };
  233 
  234 struct inode_operations umsdos_rdir_inode_operations =
  235 {
  236         create:         msdos_create,
  237         lookup:         UMSDOS_rlookup,
  238         unlink:         msdos_unlink,
  239         mkdir:          msdos_mkdir,
  240         rmdir:          UMSDOS_rrmdir,
  241         rename:         msdos_rename,
  242         setattr:        UMSDOS_notify_change,
  243 };

Cache object: 948ae74c43a9f6e4da4f0aa89b540d1d


[ 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.