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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/sysv/dir.c
  3.  *
  4.  *  minix/dir.c
  5.  *  Copyright (C) 1991, 1992  Linus Torvalds
  6.  *
  7.  *  coh/dir.c
  8.  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
  9.  *
  10.  *  sysv/dir.c
  11.  *  Copyright (C) 1993  Bruno Haible
  12.  *
  13.  *  SystemV/Coherent directory handling functions
  14.  */
  15. #include <linux/fs.h>
  16. #include <linux/sysv_fs.h>
  17. #include <linux/pagemap.h>
  18. static int sysv_readdir(struct file *, void *, filldir_t);
  19. struct file_operations sysv_dir_operations = {
  20. read: generic_read_dir,
  21. readdir: sysv_readdir,
  22. fsync: sysv_sync_file,
  23. };
  24. static inline void dir_put_page(struct page *page)
  25. {
  26. kunmap(page);
  27. page_cache_release(page);
  28. }
  29. static inline unsigned long dir_pages(struct inode *inode)
  30. {
  31. return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
  32. }
  33. static int dir_commit_chunk(struct page *page, unsigned from, unsigned to)
  34. {
  35. struct inode *dir = (struct inode *)page->mapping->host;
  36. int err = 0;
  37. dir->i_version = ++event;
  38. page->mapping->a_ops->commit_write(NULL, page, from, to);
  39. if (IS_SYNC(dir)) {
  40. int err2;
  41. err = writeout_one_page(page);
  42. err2 = waitfor_one_page(page);
  43. if (err == 0)
  44. err = err2;
  45. }
  46. return err;
  47. }
  48. static struct page * dir_get_page(struct inode *dir, unsigned long n)
  49. {
  50. struct address_space *mapping = dir->i_mapping;
  51. struct page *page = read_cache_page(mapping, n,
  52. (filler_t*)mapping->a_ops->readpage, NULL);
  53. if (!IS_ERR(page)) {
  54. wait_on_page(page);
  55. kmap(page);
  56. if (!Page_Uptodate(page))
  57. goto fail;
  58. }
  59. return page;
  60. fail:
  61. dir_put_page(page);
  62. return ERR_PTR(-EIO);
  63. }
  64. static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
  65. {
  66. unsigned long pos = filp->f_pos;
  67. struct inode *inode = filp->f_dentry->d_inode;
  68. struct super_block *sb = inode->i_sb;
  69. unsigned offset = pos & ~PAGE_CACHE_MASK;
  70. unsigned long n = pos >> PAGE_CACHE_SHIFT;
  71. unsigned long npages = dir_pages(inode);
  72. pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
  73. if (pos >= inode->i_size)
  74. goto done;
  75. for ( ; n < npages; n++, offset = 0) {
  76. char *kaddr, *limit;
  77. struct sysv_dir_entry *de;
  78. struct page *page = dir_get_page(inode, n);
  79. if (IS_ERR(page))
  80. continue;
  81. kaddr = (char *)page_address(page);
  82. de = (struct sysv_dir_entry *)(kaddr+offset);
  83. limit = kaddr + PAGE_CACHE_SIZE - SYSV_DIRSIZE;
  84. for ( ;(char*)de <= limit; de++) {
  85. char *name = de->name;
  86. int over;
  87. if (!de->inode)
  88. continue;
  89. offset = (char *)de - kaddr;
  90. over = filldir(dirent, name, strnlen(name,SYSV_NAMELEN),
  91. (n<<PAGE_CACHE_SHIFT) | offset,
  92. fs16_to_cpu(sb, de->inode), DT_UNKNOWN);
  93. if (over) {
  94. dir_put_page(page);
  95. goto done;
  96. }
  97. }
  98. dir_put_page(page);
  99. }
  100. done:
  101. filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
  102. filp->f_version = inode->i_version;
  103. UPDATE_ATIME(inode);
  104. return 0;
  105. }
  106. /* compare strings: name[0..len-1] (not zero-terminated) and
  107.  * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
  108.  */
  109. static inline int namecompare(int len, int maxlen,
  110. const char * name, const char * buffer)
  111. {
  112. if (len < maxlen && buffer[len])
  113. return 0;
  114. return !memcmp(name, buffer, len);
  115. }
  116. /*
  117.  * sysv_find_entry()
  118.  *
  119.  * finds an entry in the specified directory with the wanted name. It
  120.  * returns the cache buffer in which the entry was found, and the entry
  121.  * itself (as a parameter - res_dir). It does NOT read the inode of the
  122.  * entry - you'll have to do that yourself if you want to.
  123.  */
  124. struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_page)
  125. {
  126. const char * name = dentry->d_name.name;
  127. int namelen = dentry->d_name.len;
  128. struct inode * dir = dentry->d_parent->d_inode;
  129. unsigned long start, n;
  130. unsigned long npages = dir_pages(dir);
  131. struct page *page = NULL;
  132. struct sysv_dir_entry *de;
  133. *res_page = NULL;
  134. start = dir->u.sysv_i.i_dir_start_lookup;
  135. if (start >= npages)
  136. start = 0;
  137. n = start;
  138. do {
  139. char *kaddr;
  140. page = dir_get_page(dir, n);
  141. if (!IS_ERR(page)) {
  142. kaddr = (char*)page_address(page);
  143. de = (struct sysv_dir_entry *) kaddr;
  144. kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
  145. for ( ; (char *) de <= kaddr ; de++) {
  146. if (!de->inode)
  147. continue;
  148. if (namecompare(namelen, SYSV_NAMELEN,
  149. name, de->name))
  150. goto found;
  151. }
  152. }
  153. dir_put_page(page);
  154. if (++n >= npages)
  155. n = 0;
  156. } while (n != start);
  157. return NULL;
  158. found:
  159. dir->u.sysv_i.i_dir_start_lookup = n;
  160. *res_page = page;
  161. return de;
  162. }
  163. int sysv_add_link(struct dentry *dentry, struct inode *inode)
  164. {
  165. struct inode *dir = dentry->d_parent->d_inode;
  166. const char * name = dentry->d_name.name;
  167. int namelen = dentry->d_name.len;
  168. struct page *page = NULL;
  169. struct sysv_dir_entry * de;
  170. unsigned long npages = dir_pages(dir);
  171. unsigned long n;
  172. char *kaddr;
  173. unsigned from, to;
  174. int err;
  175. /* We take care of directory expansion in the same loop */
  176. for (n = 0; n <= npages; n++) {
  177. page = dir_get_page(dir, n);
  178. err = PTR_ERR(page);
  179. if (IS_ERR(page))
  180. goto out;
  181. kaddr = (char*)page_address(page);
  182. de = (struct sysv_dir_entry *)kaddr;
  183. kaddr += PAGE_CACHE_SIZE - SYSV_DIRSIZE;
  184. while ((char *)de <= kaddr) {
  185. if (!de->inode)
  186. goto got_it;
  187. err = -EEXIST;
  188. if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) 
  189. goto out_page;
  190. de++;
  191. }
  192. dir_put_page(page);
  193. }
  194. BUG();
  195. return -EINVAL;
  196. got_it:
  197. from = (char*)de - (char*)page_address(page);
  198. to = from + SYSV_DIRSIZE;
  199. lock_page(page);
  200. err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
  201. if (err)
  202. goto out_unlock;
  203. memcpy (de->name, name, namelen);
  204. memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
  205. de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
  206. err = dir_commit_chunk(page, from, to);
  207. dir->i_mtime = dir->i_ctime = CURRENT_TIME;
  208. mark_inode_dirty(dir);
  209. out_unlock:
  210. UnlockPage(page);
  211. out_page:
  212. dir_put_page(page);
  213. out:
  214. return err;
  215. }
  216. int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
  217. {
  218. struct address_space *mapping = page->mapping;
  219. struct inode *inode = (struct inode*)mapping->host;
  220. char *kaddr = (char*)page_address(page);
  221. unsigned from = (char*)de - kaddr;
  222. unsigned to = from + SYSV_DIRSIZE;
  223. int err;
  224. lock_page(page);
  225. err = mapping->a_ops->prepare_write(NULL, page, from, to);
  226. if (err)
  227. BUG();
  228. de->inode = 0;
  229. err = dir_commit_chunk(page, from, to);
  230. UnlockPage(page);
  231. dir_put_page(page);
  232. inode->i_ctime = inode->i_mtime = CURRENT_TIME;
  233. mark_inode_dirty(inode);
  234. return err;
  235. }
  236. int sysv_make_empty(struct inode *inode, struct inode *dir)
  237. {
  238. struct address_space *mapping = inode->i_mapping;
  239. struct page *page = grab_cache_page(mapping, 0);
  240. struct sysv_dir_entry * de;
  241. char *base;
  242. int err;
  243. if (!page)
  244. return -ENOMEM;
  245. err = mapping->a_ops->prepare_write(NULL, page, 0, 2 * SYSV_DIRSIZE);
  246. if (err)
  247. goto fail;
  248. base = (char*)page_address(page);
  249. memset(base, 0, PAGE_CACHE_SIZE);
  250. de = (struct sysv_dir_entry *) base;
  251. de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
  252. strcpy(de->name,".");
  253. de++;
  254. de->inode = cpu_to_fs16(inode->i_sb, dir->i_ino);
  255. strcpy(de->name,"..");
  256. err = dir_commit_chunk(page, 0, 2 * SYSV_DIRSIZE);
  257. fail:
  258. UnlockPage(page);
  259. page_cache_release(page);
  260. return err;
  261. }
  262. /*
  263.  * routine to check that the specified directory is empty (for rmdir)
  264.  */
  265. int sysv_empty_dir(struct inode * inode)
  266. {
  267. struct super_block *sb = inode->i_sb;
  268. struct page *page = NULL;
  269. unsigned long i, npages = dir_pages(inode);
  270. for (i = 0; i < npages; i++) {
  271. char *kaddr;
  272. struct sysv_dir_entry * de;
  273. page = dir_get_page(inode, i);
  274. if (IS_ERR(page))
  275. continue;
  276. kaddr = (char *)page_address(page);
  277. de = (struct sysv_dir_entry *)kaddr;
  278. kaddr += PAGE_CACHE_SIZE-SYSV_DIRSIZE;
  279. for ( ;(char *)de <= kaddr; de++) {
  280. if (!de->inode)
  281. continue;
  282. /* check for . and .. */
  283. if (de->name[0] != '.')
  284. goto not_empty;
  285. if (!de->name[1]) {
  286. if (de->inode == cpu_to_fs16(sb, inode->i_ino))
  287. continue;
  288. goto not_empty;
  289. }
  290. if (de->name[1] != '.' || de->name[2])
  291. goto not_empty;
  292. }
  293. dir_put_page(page);
  294. }
  295. return 1;
  296. not_empty:
  297. dir_put_page(page);
  298. return 0;
  299. }
  300. /* Releases the page */
  301. void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
  302. struct inode *inode)
  303. {
  304. struct inode *dir = (struct inode*)page->mapping->host;
  305. unsigned from = (char *)de-(char*)page_address(page);
  306. unsigned to = from + SYSV_DIRSIZE;
  307. int err;
  308. lock_page(page);
  309. err = page->mapping->a_ops->prepare_write(NULL, page, from, to);
  310. if (err)
  311. BUG();
  312. de->inode = cpu_to_fs16(inode->i_sb, inode->i_ino);
  313. err = dir_commit_chunk(page, from, to);
  314. UnlockPage(page);
  315. dir_put_page(page);
  316. dir->i_mtime = dir->i_ctime = CURRENT_TIME;
  317. mark_inode_dirty(dir);
  318. }
  319. struct sysv_dir_entry * sysv_dotdot (struct inode *dir, struct page **p)
  320. {
  321. struct page *page = dir_get_page(dir, 0);
  322. struct sysv_dir_entry *de = NULL;
  323. if (!IS_ERR(page)) {
  324. de = (struct sysv_dir_entry*) page_address(page) + 1;
  325. *p = page;
  326. }
  327. return de;
  328. }
  329. ino_t sysv_inode_by_name(struct dentry *dentry)
  330. {
  331. struct page *page;
  332. struct sysv_dir_entry *de = sysv_find_entry (dentry, &page);
  333. ino_t res = 0;
  334. if (de) {
  335. res = fs16_to_cpu(dentry->d_sb, de->inode);
  336. dir_put_page(page);
  337. }
  338. return res;
  339. }