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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/sysv/namei.c
  3.  *
  4.  *  minix/namei.c
  5.  *  Copyright (C) 1991, 1992  Linus Torvalds
  6.  *
  7.  *  coh/namei.c
  8.  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
  9.  *
  10.  *  sysv/namei.c
  11.  *  Copyright (C) 1993  Bruno Haible
  12.  *  Copyright (C) 1997, 1998  Krzysztof G. Baranowski
  13.  */
  14. #include <linux/fs.h>
  15. #include <linux/sysv_fs.h>
  16. #include <linux/pagemap.h>
  17. static inline void inc_count(struct inode *inode)
  18. {
  19. inode->i_nlink++;
  20. mark_inode_dirty(inode);
  21. }
  22. static inline void dec_count(struct inode *inode)
  23. {
  24. inode->i_nlink--;
  25. mark_inode_dirty(inode);
  26. }
  27. static int add_nondir(struct dentry *dentry, struct inode *inode)
  28. {
  29. int err = sysv_add_link(dentry, inode);
  30. if (!err) {
  31. d_instantiate(dentry, inode);
  32. return 0;
  33. }
  34. dec_count(inode);
  35. iput(inode);
  36. return err;
  37. }
  38. static int sysv_hash(struct dentry *dentry, struct qstr *qstr)
  39. {
  40. unsigned long hash;
  41. int i;
  42. const unsigned char *name;
  43. i = SYSV_NAMELEN;
  44. if (i >= qstr->len)
  45. return 0;
  46. /* Truncate the name in place, avoids having to define a compare
  47.    function. */
  48. qstr->len = i;
  49. name = qstr->name;
  50. hash = init_name_hash();
  51. while (i--)
  52. hash = partial_name_hash(*name++, hash);
  53. qstr->hash = end_name_hash(hash);
  54. return 0;
  55. }
  56. struct dentry_operations sysv_dentry_operations = {
  57. d_hash: sysv_hash,
  58. };
  59. static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
  60. {
  61. struct inode * inode = NULL;
  62. ino_t ino;
  63. dentry->d_op = dir->i_sb->s_root->d_op;
  64. if (dentry->d_name.len > SYSV_NAMELEN)
  65. return ERR_PTR(-ENAMETOOLONG);
  66. ino = sysv_inode_by_name(dentry);
  67. if (ino) {
  68. inode = iget(dir->i_sb, ino);
  69. if (!inode) 
  70. return ERR_PTR(-EACCES);
  71. }
  72. d_add(dentry, inode);
  73. return NULL;
  74. }
  75. static int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
  76. {
  77. struct inode * inode = sysv_new_inode(dir, mode);
  78. int err = PTR_ERR(inode);
  79. if (!IS_ERR(inode)) {
  80. sysv_set_inode(inode, rdev);
  81. mark_inode_dirty(inode);
  82. err = add_nondir(dentry, inode);
  83. }
  84. return err;
  85. }
  86. static int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
  87. {
  88. return sysv_mknod(dir, dentry, mode, 0);
  89. }
  90. static int sysv_symlink(struct inode * dir, struct dentry * dentry, 
  91. const char * symname)
  92. {
  93. int err = -ENAMETOOLONG;
  94. int l = strlen(symname)+1;
  95. struct inode * inode;
  96. if (l > dir->i_sb->s_blocksize)
  97. goto out;
  98. inode = sysv_new_inode(dir, S_IFLNK|0777);
  99. err = PTR_ERR(inode);
  100. if (IS_ERR(inode))
  101. goto out;
  102. sysv_set_inode(inode, 0);
  103. err = block_symlink(inode, symname, l);
  104. if (err)
  105. goto out_fail;
  106. mark_inode_dirty(inode);
  107. err = add_nondir(dentry, inode);
  108. out:
  109. return err;
  110. out_fail:
  111. dec_count(inode);
  112. iput(inode);
  113. goto out;
  114. }
  115. static int sysv_link(struct dentry * old_dentry, struct inode * dir, 
  116. struct dentry * dentry)
  117. {
  118. struct inode *inode = old_dentry->d_inode;
  119. if (S_ISDIR(inode->i_mode))
  120. return -EPERM;
  121. if (inode->i_nlink >= inode->i_sb->sv_link_max)
  122. return -EMLINK;
  123. inode->i_ctime = CURRENT_TIME;
  124. inc_count(inode);
  125. atomic_inc(&inode->i_count);
  126. return add_nondir(dentry, inode);
  127. }
  128. static int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
  129. {
  130. struct inode * inode;
  131. int err = -EMLINK;
  132. if (dir->i_nlink >= dir->i_sb->sv_link_max) 
  133. goto out;
  134. inc_count(dir);
  135. inode = sysv_new_inode(dir, S_IFDIR|mode);
  136. err = PTR_ERR(inode);
  137. if (IS_ERR(inode))
  138. goto out_dir;
  139. sysv_set_inode(inode, 0);
  140. inc_count(inode);
  141. err = sysv_make_empty(inode, dir);
  142. if (err)
  143. goto out_fail;
  144. err = sysv_add_link(dentry, inode);
  145. if (err)
  146. goto out_fail;
  147.         d_instantiate(dentry, inode);
  148. out:
  149. return err;
  150. out_fail:
  151. dec_count(inode);
  152. dec_count(inode);
  153. iput(inode);
  154. out_dir:
  155. dec_count(dir);
  156. goto out;
  157. }
  158. static int sysv_unlink(struct inode * dir, struct dentry * dentry)
  159. {
  160. struct inode * inode = dentry->d_inode;
  161. struct page * page;
  162. struct sysv_dir_entry * de;
  163. int err = -ENOENT;
  164. de = sysv_find_entry(dentry, &page);
  165. if (!de)
  166. goto out;
  167. err = sysv_delete_entry (de, page);
  168. if (err)
  169. goto out;
  170. inode->i_ctime = dir->i_ctime;
  171. dec_count(inode);
  172. out:
  173. return err;
  174. }
  175. static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
  176. {
  177. struct inode *inode = dentry->d_inode;
  178. int err = -ENOTEMPTY;
  179. if (sysv_empty_dir(inode)) {
  180. err = sysv_unlink(dir, dentry);
  181. if (!err) {
  182. inode->i_size = 0;
  183. dec_count(inode);
  184. dec_count(dir);
  185. }
  186. }
  187. return err;
  188. }
  189. /*
  190.  * Anybody can rename anything with this: the permission checks are left to the
  191.  * higher-level routines.
  192.  */
  193. static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
  194.   struct inode * new_dir, struct dentry * new_dentry)
  195. {
  196. struct inode * old_inode = old_dentry->d_inode;
  197. struct inode * new_inode = new_dentry->d_inode;
  198. struct page * dir_page = NULL;
  199. struct sysv_dir_entry * dir_de = NULL;
  200. struct page * old_page;
  201. struct sysv_dir_entry * old_de;
  202. int err = -ENOENT;
  203. old_de = sysv_find_entry(old_dentry, &old_page);
  204. if (!old_de)
  205. goto out;
  206. if (S_ISDIR(old_inode->i_mode)) {
  207. err = -EIO;
  208. dir_de = sysv_dotdot(old_inode, &dir_page);
  209. if (!dir_de)
  210. goto out_old;
  211. }
  212. if (new_inode) {
  213. struct page * new_page;
  214. struct sysv_dir_entry * new_de;
  215. err = -ENOTEMPTY;
  216. if (dir_de && !sysv_empty_dir(new_inode))
  217. goto out_dir;
  218. err = -ENOENT;
  219. new_de = sysv_find_entry(new_dentry, &new_page);
  220. if (!new_de)
  221. goto out_dir;
  222. inc_count(old_inode);
  223. sysv_set_link(new_de, new_page, old_inode);
  224. new_inode->i_ctime = CURRENT_TIME;
  225. if (dir_de)
  226. new_inode->i_nlink--;
  227. dec_count(new_inode);
  228. } else {
  229. if (dir_de) {
  230. err = -EMLINK;
  231. if (new_dir->i_nlink >= new_dir->i_sb->sv_link_max)
  232. goto out_dir;
  233. }
  234. inc_count(old_inode);
  235. err = sysv_add_link(new_dentry, old_inode);
  236. if (err) {
  237. dec_count(old_inode);
  238. goto out_dir;
  239. }
  240. if (dir_de)
  241. inc_count(new_dir);
  242. }
  243. sysv_delete_entry(old_de, old_page);
  244. dec_count(old_inode);
  245. if (dir_de) {
  246. sysv_set_link(dir_de, dir_page, new_dir);
  247. dec_count(old_dir);
  248. }
  249. return 0;
  250. out_dir:
  251. if (dir_de) {
  252. kunmap(dir_page);
  253. page_cache_release(dir_page);
  254. }
  255. out_old:
  256. kunmap(old_page);
  257. page_cache_release(old_page);
  258. out:
  259. return err;
  260. }
  261. /*
  262.  * directories can handle most operations...
  263.  */
  264. struct inode_operations sysv_dir_inode_operations = {
  265. create: sysv_create,
  266. lookup: sysv_lookup,
  267. link: sysv_link,
  268. unlink: sysv_unlink,
  269. symlink: sysv_symlink,
  270. mkdir: sysv_mkdir,
  271. rmdir: sysv_rmdir,
  272. mknod: sysv_mknod,
  273. rename: sysv_rename,
  274. };