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/hfs/dir_dbl.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/hfs/dir_dbl.c
    3  *
    4  * Copyright (C) 1995-1997  Paul H. Hargrove
    5  * This file may be distributed under the terms of the GNU General Public License.
    6  *
    7  * This file contains the inode_operations and file_operations
    8  * structures for HFS directories.
    9  *
   10  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
   11  *
   12  * "XXX" in a comment is a note to myself to consider changing something.
   13  *
   14  * In function preconditions the term "valid" applied to a pointer to
   15  * a structure means that the pointer is non-NULL and the structure it
   16  * points to has all fields initialized to consistent values.
   17  */
   18 
   19 #include "hfs.h"
   20 #include <linux/hfs_fs_sb.h>
   21 #include <linux/hfs_fs_i.h>
   22 #include <linux/hfs_fs.h>
   23 
   24 /*================ Forward declarations ================*/
   25 
   26 static struct dentry *dbl_lookup(struct inode *, struct dentry *);
   27 static int dbl_readdir(struct file *, void *, filldir_t);
   28 static int dbl_create(struct inode *, struct dentry *, int);
   29 static int dbl_mkdir(struct inode *, struct dentry *, int);
   30 static int dbl_unlink(struct inode *, struct dentry *);
   31 static int dbl_rmdir(struct inode *, struct dentry *);
   32 static int dbl_rename(struct inode *, struct dentry *,
   33                       struct inode *, struct dentry *);
   34 
   35 /*================ Global variables ================*/
   36 
   37 #define DOT_LEN                 1
   38 #define DOT_DOT_LEN             2
   39 #define ROOTINFO_LEN            8
   40 #define PCNT_ROOTINFO_LEN       9
   41 
   42 const struct hfs_name hfs_dbl_reserved1[] = {
   43         {DOT_LEN,               "."},
   44         {DOT_DOT_LEN,           ".."},
   45         {0,                     ""},
   46 };
   47 
   48 const struct hfs_name hfs_dbl_reserved2[] = {
   49         {ROOTINFO_LEN,          "RootInfo"},
   50         {PCNT_ROOTINFO_LEN,     "%RootInfo"},
   51         {0,                     ""},
   52 };
   53 
   54 #define DOT             (&hfs_dbl_reserved1[0])
   55 #define DOT_DOT         (&hfs_dbl_reserved1[1])
   56 #define ROOTINFO        (&hfs_dbl_reserved2[0])
   57 #define PCNT_ROOTINFO   (&hfs_dbl_reserved2[1])
   58 
   59 struct file_operations hfs_dbl_dir_operations = {
   60         read:           generic_read_dir,
   61         readdir:        dbl_readdir,
   62         fsync:          file_fsync,
   63 };
   64 
   65 struct inode_operations hfs_dbl_dir_inode_operations = {
   66         create:         dbl_create,
   67         lookup:         dbl_lookup,
   68         unlink:         dbl_unlink,
   69         mkdir:          dbl_mkdir,
   70         rmdir:          dbl_rmdir,
   71         rename:         dbl_rename,
   72         setattr:        hfs_notify_change,
   73 };
   74 
   75 
   76 /*================ File-local functions ================*/
   77 
   78 /*
   79  * is_hdr()
   80  */
   81 static int is_hdr(struct inode *dir, const char *name, int len)
   82 {
   83         int retval = 0;
   84 
   85         if (name[0] == '%') {
   86                 struct hfs_cat_entry *entry = HFS_I(dir)->entry;
   87                 struct hfs_cat_entry *victim;
   88                 struct hfs_name cname;
   89                 struct hfs_cat_key key;
   90 
   91                 hfs_nameout(dir, &cname, name+1, len-1);
   92                 hfs_cat_build_key(entry->cnid, &cname, &key);
   93                 if ((victim = hfs_cat_get(entry->mdb, &key))) {
   94                         hfs_cat_put(victim);
   95                         retval = 1;
   96                 }
   97         }
   98         return retval;
   99 }
  100 
  101 /*
  102  * dbl_lookup()
  103  *
  104  * This is the lookup() entry in the inode_operations structure for
  105  * HFS directories in the AppleDouble scheme.  The purpose is to
  106  * generate the inode corresponding to an entry in a directory, given
  107  * the inode for the directory and the name (and its length) of the
  108  * entry.
  109  */
  110 static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry)
  111 {
  112         struct hfs_name cname;
  113         struct hfs_cat_entry *entry;
  114         struct hfs_cat_key key;
  115         struct inode *inode = NULL;
  116 
  117         dentry->d_op = &hfs_dentry_operations;
  118         entry = HFS_I(dir)->entry;
  119         
  120         /* Perform name-mangling */
  121         hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len);
  122  
  123         /* no need to check for "."  or ".." */
  124 
  125         /* Check for "%RootInfo" if in the root directory. */
  126         if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
  127             hfs_streq(cname.Name, cname.Len, 
  128                       PCNT_ROOTINFO->Name, PCNT_ROOTINFO_LEN)) {
  129                 ++entry->count; /* __hfs_iget() eats one */
  130                 inode = hfs_iget(entry, HFS_DBL_HDR, dentry);
  131                 goto done;
  132         }
  133 
  134         /* Do an hfs_iget() on the mangled name. */
  135         hfs_cat_build_key(entry->cnid, &cname, &key);
  136         inode = hfs_iget(hfs_cat_get(entry->mdb, &key), HFS_DBL_NORM, dentry);
  137 
  138         /* Try as a header if not found and first character is '%' */
  139         if (!inode && (dentry->d_name.name[0] == '%')) {
  140                 hfs_nameout(dir, &cname, dentry->d_name.name+1,
  141                             dentry->d_name.len-1);
  142                 hfs_cat_build_key(entry->cnid, &cname, &key);
  143                 inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
  144                                  HFS_DBL_HDR, dentry);
  145         }
  146         
  147 done:
  148         d_add(dentry, inode);
  149         return NULL;
  150 }
  151 
  152 /*
  153  * dbl_readdir()
  154  *
  155  * This is the readdir() entry in the file_operations structure for
  156  * HFS directories in the AppleDouble scheme.  The purpose is to
  157  * enumerate the entries in a directory, given the inode of the
  158  * directory and a (struct file *), the 'f_pos' field of which
  159  * indicates the location in the directory.  The (struct file *) is
  160  * updated so that the next call with the same 'dir' and 'filp'
  161  * arguments will produce the next directory entry.  The entries are
  162  * returned in 'dirent', which is "filled-in" by calling filldir().
  163  * This allows the same readdir() function be used for different
  164  * formats.  We try to read in as many entries as we can before
  165  * filldir() refuses to take any more.
  166  *
  167  * XXX: In the future it may be a good idea to consider not generating
  168  * metadata files for covered directories since the data doesn't
  169  * correspond to the mounted directory.  However this requires an
  170  * iget() for every directory which could be considered an excessive
  171  * amount of overhead.  Since the inode for a mount point is always
  172  * in-core this is another argument for a call to get an inode if it
  173  * is in-core or NULL if it is not.
  174  */
  175 static int dbl_readdir(struct file * filp,
  176                        void * dirent, filldir_t filldir)
  177 {
  178         struct hfs_brec brec;
  179         struct hfs_cat_entry *entry;
  180         struct inode *dir = filp->f_dentry->d_inode;
  181 
  182         entry = HFS_I(dir)->entry;
  183 
  184         if (filp->f_pos == 0) {
  185                 /* Entry 0 is for "." */
  186                 if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino,
  187                             DT_DIR)) {
  188                         return 0;
  189                 }
  190                 filp->f_pos = 1;
  191         }
  192 
  193         if (filp->f_pos == 1) {
  194                 /* Entry 1 is for ".." */
  195                 if (filldir(dirent, DOT_DOT->Name, DOT_DOT_LEN, 1,
  196                             hfs_get_hl(entry->key.ParID), DT_DIR)) {
  197                         return 0;
  198                 }
  199                 filp->f_pos = 2;
  200         }
  201 
  202         if (filp->f_pos < (dir->i_size - 1)) {
  203                 hfs_u32 cnid;
  204                 hfs_u8 type;
  205 
  206                 if (hfs_cat_open(entry, &brec) ||
  207                     hfs_cat_next(entry, &brec, (filp->f_pos - 1) >> 1,
  208                                  &cnid, &type)) {
  209                         return 0;
  210                 }
  211 
  212                 while (filp->f_pos < (dir->i_size - 1)) {
  213                         unsigned char tmp_name[HFS_NAMEMAX + 1];
  214                         ino_t ino;
  215                         int is_hdr = (filp->f_pos & 1);
  216                         unsigned int len;
  217 
  218                         if (is_hdr) {
  219                                 ino = ntohl(cnid) | HFS_DBL_HDR;
  220                                 tmp_name[0] = '%';
  221                                 len = 1 + hfs_namein(dir, tmp_name + 1,
  222                                     &((struct hfs_cat_key *)brec.key)->CName);
  223                         } else {
  224                                 if (hfs_cat_next(entry, &brec, 1,
  225                                                         &cnid, &type)) {
  226                                         return 0;
  227                                 }
  228                                 ino = ntohl(cnid);
  229                                 len = hfs_namein(dir, tmp_name,
  230                                     &((struct hfs_cat_key *)brec.key)->CName);
  231                         }
  232 
  233                         if (filldir(dirent, tmp_name, len, filp->f_pos, ino,
  234                                     DT_UNKNOWN)) {
  235                                 hfs_cat_close(entry, &brec);
  236                                 return 0;
  237                         }
  238                         ++filp->f_pos;
  239                 }
  240                 hfs_cat_close(entry, &brec);
  241         }
  242 
  243         if (filp->f_pos == (dir->i_size - 1)) {
  244                 if (entry->cnid == htonl(HFS_ROOT_CNID)) {
  245                         /* In root dir last entry is for "%RootInfo" */
  246                         if (filldir(dirent, PCNT_ROOTINFO->Name,
  247                                     PCNT_ROOTINFO_LEN, filp->f_pos,
  248                                     ntohl(entry->cnid) | HFS_DBL_HDR,
  249                                     DT_UNKNOWN)) {
  250                                 return 0;
  251                         }
  252                 }
  253                 ++filp->f_pos;
  254         }
  255 
  256         return 0;
  257 }
  258 
  259 /*
  260  * dbl_create()
  261  *
  262  * This is the create() entry in the inode_operations structure for
  263  * AppleDouble directories.  The purpose is to create a new file in
  264  * a directory and return a corresponding inode, given the inode for
  265  * the directory and the name (and its length) of the new file.
  266  */
  267 static int dbl_create(struct inode * dir, struct dentry *dentry,
  268                       int mode)
  269 {
  270         int error;
  271 
  272         if (is_hdr(dir, dentry->d_name.name, dentry->d_name.len)) {
  273                 error = -EEXIST;
  274         } else {
  275                 error = hfs_create(dir, dentry, mode);
  276         }
  277         return error;
  278 }
  279 
  280 /*
  281  * dbl_mkdir()
  282  *
  283  * This is the mkdir() entry in the inode_operations structure for
  284  * AppleDouble directories.  The purpose is to create a new directory
  285  * in a directory, given the inode for the parent directory and the
  286  * name (and its length) of the new directory.
  287  */
  288 static int dbl_mkdir(struct inode * parent, struct dentry *dentry,
  289                      int mode)
  290 {
  291         int error;
  292 
  293         if (is_hdr(parent, dentry->d_name.name, dentry->d_name.len)) {
  294                 error = -EEXIST;
  295         } else {
  296                 error = hfs_mkdir(parent, dentry, mode);
  297         }
  298         return error;
  299 }
  300 
  301 /*
  302  * dbl_unlink()
  303  *
  304  * This is the unlink() entry in the inode_operations structure for
  305  * AppleDouble directories.  The purpose is to delete an existing
  306  * file, given the inode for the parent directory and the name
  307  * (and its length) of the existing file.
  308  */
  309 static int dbl_unlink(struct inode * dir, struct dentry *dentry)
  310 {
  311         int error;
  312 
  313         error = hfs_unlink(dir, dentry);
  314         if ((error == -ENOENT) && is_hdr(dir, dentry->d_name.name,
  315                                          dentry->d_name.len)) {
  316                 error = -EPERM;
  317         }
  318         return error;
  319 }
  320 
  321 /*
  322  * dbl_rmdir()
  323  *
  324  * This is the rmdir() entry in the inode_operations structure for
  325  * AppleDouble directories.  The purpose is to delete an existing
  326  * directory, given the inode for the parent directory and the name
  327  * (and its length) of the existing directory.
  328  */
  329 static int dbl_rmdir(struct inode * parent, struct dentry *dentry)
  330 {
  331         int error;
  332 
  333         error = hfs_rmdir(parent, dentry);
  334         if ((error == -ENOENT) && is_hdr(parent, dentry->d_name.name,
  335                                          dentry->d_name.len)) {
  336                 error = -ENOTDIR;
  337         }
  338         return error;
  339 }
  340 
  341 /*
  342  * dbl_rename()
  343  *
  344  * This is the rename() entry in the inode_operations structure for
  345  * AppleDouble directories.  The purpose is to rename an existing
  346  * file or directory, given the inode for the current directory and
  347  * the name (and its length) of the existing file/directory and the
  348  * inode for the new directory and the name (and its length) of the
  349  * new file/directory.
  350  * 
  351  * XXX: how do we handle must_be_dir?
  352  */
  353 static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry,
  354                       struct inode *new_dir, struct dentry *new_dentry)
  355 {
  356         int error;
  357 
  358         if (is_hdr(new_dir, new_dentry->d_name.name,
  359                    new_dentry->d_name.len)) {
  360                 error = -EPERM;
  361         } else {
  362                 error = hfs_rename(old_dir, old_dentry,
  363                                    new_dir, new_dentry);
  364                 if ((error == -ENOENT) /*&& !must_be_dir*/ &&
  365                     is_hdr(old_dir, old_dentry->d_name.name,
  366                            old_dentry->d_name.len)) {
  367                         error = -EPERM;
  368                 }
  369         }
  370         return error;
  371 }
  372 
  373 
  374 /* due to the dcache caching negative dentries for non-existent files,
  375  * we need to drop those entries when a file silently gets created.
  376  * as far as i can tell, the calls that need to do this are the file
  377  * related calls (create, rename, and mknod). the directory calls
  378  * should be immune. the relevant calls in dir.c call drop_dentry 
  379  * upon successful completion. */
  380 void hfs_dbl_drop_dentry(struct dentry *dentry, const ino_t type)
  381 {
  382   unsigned char tmp_name[HFS_NAMEMAX + 1];
  383   struct dentry *de = NULL;
  384 
  385   switch (type) {
  386   case HFS_DBL_HDR:
  387    /* given %name, look for name. i don't think this happens. */
  388    de = hfs_lookup_dentry(dentry->d_parent,
  389                           dentry->d_name.name + 1, dentry->d_name.len - 1);
  390     break;
  391   case HFS_DBL_DATA:
  392     /* given name, look for %name */
  393     tmp_name[0] = '%';
  394     strncpy(tmp_name + 1, dentry->d_name.name, HFS_NAMELEN - 1);
  395     de = hfs_lookup_dentry(dentry->d_parent, 
  396                            tmp_name, dentry->d_name.len + 1);
  397   }
  398 
  399   if (de) {
  400     if (!de->d_inode)
  401       d_drop(de);
  402     dput(de);
  403   }
  404 }

Cache object: 3376b5e76c279b379079311def9ddb4e


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