dir_cap.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:9k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 1995-1997  Paul H. Hargrove
  3.  * This file may be distributed under the terms of the GNU General Public License.
  4.  *
  5.  * This file contains the inode_operations and file_operations
  6.  * structures for HFS directories under the CAP scheme.
  7.  *
  8.  * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds
  9.  *
  10.  * The source code distribution of the Columbia AppleTalk Package for
  11.  * UNIX, version 6.0, (CAP) was used as a specification of the
  12.  * location and format of files used by CAP's Aufs.  No code from CAP
  13.  * appears in hfs_fs.  hfs_fs is not a work ``derived'' from CAP in
  14.  * the sense of intellectual property law.
  15.  *
  16.  * "XXX" in a comment is a note to myself to consider changing something.
  17.  *
  18.  * In function preconditions the term "valid" applied to a pointer to
  19.  * a structure means that the pointer is non-NULL and the structure it
  20.  * points to has all fields initialized to consistent values.
  21.  */
  22. #include "hfs.h"
  23. #include <linux/hfs_fs_sb.h>
  24. #include <linux/hfs_fs_i.h>
  25. #include <linux/hfs_fs.h>
  26. /*================ Forward declarations ================*/
  27. static struct dentry *cap_lookup(struct inode *, struct dentry *);
  28. static int cap_readdir(struct file *, void *, filldir_t);
  29. /*================ Global variables ================*/
  30. #define DOT_LEN 1
  31. #define DOT_DOT_LEN 2
  32. #define DOT_RESOURCE_LEN 9
  33. #define DOT_FINDERINFO_LEN 11
  34. #define DOT_ROOTINFO_LEN 9
  35. const struct hfs_name hfs_cap_reserved1[] = {
  36. {DOT_LEN, "."},
  37. {DOT_DOT_LEN, ".."},
  38. {DOT_RESOURCE_LEN, ".resource"},
  39. {DOT_FINDERINFO_LEN, ".finderinfo"},
  40. {0, ""},
  41. };
  42. const struct hfs_name hfs_cap_reserved2[] = {
  43. {DOT_ROOTINFO_LEN, ".rootinfo"},
  44. {0, ""},
  45. };
  46. #define DOT (&hfs_cap_reserved1[0])
  47. #define DOT_DOT (&hfs_cap_reserved1[1])
  48. #define DOT_RESOURCE (&hfs_cap_reserved1[2])
  49. #define DOT_FINDERINFO (&hfs_cap_reserved1[3])
  50. #define DOT_ROOTINFO (&hfs_cap_reserved2[0])
  51. struct file_operations hfs_cap_dir_operations = {
  52. read: generic_read_dir,
  53. readdir: cap_readdir,
  54. fsync: file_fsync,
  55. };
  56. struct inode_operations hfs_cap_ndir_inode_operations = {
  57. create: hfs_create,
  58. lookup: cap_lookup,
  59. unlink: hfs_unlink,
  60. mkdir: hfs_mkdir,
  61. rmdir: hfs_rmdir,
  62. rename: hfs_rename,
  63. setattr: hfs_notify_change,
  64. };
  65. struct inode_operations hfs_cap_fdir_inode_operations = {
  66. lookup: cap_lookup,
  67. setattr: hfs_notify_change,
  68. };
  69. struct inode_operations hfs_cap_rdir_inode_operations = {
  70. create: hfs_create,
  71. lookup: cap_lookup,
  72. setattr: hfs_notify_change,
  73. };
  74. /*================ File-local functions ================*/
  75. /*
  76.  * cap_lookup()
  77.  *
  78.  * This is the lookup() entry in the inode_operations structure for
  79.  * HFS directories in the CAP scheme.  The purpose is to generate the
  80.  * inode corresponding to an entry in a directory, given the inode for
  81.  * the directory and the name (and its length) of the entry.
  82.  */
  83. static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry)
  84. {
  85. ino_t dtype;
  86. struct hfs_name cname;
  87. struct hfs_cat_entry *entry;
  88. struct hfs_cat_key key;
  89. struct inode *inode = NULL;
  90. dentry->d_op = &hfs_dentry_operations;
  91. entry = HFS_I(dir)->entry;
  92. dtype = HFS_ITYPE(dir->i_ino);
  93. /* Perform name-mangling */
  94. hfs_nameout(dir, &cname, dentry->d_name.name, 
  95.     dentry->d_name.len);
  96. /* no need to check for "."  or ".." */
  97. /* Check for special directories if in a normal directory.
  98.    Note that cap_dupdir() does an iput(dir). */
  99. if (dtype==HFS_CAP_NDIR) {
  100. /* Check for ".resource", ".finderinfo" and ".rootinfo" */
  101. if (hfs_streq(cname.Name, cname.Len, 
  102.       DOT_RESOURCE->Name, DOT_RESOURCE_LEN)) {
  103. ++entry->count; /* __hfs_iget() eats one */
  104. inode = hfs_iget(entry, HFS_CAP_RDIR, dentry);
  105. goto done;
  106. } else if (hfs_streq(cname.Name, cname.Len, 
  107.      DOT_FINDERINFO->Name, 
  108.      DOT_FINDERINFO_LEN)) {
  109. ++entry->count; /* __hfs_iget() eats one */
  110. inode = hfs_iget(entry, HFS_CAP_FDIR, dentry);
  111. goto done;
  112. } else if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
  113.    hfs_streq(cname.Name, cname.Len, 
  114.      DOT_ROOTINFO->Name, DOT_ROOTINFO_LEN)) {
  115. ++entry->count; /* __hfs_iget() eats one */
  116. inode = hfs_iget(entry, HFS_CAP_FNDR, dentry);
  117. goto done;
  118. }
  119. }
  120. /* Do an hfs_iget() on the mangled name. */
  121. hfs_cat_build_key(entry->cnid, &cname, &key);
  122. inode = hfs_iget(hfs_cat_get(entry->mdb, &key),
  123.  HFS_I(dir)->file_type, dentry);
  124. /* Don't return a resource fork for a directory */
  125. if (inode && (dtype == HFS_CAP_RDIR) && 
  126.     (HFS_I(inode)->entry->type == HFS_CDR_DIR)) {
  127.         iput(inode); /* this does an hfs_cat_put */
  128. inode = NULL;
  129. }
  130. done:
  131. d_add(dentry, inode);
  132. return NULL;
  133. }
  134. /*
  135.  * cap_readdir()
  136.  *
  137.  * This is the readdir() entry in the file_operations structure for
  138.  * HFS directories in the CAP scheme.  The purpose is to enumerate the
  139.  * entries in a directory, given the inode of the directory and a
  140.  * (struct file *), the 'f_pos' field of which indicates the location
  141.  * in the directory.  The (struct file *) is updated so that the next
  142.  * call with the same 'dir' and 'filp' arguments will produce the next
  143.  * directory entry.  The entries are returned in 'dirent', which is
  144.  * "filled-in" by calling filldir().  This allows the same readdir()
  145.  * function be used for different dirent formats.  We try to read in
  146.  * as many entries as we can before filldir() refuses to take any more.
  147.  *
  148.  * XXX: In the future it may be a good idea to consider not generating
  149.  * metadata files for covered directories since the data doesn't
  150.  * correspond to the mounted directory.  However this requires an
  151.  * iget() for every directory which could be considered an excessive
  152.  * amount of overhead. Since the inode for a mount point is always
  153.  * in-core this is another argument for a call to get an inode if it
  154.  * is in-core or NULL if it is not.
  155.  */
  156. static int cap_readdir(struct file * filp,
  157.        void * dirent, filldir_t filldir)
  158. {
  159. ino_t type;
  160. int skip_dirs;
  161. struct hfs_brec brec;
  162.         struct hfs_cat_entry *entry;
  163. struct inode *dir = filp->f_dentry->d_inode;
  164. entry = HFS_I(dir)->entry;
  165. type = HFS_ITYPE(dir->i_ino);
  166. skip_dirs = (type == HFS_CAP_RDIR);
  167. if (filp->f_pos == 0) {
  168. /* Entry 0 is for "." */
  169. if (filldir(dirent, DOT->Name, DOT_LEN, 0, dir->i_ino, DT_DIR)) {
  170. return 0;
  171. }
  172. filp->f_pos = 1;
  173. }
  174. if (filp->f_pos == 1) {
  175. /* Entry 1 is for ".." */
  176. hfs_u32 cnid;
  177. if (type == HFS_CAP_NDIR) {
  178. cnid = hfs_get_nl(entry->key.ParID);
  179. } else {
  180. cnid = entry->cnid;
  181. }
  182. if (filldir(dirent, DOT_DOT->Name,
  183.     DOT_DOT_LEN, 1, ntohl(cnid), DT_DIR)) {
  184. return 0;
  185. }
  186. filp->f_pos = 2;
  187. }
  188. if (filp->f_pos < (dir->i_size - 3)) {
  189. hfs_u32 cnid;
  190. hfs_u8 type;
  191.      if (hfs_cat_open(entry, &brec) ||
  192.          hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) {
  193. return 0;
  194. }
  195. while (filp->f_pos < (dir->i_size - 3)) {
  196. if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) {
  197. return 0;
  198. }
  199. if (!skip_dirs || (type != HFS_CDR_DIR)) {
  200. ino_t ino;
  201. unsigned int len;
  202. unsigned char tmp_name[HFS_NAMEMAX];
  203. ino = ntohl(cnid) | HFS_I(dir)->file_type;
  204. len = hfs_namein(dir, tmp_name,
  205.     &((struct hfs_cat_key *)brec.key)->CName);
  206. if (filldir(dirent, tmp_name, len,
  207.     filp->f_pos, ino, DT_UNKNOWN)) {
  208. hfs_cat_close(entry, &brec);
  209. return 0;
  210. }
  211. }
  212. ++filp->f_pos;
  213. }
  214. hfs_cat_close(entry, &brec);
  215. }
  216. if (filp->f_pos == (dir->i_size - 3)) {
  217. if ((entry->cnid == htonl(HFS_ROOT_CNID)) &&
  218.     (type == HFS_CAP_NDIR)) {
  219. /* In root dir last-2 entry is for ".rootinfo" */
  220. if (filldir(dirent, DOT_ROOTINFO->Name,
  221.     DOT_ROOTINFO_LEN, filp->f_pos,
  222.     ntohl(entry->cnid) | HFS_CAP_FNDR,
  223.     DT_UNKNOWN)) {
  224. return 0;
  225. }
  226. }
  227. ++filp->f_pos;
  228. }
  229. if (filp->f_pos == (dir->i_size - 2)) {
  230. if (type == HFS_CAP_NDIR) {
  231. /* In normal dirs last-1 entry is for ".finderinfo" */
  232. if (filldir(dirent, DOT_FINDERINFO->Name,
  233.     DOT_FINDERINFO_LEN, filp->f_pos,
  234.     ntohl(entry->cnid) | HFS_CAP_FDIR,
  235.     DT_UNKNOWN)) {
  236. return 0;
  237. }
  238. }
  239. ++filp->f_pos;
  240. }
  241. if (filp->f_pos == (dir->i_size - 1)) {
  242. if (type == HFS_CAP_NDIR) {
  243. /* In normal dirs last entry is for ".resource" */
  244. if (filldir(dirent, DOT_RESOURCE->Name,
  245.     DOT_RESOURCE_LEN, filp->f_pos,
  246.     ntohl(entry->cnid) | HFS_CAP_RDIR,
  247.     DT_UNKNOWN)) {
  248. return 0;
  249. }
  250. }
  251. ++filp->f_pos;
  252. }
  253. return 0;
  254. }
  255. /* due to the dcache caching negative dentries for non-existent files,
  256.  * we need to drop those entries when a file silently gets created.
  257.  * as far as i can tell, the calls that need to do this are the file
  258.  * related calls (create, rename, and mknod). the directory calls
  259.  * should be immune. the relevant calls in dir.c call drop_dentry 
  260.  * upon successful completion. */
  261. void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type)
  262. {
  263.   if (type == HFS_CAP_DATA) { /* given name */
  264.     hfs_drop_special(dentry->d_parent, DOT_FINDERINFO, dentry);
  265.     hfs_drop_special(dentry->d_parent, DOT_RESOURCE, dentry);
  266.   } else {
  267.     struct dentry *de;
  268.     /* given {.resource,.finderinfo}/name, look for name */
  269.     if ((de = hfs_lookup_dentry(dentry->d_parent->d_parent,
  270. dentry->d_name.name, dentry->d_name.len))) {
  271.       if (!de->d_inode)
  272. d_drop(de);
  273.       dput(de);
  274.     }
  275.     
  276.     switch (type) {
  277.     case HFS_CAP_RSRC: /* given .resource/name */
  278.        /* look for .finderinfo/name */
  279.       hfs_drop_special(dentry->d_parent->d_parent, DOT_FINDERINFO, 
  280.        dentry);
  281.       break;
  282.     case HFS_CAP_FNDR: /* given .finderinfo/name. i don't this 
  283. * happens. */
  284.       /* look for .resource/name */
  285.       hfs_drop_special(dentry->d_parent->d_parent, DOT_RESOURCE, 
  286.        dentry);
  287.       break;
  288.     }
  289.   }
  290. }