fs.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include "internal.h"
  3. #include <fs_internal.h>
  4. struct erofs_sb_info sbi;
  5. static struct erofs_ctxt {
  6. struct disk_partition cur_part_info;
  7. struct blk_desc *cur_dev;
  8. } ctxt;
  9. int erofs_dev_read(int device_id, void *buf, u64 offset, size_t len)
  10. {
  11. lbaint_t sect = offset >> ctxt.cur_dev->log2blksz;
  12. int off = offset & (ctxt.cur_dev->blksz - 1);
  13. if (!ctxt.cur_dev)
  14. return -EIO;
  15. if (fs_devread(ctxt.cur_dev, &ctxt.cur_part_info, sect,
  16. off, len, buf))
  17. return 0;
  18. return -EIO;
  19. }
  20. int erofs_blk_read(void *buf, erofs_blk_t start, u32 nblocks)
  21. {
  22. return erofs_dev_read(0, buf, erofs_pos(start),
  23. erofs_pos(nblocks));
  24. }
  25. int erofs_probe(struct blk_desc *fs_dev_desc,
  26. struct disk_partition *fs_partition)
  27. {
  28. int ret;
  29. ctxt.cur_dev = fs_dev_desc;
  30. ctxt.cur_part_info = *fs_partition;
  31. ret = erofs_read_superblock();
  32. if (ret)
  33. goto error;
  34. return 0;
  35. error:
  36. ctxt.cur_dev = NULL;
  37. return ret;
  38. }
  39. struct erofs_dir_stream {
  40. struct fs_dir_stream fs_dirs;
  41. struct fs_dirent dirent;
  42. struct erofs_inode inode;
  43. char dblk[EROFS_MAX_BLOCK_SIZE];
  44. unsigned int maxsize, de_end;
  45. erofs_off_t pos;
  46. };
  47. static int erofs_readlink(struct erofs_inode *vi)
  48. {
  49. size_t len = vi->i_size;
  50. char *target;
  51. int err;
  52. target = malloc(len + 1);
  53. if (!target)
  54. return -ENOMEM;
  55. target[len] = '\0';
  56. err = erofs_pread(vi, target, len, 0);
  57. if (err)
  58. goto err_out;
  59. err = erofs_ilookup(target, vi);
  60. if (err)
  61. goto err_out;
  62. err_out:
  63. free(target);
  64. return err;
  65. }
  66. int erofs_opendir(const char *filename, struct fs_dir_stream **dirsp)
  67. {
  68. struct erofs_dir_stream *dirs;
  69. int err;
  70. dirs = calloc(1, sizeof(*dirs));
  71. if (!dirs)
  72. return -ENOMEM;
  73. err = erofs_ilookup(filename, &dirs->inode);
  74. if (err)
  75. goto err_out;
  76. if (S_ISLNK(dirs->inode.i_mode)) {
  77. err = erofs_readlink(&dirs->inode);
  78. if (err)
  79. goto err_out;
  80. }
  81. if (!S_ISDIR(dirs->inode.i_mode)) {
  82. err = -ENOTDIR;
  83. goto err_out;
  84. }
  85. *dirsp = (struct fs_dir_stream *)dirs;
  86. return 0;
  87. err_out:
  88. free(dirs);
  89. return err;
  90. }
  91. int erofs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
  92. {
  93. struct erofs_dir_stream *dirs = (struct erofs_dir_stream *)fs_dirs;
  94. struct fs_dirent *dent = &dirs->dirent;
  95. erofs_off_t pos = dirs->pos;
  96. unsigned int nameoff, de_namelen;
  97. struct erofs_dirent *de;
  98. char *de_name;
  99. int err;
  100. if (pos >= dirs->inode.i_size)
  101. return 1;
  102. if (!dirs->maxsize) {
  103. dirs->maxsize = min_t(unsigned int, EROFS_MAX_BLOCK_SIZE,
  104. dirs->inode.i_size - pos);
  105. err = erofs_pread(&dirs->inode, dirs->dblk,
  106. dirs->maxsize, pos);
  107. if (err)
  108. return err;
  109. de = (struct erofs_dirent *)dirs->dblk;
  110. dirs->de_end = le16_to_cpu(de->nameoff);
  111. if (dirs->de_end < sizeof(struct erofs_dirent) ||
  112. dirs->de_end >= EROFS_MAX_BLOCK_SIZE) {
  113. erofs_err("invalid de[0].nameoff %u @ nid %llu",
  114. dirs->de_end, de->nid | 0ULL);
  115. return -EFSCORRUPTED;
  116. }
  117. }
  118. de = (struct erofs_dirent *)(dirs->dblk + erofs_blkoff(pos));
  119. nameoff = le16_to_cpu(de->nameoff);
  120. de_name = (char *)dirs->dblk + nameoff;
  121. /* the last dirent in the block? */
  122. if (de + 1 >= (struct erofs_dirent *)(dirs->dblk + dirs->de_end))
  123. de_namelen = strnlen(de_name, dirs->maxsize - nameoff);
  124. else
  125. de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
  126. /* a corrupted entry is found */
  127. if (nameoff + de_namelen > dirs->maxsize ||
  128. de_namelen > EROFS_NAME_LEN) {
  129. erofs_err("bogus dirent @ nid %llu", de->nid | 0ULL);
  130. DBG_BUGON(1);
  131. return -EFSCORRUPTED;
  132. }
  133. memcpy(dent->name, de_name, de_namelen);
  134. dent->name[de_namelen] = '\0';
  135. if (de->file_type == EROFS_FT_DIR) {
  136. dent->type = FS_DT_DIR;
  137. } else if (de->file_type == EROFS_FT_SYMLINK) {
  138. dent->type = FS_DT_LNK;
  139. } else {
  140. struct erofs_inode vi;
  141. dent->type = FS_DT_REG;
  142. vi.nid = de->nid;
  143. err = erofs_read_inode_from_disk(&vi);
  144. if (err)
  145. return err;
  146. dent->size = vi.i_size;
  147. }
  148. *dentp = dent;
  149. pos += sizeof(*de);
  150. if (erofs_blkoff(pos) >= dirs->de_end) {
  151. pos = erofs_pos(erofs_blknr(pos) + 1);
  152. dirs->maxsize = 0;
  153. }
  154. dirs->pos = pos;
  155. return 0;
  156. }
  157. void erofs_closedir(struct fs_dir_stream *fs_dirs)
  158. {
  159. free(fs_dirs);
  160. }
  161. int erofs_exists(const char *filename)
  162. {
  163. struct erofs_inode vi;
  164. int err;
  165. err = erofs_ilookup(filename, &vi);
  166. return err == 0;
  167. }
  168. int erofs_size(const char *filename, loff_t *size)
  169. {
  170. struct erofs_inode vi;
  171. int err;
  172. err = erofs_ilookup(filename, &vi);
  173. if (err)
  174. return err;
  175. *size = vi.i_size;
  176. return 0;
  177. }
  178. int erofs_read(const char *filename, void *buf, loff_t offset, loff_t len,
  179. loff_t *actread)
  180. {
  181. struct erofs_inode vi;
  182. int err;
  183. err = erofs_ilookup(filename, &vi);
  184. if (err)
  185. return err;
  186. if (S_ISLNK(vi.i_mode)) {
  187. err = erofs_readlink(&vi);
  188. if (err)
  189. return err;
  190. }
  191. if (!len)
  192. len = vi.i_size;
  193. err = erofs_pread(&vi, buf, len, offset);
  194. if (err) {
  195. *actread = 0;
  196. return err;
  197. }
  198. if (offset >= vi.i_size)
  199. *actread = 0;
  200. else if (offset + len > vi.i_size)
  201. *actread = vi.i_size - offset;
  202. else
  203. *actread = len;
  204. return 0;
  205. }
  206. void erofs_close(void)
  207. {
  208. ctxt.cur_dev = NULL;
  209. }
  210. int erofs_uuid(char *uuid_str)
  211. {
  212. if (IS_ENABLED(CONFIG_LIB_UUID)) {
  213. if (ctxt.cur_dev)
  214. uuid_bin_to_str(sbi.uuid, uuid_str,
  215. UUID_STR_FORMAT_STD);
  216. return 0;
  217. }
  218. return -ENOSYS;
  219. }