dir.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/hfs/dir.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 directory-related functions independent of which
  8.  * scheme is being used to represent forks.
  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. #include "hfs.h"
  19. #include <linux/hfs_fs_sb.h>
  20. #include <linux/hfs_fs_i.h>
  21. #include <linux/hfs_fs.h>
  22. /*================ File-local functions ================*/
  23. /*
  24.  * build_key()
  25.  *
  26.  * Build a key for a file by the given name in the given directory.
  27.  * If the name matches one of the reserved names returns 1 otherwise 0.
  28.  */
  29. static int build_key(struct hfs_cat_key *key, struct inode *dir,
  30.      const char *name, int len)
  31. {
  32. struct hfs_name cname;
  33. const struct hfs_name *reserved;
  34. /* mangle the name */
  35. hfs_nameout(dir, &cname, name, len);
  36. /* check against reserved names */
  37. reserved = HFS_SB(dir->i_sb)->s_reserved1;
  38. while (reserved->Len) {
  39. if (hfs_streq(reserved->Name, reserved->Len, 
  40.       cname.Name, cname.Len)) {
  41. return 1;
  42. }
  43. ++reserved;
  44. }
  45. /* check against the names reserved only in the root directory */
  46. if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) {
  47. reserved = HFS_SB(dir->i_sb)->s_reserved2;
  48. while (reserved->Len) {
  49. if (hfs_streq(reserved->Name, reserved->Len,
  50.       cname.Name, cname.Len)) {
  51. return 1;
  52. }
  53. ++reserved;
  54. }
  55. }
  56. /* build the key */
  57. hfs_cat_build_key(HFS_I(dir)->entry->cnid, &cname, key);
  58. return 0;
  59. }
  60. /*
  61.  * update_dirs_plus()
  62.  *
  63.  * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
  64.  * 'i_version' of the inodes associated with a directory that has
  65.  * had a file ('is_dir'==0) or directory ('is_dir'!=0) added to it.
  66.  */
  67. static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
  68. {
  69. int i;
  70. for (i = 0; i < 4; ++i) {
  71. struct dentry *de = dir->sys_entry[i];
  72. if (de) {
  73.         struct inode *tmp = de->d_inode;
  74. if (S_ISDIR(tmp->i_mode)) {
  75. if (is_dir &&
  76.     (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
  77. /* In "normal" directory only */
  78. ++(tmp->i_nlink);
  79. }
  80. tmp->i_size += HFS_I(tmp)->dir_size;
  81. tmp->i_version = ++event;
  82. }
  83. tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
  84. mark_inode_dirty(tmp);
  85. }
  86. }
  87. }
  88. /*
  89.  * update_dirs_minus()
  90.  *
  91.  * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and
  92.  * 'i_version' of the inodes associated with a directory that has
  93.  * had a file ('is_dir'==0) or directory ('is_dir'!=0) removed.
  94.  */
  95. static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir)
  96. {
  97. int i;
  98. for (i = 0; i < 4; ++i) {
  99. struct dentry *de = dir->sys_entry[i];
  100. if (de) {
  101.         struct inode *tmp = de->d_inode;
  102. if (S_ISDIR(tmp->i_mode)) {
  103. if (is_dir &&
  104.     (i == HFS_ITYPE_TO_INT(HFS_ITYPE_NORM))) {
  105. /* In "normal" directory only */
  106. --(tmp->i_nlink);
  107. }
  108. tmp->i_size -= HFS_I(tmp)->dir_size;
  109. tmp->i_version = ++event;
  110. }
  111. tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
  112. mark_inode_dirty(tmp);
  113. }
  114. }
  115. }
  116. /*
  117.  * mark_inodes_deleted()
  118.  *
  119.  * Update inodes associated with a deleted entry to reflect its deletion.
  120.  * Well, we really just drop the dentry.
  121.  *
  122.  * XXX: we should be using delete_inode for some of this stuff.
  123.  */
  124. static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, 
  125.        struct dentry *dentry)
  126. {
  127. struct dentry *de;
  128. struct inode *tmp;
  129. int i;
  130. for (i = 0; i < 4; ++i) {
  131. if ((de = entry->sys_entry[i]) && (dentry != de)) {
  132.       dget(de);
  133.       tmp = de->d_inode;
  134.       tmp->i_nlink = 0;
  135.       tmp->i_ctime = CURRENT_TIME;
  136.       mark_inode_dirty(tmp);
  137.       d_delete(de);
  138.       dput(de);
  139. }
  140. }
  141. }
  142. /*================ Global functions ================*/
  143. /*
  144.  * hfs_create()
  145.  *
  146.  * This is the create() entry in the inode_operations structure for
  147.  * regular HFS directories.  The purpose is to create a new file in
  148.  * a directory and return a corresponding inode, given the inode for
  149.  * the directory and the name (and its length) of the new file.
  150.  */
  151. int hfs_create(struct inode * dir, struct dentry *dentry, int mode)
  152. {
  153. struct hfs_cat_entry *entry = HFS_I(dir)->entry;
  154. struct hfs_cat_entry *new;
  155. struct hfs_cat_key key;
  156. struct inode *inode;
  157. int error;
  158. /* build the key, checking against reserved names */
  159. if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) 
  160. return -EEXIST;
  161. if ((error = hfs_cat_create(entry, &key, 
  162.        (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK,
  163.        HFS_SB(dir->i_sb)->s_type,
  164.        HFS_SB(dir->i_sb)->s_creator, &new)))
  165. return error;
  166. /* create an inode for the new file. back out if we run
  167.  * into trouble. */
  168. new->count++; /* hfs_iget() eats one */
  169. if (!(inode = hfs_iget(new, HFS_I(dir)->file_type, dentry))) {
  170. hfs_cat_delete(entry, new, 1);
  171. hfs_cat_put(new);
  172. return -EIO;
  173. }
  174. hfs_cat_put(new);
  175. update_dirs_plus(entry, 0);
  176. /* toss any relevant negative dentries */
  177. if (HFS_I(dir)->d_drop_op)
  178. HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type);
  179. mark_inode_dirty(inode);
  180. d_instantiate(dentry, inode);
  181. return 0;
  182. }
  183. /*
  184.  * hfs_mkdir()
  185.  *
  186.  * This is the mkdir() entry in the inode_operations structure for
  187.  * regular HFS directories.  The purpose is to create a new directory
  188.  * in a directory, given the inode for the parent directory and the
  189.  * name (and its length) of the new directory.
  190.  */
  191. int hfs_mkdir(struct inode * parent, struct dentry *dentry, int mode)
  192. {
  193. struct hfs_cat_entry *entry = HFS_I(parent)->entry;
  194. struct hfs_cat_entry *new;
  195. struct hfs_cat_key key;
  196. struct inode *inode;
  197. int error;
  198. /* build the key, checking against reserved names */
  199. if (build_key(&key, parent, dentry->d_name.name, 
  200.       dentry->d_name.len)) 
  201. return -EEXIST;
  202. /* try to create the directory */
  203. if ((error = hfs_cat_mkdir(entry, &key, &new)))
  204. return error;
  205. /* back out if we run into trouble */
  206. new->count++; /* hfs_iget eats one */
  207. if (!(inode = hfs_iget(new, HFS_I(parent)->file_type, dentry))) {
  208. hfs_cat_delete(entry, new, 1);
  209. hfs_cat_put(new);
  210. return -EIO;
  211. }
  212. hfs_cat_put(new);
  213. update_dirs_plus(entry, 1);
  214. mark_inode_dirty(inode);
  215. d_instantiate(dentry, inode);
  216. return 0;
  217. }
  218. /*
  219.  * hfs_unlink()
  220.  *
  221.  * This is the unlink() entry in the inode_operations structure for
  222.  * regular HFS directories.  The purpose is to delete an existing
  223.  * file, given the inode for the parent directory and the name
  224.  * (and its length) of the existing file.
  225.  */
  226. int hfs_unlink(struct inode * dir, struct dentry *dentry)
  227. {
  228. struct hfs_cat_entry *entry = HFS_I(dir)->entry;
  229. struct hfs_cat_entry *victim = NULL;
  230. struct hfs_cat_key key;
  231. int error;
  232. if (build_key(&key, dir, dentry->d_name.name,
  233.       dentry->d_name.len)) 
  234. return -EPERM;
  235. if (!(victim = hfs_cat_get(entry->mdb, &key))) 
  236. return -ENOENT;
  237. error = -EPERM;
  238. if (victim->type != HFS_CDR_FIL)
  239. goto hfs_unlink_put;
  240. if (!(error = hfs_cat_delete(entry, victim, 1))) {
  241. struct inode *inode = dentry->d_inode;
  242. mark_inodes_deleted(victim, dentry);
  243. inode->i_nlink--; 
  244. inode->i_ctime = CURRENT_TIME;
  245. mark_inode_dirty(inode);
  246. update_dirs_minus(entry, 0);
  247. }
  248. hfs_unlink_put:
  249. hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
  250. return error;
  251. }
  252. /*
  253.  * hfs_rmdir()
  254.  *
  255.  * This is the rmdir() entry in the inode_operations structure for
  256.  * regular HFS directories.  The purpose is to delete an existing
  257.  * directory, given the inode for the parent directory and the name
  258.  * (and its length) of the existing directory.
  259.  */
  260. int hfs_rmdir(struct inode * parent, struct dentry *dentry)
  261. {
  262. struct hfs_cat_entry *entry = HFS_I(parent)->entry;
  263. struct hfs_cat_entry *victim = NULL;
  264. struct inode *inode = dentry->d_inode;
  265. struct hfs_cat_key key;
  266. int error;
  267. if (build_key(&key, parent, dentry->d_name.name,
  268.       dentry->d_name.len))
  269. return -EPERM;
  270. if (!(victim = hfs_cat_get(entry->mdb, &key)))
  271. return -ENOENT;
  272. error = -ENOTDIR;
  273. if (victim->type != HFS_CDR_DIR) 
  274. goto hfs_rmdir_put;
  275. error = -EBUSY;
  276. if (!d_unhashed(dentry))
  277. goto hfs_rmdir_put;
  278. /* we only have to worry about 2 and 3 for mount points */
  279. if (victim->sys_entry[2] && d_mountpoint(victim->sys_entry[2]))
  280. goto hfs_rmdir_put;
  281. if (victim->sys_entry[3] && d_mountpoint(victim->sys_entry[3])) 
  282. goto hfs_rmdir_put;
  283. if ((error = hfs_cat_delete(entry, victim, 1)))
  284. goto hfs_rmdir_put;
  285. mark_inodes_deleted(victim, dentry);
  286. inode->i_nlink = 0;
  287. inode->i_ctime = CURRENT_TIME;
  288. mark_inode_dirty(inode);
  289. update_dirs_minus(entry, 1);
  290.  
  291. hfs_rmdir_put:
  292. hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
  293. return error;
  294. }
  295. /*
  296.  * hfs_rename()
  297.  *
  298.  * This is the rename() entry in the inode_operations structure for
  299.  * regular HFS directories.  The purpose is to rename an existing
  300.  * file or directory, given the inode for the current directory and
  301.  * the name (and its length) of the existing file/directory and the
  302.  * inode for the new directory and the name (and its length) of the
  303.  * new file/directory.
  304.  * XXX: how do you handle must_be dir?
  305.  */
  306. int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
  307.        struct inode *new_dir, struct dentry *new_dentry)
  308. {
  309. struct hfs_cat_entry *old_parent = HFS_I(old_dir)->entry;
  310. struct hfs_cat_entry *new_parent = HFS_I(new_dir)->entry;
  311. struct hfs_cat_entry *victim = NULL;
  312. struct hfs_cat_entry *deleted;
  313. struct hfs_cat_key key;
  314. int error;
  315. if (build_key(&key, old_dir, old_dentry->d_name.name,
  316.       old_dentry->d_name.len) ||
  317.     (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) 
  318. return -EPERM;
  319. if (!(victim = hfs_cat_get(old_parent->mdb, &key))) 
  320. return -ENOENT;
  321. error = -EPERM;
  322. if (build_key(&key, new_dir, new_dentry->d_name.name,
  323.      new_dentry->d_name.len)) 
  324. goto hfs_rename_put;
  325. if (!(error = hfs_cat_move(old_parent, new_parent,
  326.    victim, &key, &deleted))) {
  327. int is_dir = (victim->type == HFS_CDR_DIR);
  328. /* drop the old dentries */
  329. mark_inodes_deleted(victim, old_dentry);
  330. update_dirs_minus(old_parent, is_dir);
  331. if (deleted) {
  332. mark_inodes_deleted(deleted, new_dentry);
  333. hfs_cat_put(deleted);
  334. } else {
  335. /* no existing inodes. just drop negative dentries */
  336. if (HFS_I(new_dir)->d_drop_op) 
  337. HFS_I(new_dir)->d_drop_op(new_dentry, 
  338.   HFS_I(new_dir)->file_type);
  339. update_dirs_plus(new_parent, is_dir);
  340. }
  341. }
  342. hfs_rename_put:
  343. hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */
  344. return error;
  345. }