dir.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * linux/fs/adfs/dir.c
  3. *
  4. * Copyright (C) 1999-2000 Russell King
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Common directory handling for ADFS
  11. */
  12. #include "adfs.h"
  13. /*
  14. * For future. This should probably be per-directory.
  15. */
  16. static DEFINE_RWLOCK(adfs_dir_lock);
  17. static int
  18. adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  19. {
  20. struct inode *inode = filp->f_path.dentry->d_inode;
  21. struct super_block *sb = inode->i_sb;
  22. struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
  23. struct object_info obj;
  24. struct adfs_dir dir;
  25. int ret = 0;
  26. if (filp->f_pos >> 32)
  27. goto out;
  28. ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
  29. if (ret)
  30. goto out;
  31. switch ((unsigned long)filp->f_pos) {
  32. case 0:
  33. if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
  34. goto free_out;
  35. filp->f_pos += 1;
  36. case 1:
  37. if (filldir(dirent, "..", 2, 1, dir.parent_id, DT_DIR) < 0)
  38. goto free_out;
  39. filp->f_pos += 1;
  40. default:
  41. break;
  42. }
  43. read_lock(&adfs_dir_lock);
  44. ret = ops->setpos(&dir, filp->f_pos - 2);
  45. if (ret)
  46. goto unlock_out;
  47. while (ops->getnext(&dir, &obj) == 0) {
  48. if (filldir(dirent, obj.name, obj.name_len,
  49. filp->f_pos, obj.file_id, DT_UNKNOWN) < 0)
  50. goto unlock_out;
  51. filp->f_pos += 1;
  52. }
  53. unlock_out:
  54. read_unlock(&adfs_dir_lock);
  55. free_out:
  56. ops->free(&dir);
  57. out:
  58. return ret;
  59. }
  60. int
  61. adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
  62. {
  63. int ret = -EINVAL;
  64. #ifdef CONFIG_ADFS_FS_RW
  65. struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
  66. struct adfs_dir dir;
  67. printk(KERN_INFO "adfs_dir_update: object %06X in dir %06X\n",
  68. obj->file_id, obj->parent_id);
  69. if (!ops->update) {
  70. ret = -EINVAL;
  71. goto out;
  72. }
  73. ret = ops->read(sb, obj->parent_id, 0, &dir);
  74. if (ret)
  75. goto out;
  76. write_lock(&adfs_dir_lock);
  77. ret = ops->update(&dir, obj);
  78. write_unlock(&adfs_dir_lock);
  79. if (wait) {
  80. int err = ops->sync(&dir);
  81. if (!ret)
  82. ret = err;
  83. }
  84. ops->free(&dir);
  85. out:
  86. #endif
  87. return ret;
  88. }
  89. static int
  90. adfs_match(struct qstr *name, struct object_info *obj)
  91. {
  92. int i;
  93. if (name->len != obj->name_len)
  94. return 0;
  95. for (i = 0; i < name->len; i++) {
  96. char c1, c2;
  97. c1 = name->name[i];
  98. c2 = obj->name[i];
  99. if (c1 >= 'A' && c1 <= 'Z')
  100. c1 += 'a' - 'A';
  101. if (c2 >= 'A' && c2 <= 'Z')
  102. c2 += 'a' - 'A';
  103. if (c1 != c2)
  104. return 0;
  105. }
  106. return 1;
  107. }
  108. static int
  109. adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_info *obj)
  110. {
  111. struct super_block *sb = inode->i_sb;
  112. struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
  113. struct adfs_dir dir;
  114. int ret;
  115. ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
  116. if (ret)
  117. goto out;
  118. if (ADFS_I(inode)->parent_id != dir.parent_id) {
  119. adfs_error(sb, "parent directory changed under me! (%lx but got %lx)\n",
  120. ADFS_I(inode)->parent_id, dir.parent_id);
  121. ret = -EIO;
  122. goto free_out;
  123. }
  124. obj->parent_id = inode->i_ino;
  125. /*
  126. * '.' is handled by reserved_lookup() in fs/namei.c
  127. */
  128. if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.') {
  129. /*
  130. * Currently unable to fill in the rest of 'obj',
  131. * but this is better than nothing. We need to
  132. * ascend one level to find it's parent.
  133. */
  134. obj->name_len = 0;
  135. obj->file_id = obj->parent_id;
  136. goto free_out;
  137. }
  138. read_lock(&adfs_dir_lock);
  139. ret = ops->setpos(&dir, 0);
  140. if (ret)
  141. goto unlock_out;
  142. ret = -ENOENT;
  143. while (ops->getnext(&dir, obj) == 0) {
  144. if (adfs_match(name, obj)) {
  145. ret = 0;
  146. break;
  147. }
  148. }
  149. unlock_out:
  150. read_unlock(&adfs_dir_lock);
  151. free_out:
  152. ops->free(&dir);
  153. out:
  154. return ret;
  155. }
  156. const struct file_operations adfs_dir_operations = {
  157. .read = generic_read_dir,
  158. .llseek = generic_file_llseek,
  159. .readdir = adfs_readdir,
  160. .fsync = generic_file_fsync,
  161. };
  162. static int
  163. adfs_hash(const struct dentry *parent, const struct inode *inode,
  164. struct qstr *qstr)
  165. {
  166. const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen;
  167. const unsigned char *name;
  168. unsigned long hash;
  169. int i;
  170. if (qstr->len < name_len)
  171. return 0;
  172. /*
  173. * Truncate the name in place, avoids
  174. * having to define a compare function.
  175. */
  176. qstr->len = i = name_len;
  177. name = qstr->name;
  178. hash = init_name_hash();
  179. while (i--) {
  180. char c;
  181. c = *name++;
  182. if (c >= 'A' && c <= 'Z')
  183. c += 'a' - 'A';
  184. hash = partial_name_hash(c, hash);
  185. }
  186. qstr->hash = end_name_hash(hash);
  187. return 0;
  188. }
  189. /*
  190. * Compare two names, taking note of the name length
  191. * requirements of the underlying filesystem.
  192. */
  193. static int
  194. adfs_compare(const struct dentry *parent, const struct inode *pinode,
  195. const struct dentry *dentry, const struct inode *inode,
  196. unsigned int len, const char *str, const struct qstr *name)
  197. {
  198. int i;
  199. if (len != name->len)
  200. return 1;
  201. for (i = 0; i < name->len; i++) {
  202. char a, b;
  203. a = str[i];
  204. b = name->name[i];
  205. if (a >= 'A' && a <= 'Z')
  206. a += 'a' - 'A';
  207. if (b >= 'A' && b <= 'Z')
  208. b += 'a' - 'A';
  209. if (a != b)
  210. return 1;
  211. }
  212. return 0;
  213. }
  214. const struct dentry_operations adfs_dentry_operations = {
  215. .d_hash = adfs_hash,
  216. .d_compare = adfs_compare,
  217. };
  218. static struct dentry *
  219. adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
  220. {
  221. struct inode *inode = NULL;
  222. struct object_info obj;
  223. int error;
  224. error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
  225. if (error == 0) {
  226. error = -EACCES;
  227. /*
  228. * This only returns NULL if get_empty_inode
  229. * fails.
  230. */
  231. inode = adfs_iget(dir->i_sb, &obj);
  232. if (inode)
  233. error = 0;
  234. }
  235. d_add(dentry, inode);
  236. return ERR_PTR(error);
  237. }
  238. /*
  239. * directories can handle most operations...
  240. */
  241. const struct inode_operations adfs_dir_inode_operations = {
  242. .lookup = adfs_lookup,
  243. .setattr = adfs_notify_change,
  244. };