dir.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * linux/fs/hfsplus/dir.c
  4. *
  5. * Copyright (C) 2001
  6. * Brad Boyer (flar@allandria.com)
  7. * (C) 2003 Ardis Technologies <roman@ardistech.com>
  8. *
  9. * Handling of directories
  10. */
  11. #include <linux/errno.h>
  12. #include <linux/fs.h>
  13. #include <linux/slab.h>
  14. #include <linux/random.h>
  15. #include <linux/nls.h>
  16. #include "hfsplus_fs.h"
  17. #include "hfsplus_raw.h"
  18. #include "xattr.h"
  19. static inline void hfsplus_instantiate(struct dentry *dentry,
  20. struct inode *inode, u32 cnid)
  21. {
  22. dentry->d_fsdata = (void *)(unsigned long)cnid;
  23. d_instantiate(dentry, inode);
  24. }
  25. /* Find the entry inside dir named dentry->d_name */
  26. static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
  27. unsigned int flags)
  28. {
  29. struct inode *inode = NULL;
  30. struct hfs_find_data fd;
  31. struct super_block *sb;
  32. hfsplus_cat_entry entry;
  33. int err;
  34. u32 cnid, linkid = 0;
  35. u16 type;
  36. sb = dir->i_sb;
  37. dentry->d_fsdata = NULL;
  38. err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
  39. if (err)
  40. return ERR_PTR(err);
  41. err = hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino,
  42. &dentry->d_name);
  43. if (unlikely(err < 0))
  44. goto fail;
  45. again:
  46. err = hfs_brec_read(&fd, &entry, sizeof(entry));
  47. if (err) {
  48. if (err == -ENOENT) {
  49. hfs_find_exit(&fd);
  50. /* No such entry */
  51. inode = NULL;
  52. goto out;
  53. }
  54. goto fail;
  55. }
  56. type = be16_to_cpu(entry.type);
  57. if (type == HFSPLUS_FOLDER) {
  58. if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) {
  59. err = -EIO;
  60. goto fail;
  61. }
  62. cnid = be32_to_cpu(entry.folder.id);
  63. dentry->d_fsdata = (void *)(unsigned long)cnid;
  64. } else if (type == HFSPLUS_FILE) {
  65. if (fd.entrylength < sizeof(struct hfsplus_cat_file)) {
  66. err = -EIO;
  67. goto fail;
  68. }
  69. cnid = be32_to_cpu(entry.file.id);
  70. if (entry.file.user_info.fdType ==
  71. cpu_to_be32(HFSP_HARDLINK_TYPE) &&
  72. entry.file.user_info.fdCreator ==
  73. cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
  74. HFSPLUS_SB(sb)->hidden_dir &&
  75. (entry.file.create_date ==
  76. HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->
  77. create_date ||
  78. entry.file.create_date ==
  79. HFSPLUS_I(d_inode(sb->s_root))->
  80. create_date)) {
  81. struct qstr str;
  82. char name[32];
  83. if (dentry->d_fsdata) {
  84. /*
  85. * We found a link pointing to another link,
  86. * so ignore it and treat it as regular file.
  87. */
  88. cnid = (unsigned long)dentry->d_fsdata;
  89. linkid = 0;
  90. } else {
  91. dentry->d_fsdata = (void *)(unsigned long)cnid;
  92. linkid =
  93. be32_to_cpu(entry.file.permissions.dev);
  94. str.len = sprintf(name, "iNode%d", linkid);
  95. str.name = name;
  96. err = hfsplus_cat_build_key(sb, fd.search_key,
  97. HFSPLUS_SB(sb)->hidden_dir->i_ino,
  98. &str);
  99. if (unlikely(err < 0))
  100. goto fail;
  101. goto again;
  102. }
  103. } else if (!dentry->d_fsdata)
  104. dentry->d_fsdata = (void *)(unsigned long)cnid;
  105. } else {
  106. pr_err("invalid catalog entry type in lookup\n");
  107. err = -EIO;
  108. goto fail;
  109. }
  110. hfs_find_exit(&fd);
  111. inode = hfsplus_iget(dir->i_sb, cnid);
  112. if (IS_ERR(inode))
  113. return ERR_CAST(inode);
  114. if (S_ISREG(inode->i_mode))
  115. HFSPLUS_I(inode)->linkid = linkid;
  116. out:
  117. return d_splice_alias(inode, dentry);
  118. fail:
  119. hfs_find_exit(&fd);
  120. return ERR_PTR(err);
  121. }
  122. static int hfsplus_readdir(struct file *file, struct dir_context *ctx)
  123. {
  124. struct inode *inode = file_inode(file);
  125. struct super_block *sb = inode->i_sb;
  126. int len, err;
  127. char *strbuf;
  128. hfsplus_cat_entry entry;
  129. struct hfs_find_data fd;
  130. struct hfsplus_readdir_data *rd;
  131. u16 type;
  132. if (file->f_pos >= inode->i_size)
  133. return 0;
  134. err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
  135. if (err)
  136. return err;
  137. strbuf = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_MAX_STRLEN + 1, GFP_KERNEL);
  138. if (!strbuf) {
  139. err = -ENOMEM;
  140. goto out;
  141. }
  142. hfsplus_cat_build_key_with_cnid(sb, fd.search_key, inode->i_ino);
  143. err = hfs_brec_find(&fd, hfs_find_rec_by_key);
  144. if (err)
  145. goto out;
  146. if (ctx->pos == 0) {
  147. /* This is completely artificial... */
  148. if (!dir_emit_dot(file, ctx))
  149. goto out;
  150. ctx->pos = 1;
  151. }
  152. if (ctx->pos == 1) {
  153. if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
  154. err = -EIO;
  155. goto out;
  156. }
  157. hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
  158. fd.entrylength);
  159. if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
  160. pr_err("bad catalog folder thread\n");
  161. err = -EIO;
  162. goto out;
  163. }
  164. if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) {
  165. pr_err("truncated catalog thread\n");
  166. err = -EIO;
  167. goto out;
  168. }
  169. if (!dir_emit(ctx, "..", 2,
  170. be32_to_cpu(entry.thread.parentID), DT_DIR))
  171. goto out;
  172. ctx->pos = 2;
  173. }
  174. if (ctx->pos >= inode->i_size)
  175. goto out;
  176. err = hfs_brec_goto(&fd, ctx->pos - 1);
  177. if (err)
  178. goto out;
  179. for (;;) {
  180. if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) {
  181. pr_err("walked past end of dir\n");
  182. err = -EIO;
  183. goto out;
  184. }
  185. if (fd.entrylength > sizeof(entry) || fd.entrylength < 0) {
  186. err = -EIO;
  187. goto out;
  188. }
  189. hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
  190. fd.entrylength);
  191. type = be16_to_cpu(entry.type);
  192. len = NLS_MAX_CHARSET_SIZE * HFSPLUS_MAX_STRLEN;
  193. err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
  194. if (err)
  195. goto out;
  196. if (type == HFSPLUS_FOLDER) {
  197. if (fd.entrylength <
  198. sizeof(struct hfsplus_cat_folder)) {
  199. pr_err("small dir entry\n");
  200. err = -EIO;
  201. goto out;
  202. }
  203. if (HFSPLUS_SB(sb)->hidden_dir &&
  204. HFSPLUS_SB(sb)->hidden_dir->i_ino ==
  205. be32_to_cpu(entry.folder.id))
  206. goto next;
  207. if (!dir_emit(ctx, strbuf, len,
  208. be32_to_cpu(entry.folder.id), DT_DIR))
  209. break;
  210. } else if (type == HFSPLUS_FILE) {
  211. u16 mode;
  212. unsigned type = DT_UNKNOWN;
  213. if (fd.entrylength < sizeof(struct hfsplus_cat_file)) {
  214. pr_err("small file entry\n");
  215. err = -EIO;
  216. goto out;
  217. }
  218. mode = be16_to_cpu(entry.file.permissions.mode);
  219. if (S_ISREG(mode))
  220. type = DT_REG;
  221. else if (S_ISLNK(mode))
  222. type = DT_LNK;
  223. else if (S_ISFIFO(mode))
  224. type = DT_FIFO;
  225. else if (S_ISCHR(mode))
  226. type = DT_CHR;
  227. else if (S_ISBLK(mode))
  228. type = DT_BLK;
  229. else if (S_ISSOCK(mode))
  230. type = DT_SOCK;
  231. if (!dir_emit(ctx, strbuf, len,
  232. be32_to_cpu(entry.file.id), type))
  233. break;
  234. } else {
  235. pr_err("bad catalog entry type\n");
  236. err = -EIO;
  237. goto out;
  238. }
  239. next:
  240. ctx->pos++;
  241. if (ctx->pos >= inode->i_size)
  242. goto out;
  243. err = hfs_brec_goto(&fd, 1);
  244. if (err)
  245. goto out;
  246. }
  247. rd = file->private_data;
  248. if (!rd) {
  249. rd = kmalloc(sizeof(struct hfsplus_readdir_data), GFP_KERNEL);
  250. if (!rd) {
  251. err = -ENOMEM;
  252. goto out;
  253. }
  254. file->private_data = rd;
  255. rd->file = file;
  256. spin_lock(&HFSPLUS_I(inode)->open_dir_lock);
  257. list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
  258. spin_unlock(&HFSPLUS_I(inode)->open_dir_lock);
  259. }
  260. /*
  261. * Can be done after the list insertion; exclusion with
  262. * hfsplus_delete_cat() is provided by directory lock.
  263. */
  264. memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key));
  265. out:
  266. kfree(strbuf);
  267. hfs_find_exit(&fd);
  268. return err;
  269. }
  270. static int hfsplus_dir_release(struct inode *inode, struct file *file)
  271. {
  272. struct hfsplus_readdir_data *rd = file->private_data;
  273. if (rd) {
  274. spin_lock(&HFSPLUS_I(inode)->open_dir_lock);
  275. list_del(&rd->list);
  276. spin_unlock(&HFSPLUS_I(inode)->open_dir_lock);
  277. kfree(rd);
  278. }
  279. return 0;
  280. }
  281. static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
  282. struct dentry *dst_dentry)
  283. {
  284. struct hfsplus_sb_info *sbi = HFSPLUS_SB(dst_dir->i_sb);
  285. struct inode *inode = d_inode(src_dentry);
  286. struct inode *src_dir = d_inode(src_dentry->d_parent);
  287. struct qstr str;
  288. char name[32];
  289. u32 cnid, id;
  290. int res;
  291. if (HFSPLUS_IS_RSRC(inode))
  292. return -EPERM;
  293. if (!S_ISREG(inode->i_mode))
  294. return -EPERM;
  295. mutex_lock(&sbi->vh_mutex);
  296. if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) {
  297. for (;;) {
  298. get_random_bytes(&id, sizeof(cnid));
  299. id &= 0x3fffffff;
  300. str.name = name;
  301. str.len = sprintf(name, "iNode%d", id);
  302. res = hfsplus_rename_cat(inode->i_ino,
  303. src_dir, &src_dentry->d_name,
  304. sbi->hidden_dir, &str);
  305. if (!res)
  306. break;
  307. if (res != -EEXIST)
  308. goto out;
  309. }
  310. HFSPLUS_I(inode)->linkid = id;
  311. cnid = sbi->next_cnid++;
  312. src_dentry->d_fsdata = (void *)(unsigned long)cnid;
  313. res = hfsplus_create_cat(cnid, src_dir,
  314. &src_dentry->d_name, inode);
  315. if (res)
  316. /* panic? */
  317. goto out;
  318. sbi->file_count++;
  319. }
  320. cnid = sbi->next_cnid++;
  321. res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode);
  322. if (res)
  323. goto out;
  324. inc_nlink(inode);
  325. hfsplus_instantiate(dst_dentry, inode, cnid);
  326. ihold(inode);
  327. inode->i_ctime = current_time(inode);
  328. mark_inode_dirty(inode);
  329. sbi->file_count++;
  330. hfsplus_mark_mdb_dirty(dst_dir->i_sb);
  331. out:
  332. mutex_unlock(&sbi->vh_mutex);
  333. return res;
  334. }
  335. static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
  336. {
  337. struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
  338. struct inode *inode = d_inode(dentry);
  339. struct qstr str;
  340. char name[32];
  341. u32 cnid;
  342. int res;
  343. if (HFSPLUS_IS_RSRC(inode))
  344. return -EPERM;
  345. mutex_lock(&sbi->vh_mutex);
  346. cnid = (u32)(unsigned long)dentry->d_fsdata;
  347. if (inode->i_ino == cnid &&
  348. atomic_read(&HFSPLUS_I(inode)->opencnt)) {
  349. str.name = name;
  350. str.len = sprintf(name, "temp%lu", inode->i_ino);
  351. res = hfsplus_rename_cat(inode->i_ino,
  352. dir, &dentry->d_name,
  353. sbi->hidden_dir, &str);
  354. if (!res) {
  355. inode->i_flags |= S_DEAD;
  356. drop_nlink(inode);
  357. }
  358. goto out;
  359. }
  360. res = hfsplus_delete_cat(cnid, dir, &dentry->d_name);
  361. if (res)
  362. goto out;
  363. if (inode->i_nlink > 0)
  364. drop_nlink(inode);
  365. if (inode->i_ino == cnid)
  366. clear_nlink(inode);
  367. if (!inode->i_nlink) {
  368. if (inode->i_ino != cnid) {
  369. sbi->file_count--;
  370. if (!atomic_read(&HFSPLUS_I(inode)->opencnt)) {
  371. res = hfsplus_delete_cat(inode->i_ino,
  372. sbi->hidden_dir,
  373. NULL);
  374. if (!res)
  375. hfsplus_delete_inode(inode);
  376. } else
  377. inode->i_flags |= S_DEAD;
  378. } else
  379. hfsplus_delete_inode(inode);
  380. } else
  381. sbi->file_count--;
  382. inode->i_ctime = current_time(inode);
  383. mark_inode_dirty(inode);
  384. out:
  385. mutex_unlock(&sbi->vh_mutex);
  386. return res;
  387. }
  388. static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
  389. {
  390. struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
  391. struct inode *inode = d_inode(dentry);
  392. int res;
  393. if (inode->i_size != 2)
  394. return -ENOTEMPTY;
  395. mutex_lock(&sbi->vh_mutex);
  396. res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
  397. if (res)
  398. goto out;
  399. clear_nlink(inode);
  400. inode->i_ctime = current_time(inode);
  401. hfsplus_delete_inode(inode);
  402. mark_inode_dirty(inode);
  403. out:
  404. mutex_unlock(&sbi->vh_mutex);
  405. return res;
  406. }
  407. static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
  408. const char *symname)
  409. {
  410. struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
  411. struct inode *inode;
  412. int res = -ENOMEM;
  413. mutex_lock(&sbi->vh_mutex);
  414. inode = hfsplus_new_inode(dir->i_sb, dir, S_IFLNK | S_IRWXUGO);
  415. if (!inode)
  416. goto out;
  417. res = page_symlink(inode, symname, strlen(symname) + 1);
  418. if (res)
  419. goto out_err;
  420. res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
  421. if (res)
  422. goto out_err;
  423. res = hfsplus_init_security(inode, dir, &dentry->d_name);
  424. if (res == -EOPNOTSUPP)
  425. res = 0; /* Operation is not supported. */
  426. else if (res) {
  427. /* Try to delete anyway without error analysis. */
  428. hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
  429. goto out_err;
  430. }
  431. hfsplus_instantiate(dentry, inode, inode->i_ino);
  432. mark_inode_dirty(inode);
  433. goto out;
  434. out_err:
  435. clear_nlink(inode);
  436. hfsplus_delete_inode(inode);
  437. iput(inode);
  438. out:
  439. mutex_unlock(&sbi->vh_mutex);
  440. return res;
  441. }
  442. static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
  443. umode_t mode, dev_t rdev)
  444. {
  445. struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
  446. struct inode *inode;
  447. int res = -ENOMEM;
  448. mutex_lock(&sbi->vh_mutex);
  449. inode = hfsplus_new_inode(dir->i_sb, dir, mode);
  450. if (!inode)
  451. goto out;
  452. if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
  453. init_special_inode(inode, mode, rdev);
  454. res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
  455. if (res)
  456. goto failed_mknod;
  457. res = hfsplus_init_security(inode, dir, &dentry->d_name);
  458. if (res == -EOPNOTSUPP)
  459. res = 0; /* Operation is not supported. */
  460. else if (res) {
  461. /* Try to delete anyway without error analysis. */
  462. hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
  463. goto failed_mknod;
  464. }
  465. hfsplus_instantiate(dentry, inode, inode->i_ino);
  466. mark_inode_dirty(inode);
  467. goto out;
  468. failed_mknod:
  469. clear_nlink(inode);
  470. hfsplus_delete_inode(inode);
  471. iput(inode);
  472. out:
  473. mutex_unlock(&sbi->vh_mutex);
  474. return res;
  475. }
  476. static int hfsplus_create(struct inode *dir, struct dentry *dentry, umode_t mode,
  477. bool excl)
  478. {
  479. return hfsplus_mknod(dir, dentry, mode, 0);
  480. }
  481. static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
  482. {
  483. return hfsplus_mknod(dir, dentry, mode | S_IFDIR, 0);
  484. }
  485. static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
  486. struct inode *new_dir, struct dentry *new_dentry,
  487. unsigned int flags)
  488. {
  489. int res;
  490. if (flags & ~RENAME_NOREPLACE)
  491. return -EINVAL;
  492. /* Unlink destination if it already exists */
  493. if (d_really_is_positive(new_dentry)) {
  494. if (d_is_dir(new_dentry))
  495. res = hfsplus_rmdir(new_dir, new_dentry);
  496. else
  497. res = hfsplus_unlink(new_dir, new_dentry);
  498. if (res)
  499. return res;
  500. }
  501. res = hfsplus_rename_cat((u32)(unsigned long)old_dentry->d_fsdata,
  502. old_dir, &old_dentry->d_name,
  503. new_dir, &new_dentry->d_name);
  504. if (!res)
  505. new_dentry->d_fsdata = old_dentry->d_fsdata;
  506. return res;
  507. }
  508. const struct inode_operations hfsplus_dir_inode_operations = {
  509. .lookup = hfsplus_lookup,
  510. .create = hfsplus_create,
  511. .link = hfsplus_link,
  512. .unlink = hfsplus_unlink,
  513. .mkdir = hfsplus_mkdir,
  514. .rmdir = hfsplus_rmdir,
  515. .symlink = hfsplus_symlink,
  516. .mknod = hfsplus_mknod,
  517. .rename = hfsplus_rename,
  518. .listxattr = hfsplus_listxattr,
  519. };
  520. const struct file_operations hfsplus_dir_operations = {
  521. .fsync = hfsplus_file_fsync,
  522. .read = generic_read_dir,
  523. .iterate_shared = hfsplus_readdir,
  524. .unlocked_ioctl = hfsplus_ioctl,
  525. .llseek = generic_file_llseek,
  526. .release = hfsplus_dir_release,
  527. };