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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * fs/bfs/dir.c
  3.  * BFS directory operations.
  4.  * Copyright (C) 1999,2000  Tigran Aivazian <tigran@veritas.com>
  5.  */
  6. #include <linux/sched.h>
  7. #include <linux/string.h>
  8. #include <linux/bfs_fs.h>
  9. #include <linux/locks.h>
  10. #include "bfs_defs.h"
  11. #undef DEBUG
  12. #ifdef DEBUG
  13. #define dprintf(x...) printf(x)
  14. #else
  15. #define dprintf(x...)
  16. #endif
  17. static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino);
  18. static struct buffer_head * bfs_find_entry(struct inode * dir, 
  19. const char * name, int namelen, struct bfs_dirent ** res_dir);
  20. static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
  21. {
  22. struct inode * dir = f->f_dentry->d_inode;
  23. struct buffer_head * bh;
  24. struct bfs_dirent * de;
  25. kdev_t dev = dir->i_dev;
  26. unsigned int offset;
  27. int block;
  28. if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
  29. printf("Bad f_pos=%08lx for %s:%08lxn", (unsigned long)f->f_pos, 
  30. bdevname(dev), dir->i_ino);
  31. return -EBADF;
  32. }
  33. while (f->f_pos < dir->i_size) {
  34. offset = f->f_pos & (BFS_BSIZE-1);
  35. block = dir->iu_sblock + (f->f_pos >> BFS_BSIZE_BITS);
  36. bh = sb_bread(dir->i_sb, block);
  37. if (!bh) {
  38. f->f_pos += BFS_BSIZE - offset;
  39. continue;
  40. }
  41. do {
  42. de = (struct bfs_dirent *)(bh->b_data + offset);
  43. if (de->ino) {
  44. int size = strnlen(de->name, BFS_NAMELEN);
  45. if (filldir(dirent, de->name, size, f->f_pos, de->ino, DT_UNKNOWN) < 0) {
  46. brelse(bh);
  47. return 0;
  48. }
  49. }
  50. offset += BFS_DIRENT_SIZE;
  51. f->f_pos += BFS_DIRENT_SIZE;
  52. } while (offset < BFS_BSIZE && f->f_pos < dir->i_size);
  53. brelse(bh);
  54. }
  55. UPDATE_ATIME(dir);
  56. return 0;
  57. }
  58. struct file_operations bfs_dir_operations = {
  59. read: generic_read_dir,
  60. readdir: bfs_readdir,
  61. fsync: file_fsync,
  62. };
  63. extern void dump_imap(const char *, struct super_block *);
  64. static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
  65. {
  66. int err;
  67. struct inode * inode;
  68. struct super_block * s = dir->i_sb;
  69. unsigned long ino;
  70. inode = new_inode(s);
  71. if (!inode)
  72. return -ENOSPC;
  73. ino = find_first_zero_bit(s->su_imap, s->su_lasti);
  74. if (ino > s->su_lasti) {
  75. iput(inode);
  76. return -ENOSPC;
  77. }
  78. set_bit(ino, s->su_imap);
  79. s->su_freei--;
  80. inode->i_uid = current->fsuid;
  81. inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
  82. inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
  83. inode->i_blocks = inode->i_blksize = 0;
  84. inode->i_op = &bfs_file_inops;
  85. inode->i_fop = &bfs_file_operations;
  86. inode->i_mapping->a_ops = &bfs_aops;
  87. inode->i_mode = mode;
  88. inode->i_ino = inode->iu_dsk_ino = ino;
  89. inode->iu_sblock = inode->iu_eblock = 0;
  90. insert_inode_hash(inode);
  91.         mark_inode_dirty(inode);
  92. dump_imap("create",s);
  93. err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
  94. if (err) {
  95. inode->i_nlink--;
  96. mark_inode_dirty(inode);
  97. iput(inode);
  98. return err;
  99. }
  100. d_instantiate(dentry, inode);
  101. return 0;
  102. }
  103. static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry)
  104. {
  105. struct inode * inode = NULL;
  106. struct buffer_head * bh;
  107. struct bfs_dirent * de;
  108. if (dentry->d_name.len > BFS_NAMELEN)
  109. return ERR_PTR(-ENAMETOOLONG);
  110. bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
  111. if (bh) {
  112. unsigned long ino = le32_to_cpu(de->ino);
  113. brelse(bh);
  114. inode = iget(dir->i_sb, ino);
  115. if (!inode)
  116. return ERR_PTR(-EACCES);
  117. }
  118. d_add(dentry, inode);
  119. return NULL;
  120. }
  121. static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new)
  122. {
  123. struct inode * inode = old->d_inode;
  124. int err;
  125. if (S_ISDIR(inode->i_mode))
  126. return -EPERM;
  127. err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, inode->i_ino);
  128. if (err)
  129. return err;
  130. inode->i_nlink++;
  131. inode->i_ctime = CURRENT_TIME;
  132. mark_inode_dirty(inode);
  133. atomic_inc(&inode->i_count);
  134. d_instantiate(new, inode);
  135. return 0;
  136. }
  137. static int bfs_unlink(struct inode * dir, struct dentry * dentry)
  138. {
  139. int error = -ENOENT;
  140. struct inode * inode;
  141. struct buffer_head * bh;
  142. struct bfs_dirent * de;
  143. inode = dentry->d_inode;
  144. bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
  145. if (!bh || de->ino != inode->i_ino) 
  146. goto out_brelse;
  147. if (!inode->i_nlink) {
  148. printf("unlinking non-existent file %s:%lu (nlink=%d)n", bdevname(inode->i_dev), 
  149. inode->i_ino, inode->i_nlink);
  150. inode->i_nlink = 1;
  151. }
  152. de->ino = 0;
  153. dir->i_version = ++event;
  154. mark_buffer_dirty(bh);
  155. dir->i_ctime = dir->i_mtime = CURRENT_TIME;
  156. mark_inode_dirty(dir);
  157. inode->i_nlink--;
  158. inode->i_ctime = dir->i_ctime;
  159. mark_inode_dirty(inode);
  160. error = 0;
  161. out_brelse:
  162. brelse(bh);
  163. return error;
  164. }
  165. static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry, 
  166. struct inode * new_dir, struct dentry * new_dentry)
  167. {
  168. struct inode * old_inode, * new_inode;
  169. struct buffer_head * old_bh, * new_bh;
  170. struct bfs_dirent * old_de, * new_de;
  171. int error = -ENOENT;
  172. old_bh = new_bh = NULL;
  173. old_inode = old_dentry->d_inode;
  174. if (S_ISDIR(old_inode->i_mode))
  175. return -EINVAL;
  176. old_bh = bfs_find_entry(old_dir, 
  177. old_dentry->d_name.name, 
  178. old_dentry->d_name.len, &old_de);
  179. if (!old_bh || old_de->ino != old_inode->i_ino)
  180. goto end_rename;
  181. error = -EPERM;
  182. new_inode = new_dentry->d_inode;
  183. new_bh = bfs_find_entry(new_dir, 
  184. new_dentry->d_name.name, 
  185. new_dentry->d_name.len, &new_de);
  186. if (new_bh && !new_inode) {
  187. brelse(new_bh);
  188. new_bh = NULL;
  189. }
  190. if (!new_bh) {
  191. error = bfs_add_entry(new_dir, 
  192. new_dentry->d_name.name,
  193.   new_dentry->d_name.len, old_inode->i_ino);
  194. if (error)
  195. goto end_rename;
  196. }
  197. old_de->ino = 0;
  198. old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
  199. old_dir->i_version = ++event;
  200. mark_inode_dirty(old_dir);
  201. if (new_inode) {
  202. new_inode->i_nlink--;
  203. new_inode->i_ctime = CURRENT_TIME;
  204. mark_inode_dirty(new_inode);
  205. }
  206. mark_buffer_dirty(old_bh);
  207. error = 0;
  208. end_rename:
  209. brelse(old_bh);
  210. brelse(new_bh);
  211. return error;
  212. }
  213. struct inode_operations bfs_dir_inops = {
  214. create: bfs_create,
  215. lookup: bfs_lookup,
  216. link: bfs_link,
  217. unlink: bfs_unlink,
  218. rename: bfs_rename,
  219. };
  220. static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino)
  221. {
  222. struct buffer_head * bh;
  223. struct bfs_dirent * de;
  224. int block, sblock, eblock, off;
  225. kdev_t dev;
  226. int i;
  227. dprintf("name=%s, namelen=%dn", name, namelen);
  228. if (!namelen)
  229. return -ENOENT;
  230. if (namelen > BFS_NAMELEN)
  231. return -ENAMETOOLONG;
  232. dev = dir->i_dev;
  233. sblock = dir->iu_sblock;
  234. eblock = dir->iu_eblock;
  235. for (block=sblock; block<=eblock; block++) {
  236. bh = sb_bread(dir->i_sb, block);
  237. if(!bh) 
  238. return -ENOSPC;
  239. for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) {
  240. de = (struct bfs_dirent *)(bh->b_data + off);
  241. if (!de->ino) {
  242. if ((block-sblock)*BFS_BSIZE + off >= dir->i_size) {
  243. dir->i_size += BFS_DIRENT_SIZE;
  244. dir->i_ctime = CURRENT_TIME;
  245. }
  246. dir->i_mtime = CURRENT_TIME;
  247. mark_inode_dirty(dir);
  248. dir->i_version = ++event;
  249. de->ino = ino;
  250. for (i=0; i<BFS_NAMELEN; i++)
  251. de->name[i] = (i < namelen) ? name[i] : 0;
  252. mark_buffer_dirty(bh);
  253. brelse(bh);
  254. return 0;
  255. }
  256. }
  257. brelse(bh);
  258. }
  259. return -ENOSPC;
  260. }
  261. static inline int bfs_namecmp(int len, const char * name, const char * buffer)
  262. {
  263. if (len < BFS_NAMELEN && buffer[len])
  264. return 0;
  265. return !memcmp(name, buffer, len);
  266. }
  267. static struct buffer_head * bfs_find_entry(struct inode * dir, 
  268. const char * name, int namelen, struct bfs_dirent ** res_dir)
  269. {
  270. unsigned long block, offset;
  271. struct buffer_head * bh;
  272. struct bfs_sb_info * info;
  273. struct bfs_dirent * de;
  274. *res_dir = NULL;
  275. info = &dir->i_sb->u.bfs_sb;
  276. if (namelen > BFS_NAMELEN)
  277. return NULL;
  278. bh = NULL;
  279. block = offset = 0;
  280. while (block * BFS_BSIZE + offset < dir->i_size) {
  281. if (!bh) {
  282. bh = sb_bread(dir->i_sb, dir->iu_sblock + block);
  283. if (!bh) {
  284. block++;
  285. continue;
  286. }
  287. }
  288. de = (struct bfs_dirent *)(bh->b_data + offset);
  289. offset += BFS_DIRENT_SIZE;
  290. if (de->ino && bfs_namecmp(namelen, name, de->name)) {
  291. *res_dir = de;
  292. return bh;
  293. }
  294. if (offset < bh->b_size)
  295. continue;
  296. brelse(bh);
  297. bh = NULL;
  298. offset = 0;
  299. block++;
  300. }
  301. brelse(bh);
  302. return NULL;
  303. }