dir.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2017-2018 HUAWEI, Inc.
  4. * https://www.huawei.com/
  5. * Copyright (C) 2022, Alibaba Cloud
  6. */
  7. #include "internal.h"
  8. static void debug_one_dentry(unsigned char d_type, const char *de_name,
  9. unsigned int de_namelen)
  10. {
  11. #ifdef CONFIG_EROFS_FS_DEBUG
  12. /* since the on-disk name could not have the trailing '\0' */
  13. unsigned char dbg_namebuf[EROFS_NAME_LEN + 1];
  14. memcpy(dbg_namebuf, de_name, de_namelen);
  15. dbg_namebuf[de_namelen] = '\0';
  16. erofs_dbg("found dirent %s de_len %u d_type %d", dbg_namebuf,
  17. de_namelen, d_type);
  18. #endif
  19. }
  20. static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
  21. void *dentry_blk, struct erofs_dirent *de,
  22. unsigned int nameoff, unsigned int maxsize)
  23. {
  24. const struct erofs_dirent *end = dentry_blk + nameoff;
  25. while (de < end) {
  26. const char *de_name;
  27. unsigned int de_namelen;
  28. unsigned char d_type;
  29. d_type = fs_ftype_to_dtype(de->file_type);
  30. nameoff = le16_to_cpu(de->nameoff);
  31. de_name = (char *)dentry_blk + nameoff;
  32. /* the last dirent in the block? */
  33. if (de + 1 >= end)
  34. de_namelen = strnlen(de_name, maxsize - nameoff);
  35. else
  36. de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
  37. /* a corrupted entry is found */
  38. if (nameoff + de_namelen > maxsize ||
  39. de_namelen > EROFS_NAME_LEN) {
  40. erofs_err(dir->i_sb, "bogus dirent @ nid %llu",
  41. EROFS_I(dir)->nid);
  42. DBG_BUGON(1);
  43. return -EFSCORRUPTED;
  44. }
  45. debug_one_dentry(d_type, de_name, de_namelen);
  46. if (!dir_emit(ctx, de_name, de_namelen,
  47. le64_to_cpu(de->nid), d_type))
  48. /* stopped by some reason */
  49. return 1;
  50. ++de;
  51. ctx->pos += sizeof(struct erofs_dirent);
  52. }
  53. return 0;
  54. }
  55. static int erofs_readdir(struct file *f, struct dir_context *ctx)
  56. {
  57. struct inode *dir = file_inode(f);
  58. struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
  59. struct super_block *sb = dir->i_sb;
  60. unsigned long bsz = sb->s_blocksize;
  61. const size_t dirsize = i_size_read(dir);
  62. unsigned int i = erofs_blknr(sb, ctx->pos);
  63. unsigned int ofs = erofs_blkoff(sb, ctx->pos);
  64. int err = 0;
  65. bool initial = true;
  66. while (ctx->pos < dirsize) {
  67. struct erofs_dirent *de;
  68. unsigned int nameoff, maxsize;
  69. de = erofs_bread(&buf, dir, i, EROFS_KMAP);
  70. if (IS_ERR(de)) {
  71. erofs_err(sb, "fail to readdir of logical block %u of nid %llu",
  72. i, EROFS_I(dir)->nid);
  73. err = PTR_ERR(de);
  74. break;
  75. }
  76. nameoff = le16_to_cpu(de->nameoff);
  77. if (nameoff < sizeof(struct erofs_dirent) || nameoff >= bsz) {
  78. erofs_err(sb, "invalid de[0].nameoff %u @ nid %llu",
  79. nameoff, EROFS_I(dir)->nid);
  80. err = -EFSCORRUPTED;
  81. break;
  82. }
  83. maxsize = min_t(unsigned int, dirsize - ctx->pos + ofs, bsz);
  84. /* search dirents at the arbitrary position */
  85. if (initial) {
  86. initial = false;
  87. ofs = roundup(ofs, sizeof(struct erofs_dirent));
  88. ctx->pos = erofs_pos(sb, i) + ofs;
  89. if (ofs >= nameoff)
  90. goto skip_this;
  91. }
  92. err = erofs_fill_dentries(dir, ctx, de, (void *)de + ofs,
  93. nameoff, maxsize);
  94. if (err)
  95. break;
  96. skip_this:
  97. ctx->pos = erofs_pos(sb, i) + maxsize;
  98. ++i;
  99. ofs = 0;
  100. }
  101. erofs_put_metabuf(&buf);
  102. return err < 0 ? err : 0;
  103. }
  104. const struct file_operations erofs_dir_fops = {
  105. .llseek = generic_file_llseek,
  106. .read = generic_read_dir,
  107. .iterate_shared = erofs_readdir,
  108. };