namei.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include "internal.h"
  3. #define makedev(major, minor) ((dev_t)((((major) & 0xfff) << 8) | ((minor) & 0xff)))
  4. static dev_t erofs_new_decode_dev(u32 dev)
  5. {
  6. const unsigned int major = (dev & 0xfff00) >> 8;
  7. const unsigned int minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
  8. return makedev(major, minor);
  9. }
  10. int erofs_read_inode_from_disk(struct erofs_inode *vi)
  11. {
  12. int ret, ifmt;
  13. char buf[sizeof(struct erofs_inode_extended)];
  14. struct erofs_inode_compact *dic;
  15. struct erofs_inode_extended *die;
  16. const erofs_off_t inode_loc = iloc(vi->nid);
  17. ret = erofs_dev_read(0, buf, inode_loc, sizeof(*dic));
  18. if (ret < 0)
  19. return -EIO;
  20. dic = (struct erofs_inode_compact *)buf;
  21. ifmt = le16_to_cpu(dic->i_format);
  22. vi->datalayout = erofs_inode_datalayout(ifmt);
  23. if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
  24. erofs_err("unsupported datalayout %u of nid %llu",
  25. vi->datalayout, vi->nid | 0ULL);
  26. return -EOPNOTSUPP;
  27. }
  28. switch (erofs_inode_version(ifmt)) {
  29. case EROFS_INODE_LAYOUT_EXTENDED:
  30. vi->inode_isize = sizeof(struct erofs_inode_extended);
  31. ret = erofs_dev_read(0, buf + sizeof(*dic),
  32. inode_loc + sizeof(*dic),
  33. sizeof(*die) - sizeof(*dic));
  34. if (ret < 0)
  35. return -EIO;
  36. die = (struct erofs_inode_extended *)buf;
  37. vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
  38. vi->i_mode = le16_to_cpu(die->i_mode);
  39. switch (vi->i_mode & S_IFMT) {
  40. case S_IFREG:
  41. case S_IFDIR:
  42. case S_IFLNK:
  43. vi->u.i_blkaddr = le32_to_cpu(die->i_u.raw_blkaddr);
  44. break;
  45. case S_IFCHR:
  46. case S_IFBLK:
  47. vi->u.i_rdev =
  48. erofs_new_decode_dev(le32_to_cpu(die->i_u.rdev));
  49. break;
  50. case S_IFIFO:
  51. case S_IFSOCK:
  52. vi->u.i_rdev = 0;
  53. break;
  54. default:
  55. goto bogusimode;
  56. }
  57. vi->i_uid = le32_to_cpu(die->i_uid);
  58. vi->i_gid = le32_to_cpu(die->i_gid);
  59. vi->i_nlink = le32_to_cpu(die->i_nlink);
  60. vi->i_mtime = le64_to_cpu(die->i_mtime);
  61. vi->i_mtime_nsec = le64_to_cpu(die->i_mtime_nsec);
  62. vi->i_size = le64_to_cpu(die->i_size);
  63. if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
  64. /* fill chunked inode summary info */
  65. vi->u.chunkformat = le16_to_cpu(die->i_u.c.format);
  66. break;
  67. case EROFS_INODE_LAYOUT_COMPACT:
  68. vi->inode_isize = sizeof(struct erofs_inode_compact);
  69. vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);
  70. vi->i_mode = le16_to_cpu(dic->i_mode);
  71. switch (vi->i_mode & S_IFMT) {
  72. case S_IFREG:
  73. case S_IFDIR:
  74. case S_IFLNK:
  75. vi->u.i_blkaddr = le32_to_cpu(dic->i_u.raw_blkaddr);
  76. break;
  77. case S_IFCHR:
  78. case S_IFBLK:
  79. vi->u.i_rdev =
  80. erofs_new_decode_dev(le32_to_cpu(dic->i_u.rdev));
  81. break;
  82. case S_IFIFO:
  83. case S_IFSOCK:
  84. vi->u.i_rdev = 0;
  85. break;
  86. default:
  87. goto bogusimode;
  88. }
  89. vi->i_uid = le16_to_cpu(dic->i_uid);
  90. vi->i_gid = le16_to_cpu(dic->i_gid);
  91. vi->i_nlink = le16_to_cpu(dic->i_nlink);
  92. vi->i_mtime = sbi.build_time;
  93. vi->i_mtime_nsec = sbi.build_time_nsec;
  94. vi->i_size = le32_to_cpu(dic->i_size);
  95. if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
  96. vi->u.chunkformat = le16_to_cpu(dic->i_u.c.format);
  97. break;
  98. default:
  99. erofs_err("unsupported on-disk inode version %u of nid %llu",
  100. erofs_inode_version(ifmt), vi->nid | 0ULL);
  101. return -EOPNOTSUPP;
  102. }
  103. vi->flags = 0;
  104. if (vi->datalayout == EROFS_INODE_CHUNK_BASED) {
  105. if (vi->u.chunkformat & ~EROFS_CHUNK_FORMAT_ALL) {
  106. erofs_err("unsupported chunk format %x of nid %llu",
  107. vi->u.chunkformat, vi->nid | 0ULL);
  108. return -EOPNOTSUPP;
  109. }
  110. vi->u.chunkbits = sbi.blkszbits +
  111. (vi->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
  112. } else if (erofs_inode_is_data_compressed(vi->datalayout)) {
  113. if (erofs_blksiz() != EROFS_MAX_BLOCK_SIZE)
  114. return -EOPNOTSUPP;
  115. return z_erofs_fill_inode(vi);
  116. }
  117. return 0;
  118. bogusimode:
  119. erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode, vi->nid | 0ULL);
  120. return -EFSCORRUPTED;
  121. }
  122. struct erofs_dirent *find_target_dirent(erofs_nid_t pnid,
  123. void *dentry_blk,
  124. const char *name, unsigned int len,
  125. unsigned int nameoff,
  126. unsigned int maxsize)
  127. {
  128. struct erofs_dirent *de = dentry_blk;
  129. const struct erofs_dirent *end = dentry_blk + nameoff;
  130. while (de < end) {
  131. const char *de_name;
  132. unsigned int de_namelen;
  133. nameoff = le16_to_cpu(de->nameoff);
  134. de_name = (char *)dentry_blk + nameoff;
  135. /* the last dirent in the block? */
  136. if (de + 1 >= end)
  137. de_namelen = strnlen(de_name, maxsize - nameoff);
  138. else
  139. de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
  140. /* a corrupted entry is found */
  141. if (nameoff + de_namelen > maxsize ||
  142. de_namelen > EROFS_NAME_LEN) {
  143. erofs_err("bogus dirent @ nid %llu", pnid | 0ULL);
  144. DBG_BUGON(1);
  145. return ERR_PTR(-EFSCORRUPTED);
  146. }
  147. if (len == de_namelen && !memcmp(de_name, name, de_namelen))
  148. return de;
  149. ++de;
  150. }
  151. return NULL;
  152. }
  153. struct nameidata {
  154. erofs_nid_t nid;
  155. unsigned int ftype;
  156. };
  157. int erofs_namei(struct nameidata *nd, const char *name, unsigned int len)
  158. {
  159. erofs_nid_t nid = nd->nid;
  160. int ret;
  161. char buf[EROFS_MAX_BLOCK_SIZE];
  162. struct erofs_inode vi = { .nid = nid };
  163. erofs_off_t offset;
  164. ret = erofs_read_inode_from_disk(&vi);
  165. if (ret)
  166. return ret;
  167. offset = 0;
  168. while (offset < vi.i_size) {
  169. erofs_off_t maxsize = min_t(erofs_off_t,
  170. vi.i_size - offset, erofs_blksiz());
  171. struct erofs_dirent *de = (void *)buf;
  172. unsigned int nameoff;
  173. ret = erofs_pread(&vi, buf, maxsize, offset);
  174. if (ret)
  175. return ret;
  176. nameoff = le16_to_cpu(de->nameoff);
  177. if (nameoff < sizeof(struct erofs_dirent) ||
  178. nameoff >= erofs_blksiz()) {
  179. erofs_err("invalid de[0].nameoff %u @ nid %llu",
  180. nameoff, nid | 0ULL);
  181. return -EFSCORRUPTED;
  182. }
  183. de = find_target_dirent(nid, buf, name, len,
  184. nameoff, maxsize);
  185. if (IS_ERR(de))
  186. return PTR_ERR(de);
  187. if (de) {
  188. nd->nid = le64_to_cpu(de->nid);
  189. return 0;
  190. }
  191. offset += maxsize;
  192. }
  193. return -ENOENT;
  194. }
  195. static int link_path_walk(const char *name, struct nameidata *nd)
  196. {
  197. nd->nid = sbi.root_nid;
  198. while (*name == '/')
  199. name++;
  200. /* At this point we know we have a real path component. */
  201. while (*name != '\0') {
  202. const char *p = name;
  203. int ret;
  204. do {
  205. ++p;
  206. } while (*p != '\0' && *p != '/');
  207. DBG_BUGON(p <= name);
  208. ret = erofs_namei(nd, name, p - name);
  209. if (ret)
  210. return ret;
  211. name = p;
  212. /* Skip until no more slashes. */
  213. for (name = p; *name == '/'; ++name)
  214. ;
  215. }
  216. return 0;
  217. }
  218. int erofs_ilookup(const char *path, struct erofs_inode *vi)
  219. {
  220. int ret;
  221. struct nameidata nd;
  222. ret = link_path_walk(path, &nd);
  223. if (ret)
  224. return ret;
  225. vi->nid = nd.nid;
  226. return erofs_read_inode_from_disk(vi);
  227. }