dir.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/fs/adfs/dir.c
  4. *
  5. * Copyright (C) 1999-2000 Russell King
  6. *
  7. * Common directory handling for ADFS
  8. */
  9. #include <linux/slab.h>
  10. #include "adfs.h"
  11. /*
  12. * For future. This should probably be per-directory.
  13. */
  14. static DECLARE_RWSEM(adfs_dir_rwsem);
  15. int adfs_dir_copyfrom(void *dst, struct adfs_dir *dir, unsigned int offset,
  16. size_t len)
  17. {
  18. struct super_block *sb = dir->sb;
  19. unsigned int index, remain;
  20. index = offset >> sb->s_blocksize_bits;
  21. offset &= sb->s_blocksize - 1;
  22. remain = sb->s_blocksize - offset;
  23. if (index + (remain < len) >= dir->nr_buffers)
  24. return -EINVAL;
  25. if (remain < len) {
  26. memcpy(dst, dir->bhs[index]->b_data + offset, remain);
  27. dst += remain;
  28. len -= remain;
  29. index += 1;
  30. offset = 0;
  31. }
  32. memcpy(dst, dir->bhs[index]->b_data + offset, len);
  33. return 0;
  34. }
  35. int adfs_dir_copyto(struct adfs_dir *dir, unsigned int offset, const void *src,
  36. size_t len)
  37. {
  38. struct super_block *sb = dir->sb;
  39. unsigned int index, remain;
  40. index = offset >> sb->s_blocksize_bits;
  41. offset &= sb->s_blocksize - 1;
  42. remain = sb->s_blocksize - offset;
  43. if (index + (remain < len) >= dir->nr_buffers)
  44. return -EINVAL;
  45. if (remain < len) {
  46. memcpy(dir->bhs[index]->b_data + offset, src, remain);
  47. src += remain;
  48. len -= remain;
  49. index += 1;
  50. offset = 0;
  51. }
  52. memcpy(dir->bhs[index]->b_data + offset, src, len);
  53. return 0;
  54. }
  55. static void __adfs_dir_cleanup(struct adfs_dir *dir)
  56. {
  57. dir->nr_buffers = 0;
  58. if (dir->bhs != dir->bh)
  59. kfree(dir->bhs);
  60. dir->bhs = NULL;
  61. dir->sb = NULL;
  62. }
  63. void adfs_dir_relse(struct adfs_dir *dir)
  64. {
  65. unsigned int i;
  66. for (i = 0; i < dir->nr_buffers; i++)
  67. brelse(dir->bhs[i]);
  68. __adfs_dir_cleanup(dir);
  69. }
  70. static void adfs_dir_forget(struct adfs_dir *dir)
  71. {
  72. unsigned int i;
  73. for (i = 0; i < dir->nr_buffers; i++)
  74. bforget(dir->bhs[i]);
  75. __adfs_dir_cleanup(dir);
  76. }
  77. int adfs_dir_read_buffers(struct super_block *sb, u32 indaddr,
  78. unsigned int size, struct adfs_dir *dir)
  79. {
  80. struct buffer_head **bhs;
  81. unsigned int i, num;
  82. int block;
  83. num = ALIGN(size, sb->s_blocksize) >> sb->s_blocksize_bits;
  84. if (num > ARRAY_SIZE(dir->bh)) {
  85. /* We only allow one extension */
  86. if (dir->bhs != dir->bh)
  87. return -EINVAL;
  88. bhs = kcalloc(num, sizeof(*bhs), GFP_KERNEL);
  89. if (!bhs)
  90. return -ENOMEM;
  91. if (dir->nr_buffers)
  92. memcpy(bhs, dir->bhs, dir->nr_buffers * sizeof(*bhs));
  93. dir->bhs = bhs;
  94. }
  95. for (i = dir->nr_buffers; i < num; i++) {
  96. block = __adfs_block_map(sb, indaddr, i);
  97. if (!block) {
  98. adfs_error(sb, "dir %06x has a hole at offset %u",
  99. indaddr, i);
  100. goto error;
  101. }
  102. dir->bhs[i] = sb_bread(sb, block);
  103. if (!dir->bhs[i]) {
  104. adfs_error(sb,
  105. "dir %06x failed read at offset %u, mapped block 0x%08x",
  106. indaddr, i, block);
  107. goto error;
  108. }
  109. dir->nr_buffers++;
  110. }
  111. return 0;
  112. error:
  113. adfs_dir_relse(dir);
  114. return -EIO;
  115. }
  116. static int adfs_dir_read(struct super_block *sb, u32 indaddr,
  117. unsigned int size, struct adfs_dir *dir)
  118. {
  119. dir->sb = sb;
  120. dir->bhs = dir->bh;
  121. dir->nr_buffers = 0;
  122. return ADFS_SB(sb)->s_dir->read(sb, indaddr, size, dir);
  123. }
  124. static int adfs_dir_read_inode(struct super_block *sb, struct inode *inode,
  125. struct adfs_dir *dir)
  126. {
  127. int ret;
  128. ret = adfs_dir_read(sb, ADFS_I(inode)->indaddr, inode->i_size, dir);
  129. if (ret)
  130. return ret;
  131. if (ADFS_I(inode)->parent_id != dir->parent_id) {
  132. adfs_error(sb,
  133. "parent directory id changed under me! (%06x but got %06x)\n",
  134. ADFS_I(inode)->parent_id, dir->parent_id);
  135. adfs_dir_relse(dir);
  136. ret = -EIO;
  137. }
  138. return ret;
  139. }
  140. static void adfs_dir_mark_dirty(struct adfs_dir *dir)
  141. {
  142. unsigned int i;
  143. /* Mark the buffers dirty */
  144. for (i = 0; i < dir->nr_buffers; i++)
  145. mark_buffer_dirty(dir->bhs[i]);
  146. }
  147. static int adfs_dir_sync(struct adfs_dir *dir)
  148. {
  149. int err = 0;
  150. int i;
  151. for (i = dir->nr_buffers - 1; i >= 0; i--) {
  152. struct buffer_head *bh = dir->bhs[i];
  153. sync_dirty_buffer(bh);
  154. if (buffer_req(bh) && !buffer_uptodate(bh))
  155. err = -EIO;
  156. }
  157. return err;
  158. }
  159. void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
  160. {
  161. unsigned int dots, i;
  162. /*
  163. * RISC OS allows the use of '/' in directory entry names, so we need
  164. * to fix these up. '/' is typically used for FAT compatibility to
  165. * represent '.', so do the same conversion here. In any case, '.'
  166. * will never be in a RISC OS name since it is used as the pathname
  167. * separator. Handle the case where we may generate a '.' or '..'
  168. * name, replacing the first character with '^' (the RISC OS "parent
  169. * directory" character.)
  170. */
  171. for (i = dots = 0; i < obj->name_len; i++)
  172. if (obj->name[i] == '/') {
  173. obj->name[i] = '.';
  174. dots++;
  175. }
  176. if (obj->name_len <= 2 && dots == obj->name_len)
  177. obj->name[0] = '^';
  178. /*
  179. * If the object is a file, and the user requested the ,xyz hex
  180. * filetype suffix to the name, check the filetype and append.
  181. */
  182. if (!(obj->attr & ADFS_NDA_DIRECTORY) && ADFS_SB(dir->sb)->s_ftsuffix) {
  183. u16 filetype = adfs_filetype(obj->loadaddr);
  184. if (filetype != ADFS_FILETYPE_NONE) {
  185. obj->name[obj->name_len++] = ',';
  186. obj->name[obj->name_len++] = hex_asc_lo(filetype >> 8);
  187. obj->name[obj->name_len++] = hex_asc_lo(filetype >> 4);
  188. obj->name[obj->name_len++] = hex_asc_lo(filetype >> 0);
  189. }
  190. }
  191. }
  192. static int adfs_iterate(struct file *file, struct dir_context *ctx)
  193. {
  194. struct inode *inode = file_inode(file);
  195. struct super_block *sb = inode->i_sb;
  196. const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
  197. struct adfs_dir dir;
  198. int ret;
  199. down_read(&adfs_dir_rwsem);
  200. ret = adfs_dir_read_inode(sb, inode, &dir);
  201. if (ret)
  202. goto unlock;
  203. if (ctx->pos == 0) {
  204. if (!dir_emit_dot(file, ctx))
  205. goto unlock_relse;
  206. ctx->pos = 1;
  207. }
  208. if (ctx->pos == 1) {
  209. if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR))
  210. goto unlock_relse;
  211. ctx->pos = 2;
  212. }
  213. ret = ops->iterate(&dir, ctx);
  214. unlock_relse:
  215. up_read(&adfs_dir_rwsem);
  216. adfs_dir_relse(&dir);
  217. return ret;
  218. unlock:
  219. up_read(&adfs_dir_rwsem);
  220. return ret;
  221. }
  222. int
  223. adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
  224. {
  225. const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
  226. struct adfs_dir dir;
  227. int ret;
  228. if (!IS_ENABLED(CONFIG_ADFS_FS_RW))
  229. return -EINVAL;
  230. if (!ops->update)
  231. return -EINVAL;
  232. down_write(&adfs_dir_rwsem);
  233. ret = adfs_dir_read(sb, obj->parent_id, 0, &dir);
  234. if (ret)
  235. goto unlock;
  236. ret = ops->update(&dir, obj);
  237. if (ret)
  238. goto forget;
  239. ret = ops->commit(&dir);
  240. if (ret)
  241. goto forget;
  242. up_write(&adfs_dir_rwsem);
  243. adfs_dir_mark_dirty(&dir);
  244. if (wait)
  245. ret = adfs_dir_sync(&dir);
  246. adfs_dir_relse(&dir);
  247. return ret;
  248. /*
  249. * If the updated failed because the entry wasn't found, we can
  250. * just release the buffers. If it was any other error, forget
  251. * the dirtied buffers so they aren't written back to the media.
  252. */
  253. forget:
  254. if (ret == -ENOENT)
  255. adfs_dir_relse(&dir);
  256. else
  257. adfs_dir_forget(&dir);
  258. unlock:
  259. up_write(&adfs_dir_rwsem);
  260. return ret;
  261. }
  262. static unsigned char adfs_tolower(unsigned char c)
  263. {
  264. if (c >= 'A' && c <= 'Z')
  265. c += 'a' - 'A';
  266. return c;
  267. }
  268. static int __adfs_compare(const unsigned char *qstr, u32 qlen,
  269. const char *str, u32 len)
  270. {
  271. u32 i;
  272. if (qlen != len)
  273. return 1;
  274. for (i = 0; i < qlen; i++)
  275. if (adfs_tolower(qstr[i]) != adfs_tolower(str[i]))
  276. return 1;
  277. return 0;
  278. }
  279. static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
  280. struct object_info *obj)
  281. {
  282. struct super_block *sb = inode->i_sb;
  283. const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
  284. const unsigned char *name;
  285. struct adfs_dir dir;
  286. u32 name_len;
  287. int ret;
  288. down_read(&adfs_dir_rwsem);
  289. ret = adfs_dir_read_inode(sb, inode, &dir);
  290. if (ret)
  291. goto unlock;
  292. ret = ops->setpos(&dir, 0);
  293. if (ret)
  294. goto unlock_relse;
  295. ret = -ENOENT;
  296. name = qstr->name;
  297. name_len = qstr->len;
  298. while (ops->getnext(&dir, obj) == 0) {
  299. if (!__adfs_compare(name, name_len, obj->name, obj->name_len)) {
  300. ret = 0;
  301. break;
  302. }
  303. }
  304. obj->parent_id = ADFS_I(inode)->indaddr;
  305. unlock_relse:
  306. up_read(&adfs_dir_rwsem);
  307. adfs_dir_relse(&dir);
  308. return ret;
  309. unlock:
  310. up_read(&adfs_dir_rwsem);
  311. return ret;
  312. }
  313. const struct file_operations adfs_dir_operations = {
  314. .read = generic_read_dir,
  315. .llseek = generic_file_llseek,
  316. .iterate_shared = adfs_iterate,
  317. .fsync = generic_file_fsync,
  318. };
  319. static int
  320. adfs_hash(const struct dentry *parent, struct qstr *qstr)
  321. {
  322. const unsigned char *name;
  323. unsigned long hash;
  324. u32 len;
  325. if (qstr->len > ADFS_SB(parent->d_sb)->s_namelen)
  326. return -ENAMETOOLONG;
  327. len = qstr->len;
  328. name = qstr->name;
  329. hash = init_name_hash(parent);
  330. while (len--)
  331. hash = partial_name_hash(adfs_tolower(*name++), hash);
  332. qstr->hash = end_name_hash(hash);
  333. return 0;
  334. }
  335. /*
  336. * Compare two names, taking note of the name length
  337. * requirements of the underlying filesystem.
  338. */
  339. static int adfs_compare(const struct dentry *dentry, unsigned int len,
  340. const char *str, const struct qstr *qstr)
  341. {
  342. return __adfs_compare(qstr->name, qstr->len, str, len);
  343. }
  344. const struct dentry_operations adfs_dentry_operations = {
  345. .d_hash = adfs_hash,
  346. .d_compare = adfs_compare,
  347. };
  348. static struct dentry *
  349. adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
  350. {
  351. struct inode *inode = NULL;
  352. struct object_info obj;
  353. int error;
  354. error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
  355. if (error == 0) {
  356. /*
  357. * This only returns NULL if get_empty_inode
  358. * fails.
  359. */
  360. inode = adfs_iget(dir->i_sb, &obj);
  361. if (!inode)
  362. inode = ERR_PTR(-EACCES);
  363. } else if (error != -ENOENT) {
  364. inode = ERR_PTR(error);
  365. }
  366. return d_splice_alias(inode, dentry);
  367. }
  368. /*
  369. * directories can handle most operations...
  370. */
  371. const struct inode_operations adfs_dir_inode_operations = {
  372. .lookup = adfs_lookup,
  373. .setattr = adfs_notify_change,
  374. };