sqfs.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020 Bootlin
  4. *
  5. * Author: Joao Marcos Costa <joaomarcos.costa@bootlin.com>
  6. *
  7. * sqfs.c: SquashFS filesystem implementation
  8. */
  9. #include <asm/unaligned.h>
  10. #include <errno.h>
  11. #include <fs.h>
  12. #include <linux/types.h>
  13. #include <linux/byteorder/little_endian.h>
  14. #include <linux/byteorder/generic.h>
  15. #include <memalign.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <squashfs.h>
  19. #include <part.h>
  20. #include "sqfs_decompressor.h"
  21. #include "sqfs_filesystem.h"
  22. #include "sqfs_utils.h"
  23. static struct squashfs_ctxt ctxt;
  24. static int sqfs_disk_read(__u32 block, __u32 nr_blocks, void *buf)
  25. {
  26. ulong ret;
  27. if (!ctxt.cur_dev)
  28. return -1;
  29. ret = blk_dread(ctxt.cur_dev, ctxt.cur_part_info.start + block,
  30. nr_blocks, buf);
  31. if (ret != nr_blocks)
  32. return -1;
  33. return ret;
  34. }
  35. static int sqfs_read_sblk(struct squashfs_super_block **sblk)
  36. {
  37. *sblk = malloc_cache_aligned(ctxt.cur_dev->blksz);
  38. if (!*sblk)
  39. return -ENOMEM;
  40. if (sqfs_disk_read(0, 1, *sblk) != 1) {
  41. free(*sblk);
  42. sblk = NULL;
  43. return -EINVAL;
  44. }
  45. return 0;
  46. }
  47. static int sqfs_count_tokens(const char *filename)
  48. {
  49. int token_count = 1, l;
  50. for (l = 1; l < strlen(filename); l++) {
  51. if (filename[l] == '/')
  52. token_count++;
  53. }
  54. /* Ignore trailing '/' in path */
  55. if (filename[strlen(filename) - 1] == '/')
  56. token_count--;
  57. if (!token_count)
  58. token_count = 1;
  59. return token_count;
  60. }
  61. /*
  62. * Calculates how many blocks are needed for the buffer used in sqfs_disk_read.
  63. * The memory section (e.g. inode table) start offset and its end (i.e. the next
  64. * table start) must be specified. It also calculates the offset from which to
  65. * start reading the buffer.
  66. */
  67. static int sqfs_calc_n_blks(__le64 start, __le64 end, u64 *offset)
  68. {
  69. u64 start_, table_size;
  70. table_size = le64_to_cpu(end) - le64_to_cpu(start);
  71. start_ = le64_to_cpu(start) / ctxt.cur_dev->blksz;
  72. *offset = le64_to_cpu(start) - (start_ * ctxt.cur_dev->blksz);
  73. return DIV_ROUND_UP(table_size + *offset, ctxt.cur_dev->blksz);
  74. }
  75. /*
  76. * Retrieves fragment block entry and returns true if the fragment block is
  77. * compressed
  78. */
  79. static int sqfs_frag_lookup(u32 inode_fragment_index,
  80. struct squashfs_fragment_block_entry *e)
  81. {
  82. u64 start, n_blks, src_len, table_offset, start_block;
  83. unsigned char *metadata_buffer, *metadata, *table;
  84. struct squashfs_fragment_block_entry *entries;
  85. struct squashfs_super_block *sblk = ctxt.sblk;
  86. unsigned long dest_len;
  87. int block, offset, ret;
  88. u16 header;
  89. metadata_buffer = NULL;
  90. entries = NULL;
  91. table = NULL;
  92. if (inode_fragment_index >= get_unaligned_le32(&sblk->fragments))
  93. return -EINVAL;
  94. start = get_unaligned_le64(&sblk->fragment_table_start) /
  95. ctxt.cur_dev->blksz;
  96. n_blks = sqfs_calc_n_blks(sblk->fragment_table_start,
  97. sblk->export_table_start,
  98. &table_offset);
  99. /* Allocate a proper sized buffer to store the fragment index table */
  100. table = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
  101. if (!table) {
  102. ret = -ENOMEM;
  103. goto out;
  104. }
  105. if (sqfs_disk_read(start, n_blks, table) < 0) {
  106. ret = -EINVAL;
  107. goto out;
  108. }
  109. block = SQFS_FRAGMENT_INDEX(inode_fragment_index);
  110. offset = SQFS_FRAGMENT_INDEX_OFFSET(inode_fragment_index);
  111. /*
  112. * Get the start offset of the metadata block that contains the right
  113. * fragment block entry
  114. */
  115. start_block = get_unaligned_le64(table + table_offset + block *
  116. sizeof(u64));
  117. start = start_block / ctxt.cur_dev->blksz;
  118. n_blks = sqfs_calc_n_blks(cpu_to_le64(start_block),
  119. sblk->fragment_table_start, &table_offset);
  120. metadata_buffer = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
  121. if (!metadata_buffer) {
  122. ret = -ENOMEM;
  123. goto out;
  124. }
  125. if (sqfs_disk_read(start, n_blks, metadata_buffer) < 0) {
  126. ret = -EINVAL;
  127. goto out;
  128. }
  129. /* Every metadata block starts with a 16-bit header */
  130. header = get_unaligned_le16(metadata_buffer + table_offset);
  131. metadata = metadata_buffer + table_offset + SQFS_HEADER_SIZE;
  132. if (!metadata || !header) {
  133. ret = -ENOMEM;
  134. goto out;
  135. }
  136. entries = malloc(SQFS_METADATA_BLOCK_SIZE);
  137. if (!entries) {
  138. ret = -ENOMEM;
  139. goto out;
  140. }
  141. if (SQFS_COMPRESSED_METADATA(header)) {
  142. src_len = SQFS_METADATA_SIZE(header);
  143. dest_len = SQFS_METADATA_BLOCK_SIZE;
  144. ret = sqfs_decompress(&ctxt, entries, &dest_len, metadata,
  145. src_len);
  146. if (ret) {
  147. ret = -EINVAL;
  148. goto out;
  149. }
  150. } else {
  151. memcpy(entries, metadata, SQFS_METADATA_SIZE(header));
  152. }
  153. *e = entries[offset];
  154. ret = SQFS_COMPRESSED_BLOCK(e->size);
  155. out:
  156. free(entries);
  157. free(metadata_buffer);
  158. free(table);
  159. return ret;
  160. }
  161. /*
  162. * The entry name is a flexible array member, and we don't know its size before
  163. * actually reading the entry. So we need a first copy to retrieve this size so
  164. * we can finally copy the whole struct.
  165. */
  166. static int sqfs_read_entry(struct squashfs_directory_entry **dest, void *src)
  167. {
  168. struct squashfs_directory_entry *tmp;
  169. u16 sz;
  170. tmp = src;
  171. sz = get_unaligned_le16(src + sizeof(*tmp) - sizeof(u16));
  172. /*
  173. * 'src' points to the begin of a directory entry, and 'sz' gets its
  174. * 'name_size' member's value. name_size is actually the string
  175. * length - 1, so adding 2 compensates this difference and adds space
  176. * for the trailling null byte.
  177. */
  178. *dest = malloc(sizeof(*tmp) + sz + 2);
  179. if (!*dest)
  180. return -ENOMEM;
  181. memcpy(*dest, src, sizeof(*tmp) + sz + 1);
  182. (*dest)->name[sz + 1] = '\0';
  183. return 0;
  184. }
  185. static int sqfs_get_tokens_length(char **tokens, int count)
  186. {
  187. int length = 0, i;
  188. /*
  189. * 1 is added to the result of strlen to consider the slash separator
  190. * between the tokens.
  191. */
  192. for (i = 0; i < count; i++)
  193. length += strlen(tokens[i]) + 1;
  194. return length;
  195. }
  196. /* Takes a token list and returns a single string with '/' as separator. */
  197. static char *sqfs_concat_tokens(char **token_list, int token_count)
  198. {
  199. char *result;
  200. int i, length = 0, offset = 0;
  201. length = sqfs_get_tokens_length(token_list, token_count);
  202. result = malloc(length + 1);
  203. if (!result)
  204. return NULL;
  205. result[length] = '\0';
  206. for (i = 0; i < token_count; i++) {
  207. strcpy(result + offset, token_list[i]);
  208. offset += strlen(token_list[i]);
  209. result[offset++] = '/';
  210. }
  211. return result;
  212. }
  213. /*
  214. * Differently from sqfs_concat_tokens, sqfs_join writes the result into a
  215. * previously allocated string, and returns the number of bytes written.
  216. */
  217. static int sqfs_join(char **strings, char *dest, int start, int end,
  218. char separator)
  219. {
  220. int i, offset = 0;
  221. for (i = start; i < end; i++) {
  222. strcpy(dest + offset, strings[i]);
  223. offset += strlen(strings[i]);
  224. if (i < end - 1)
  225. dest[offset++] = separator;
  226. }
  227. return offset;
  228. }
  229. /*
  230. * Fills the given token list using its size (count) and a source string (str)
  231. */
  232. static int sqfs_tokenize(char **tokens, int count, const char *str)
  233. {
  234. int i, j, ret = 0;
  235. char *aux, *strc;
  236. strc = strdup(str);
  237. if (!strc)
  238. return -ENOMEM;
  239. if (!strcmp(strc, "/")) {
  240. tokens[0] = strdup(strc);
  241. if (!tokens[0]) {
  242. ret = -ENOMEM;
  243. goto free_strc;
  244. }
  245. } else {
  246. for (j = 0; j < count; j++) {
  247. aux = strtok(!j ? strc : NULL, "/");
  248. tokens[j] = strdup(aux);
  249. if (!tokens[j]) {
  250. for (i = 0; i < j; i++)
  251. free(tokens[i]);
  252. ret = -ENOMEM;
  253. goto free_strc;
  254. }
  255. }
  256. }
  257. free_strc:
  258. free(strc);
  259. return ret;
  260. }
  261. /*
  262. * Remove last 'updir + 1' tokens from the base path tokens list. This leaves us
  263. * with a token list containing only the tokens needed to form the resolved
  264. * path, and returns the decremented size of the token list.
  265. */
  266. static int sqfs_clean_base_path(char **base, int count, int updir)
  267. {
  268. int i;
  269. for (i = count - updir - 1; i < count; i++)
  270. free(base[i]);
  271. return count - updir - 1;
  272. }
  273. /*
  274. * Given the base ("current dir.") path and the relative one, generate the
  275. * absolute path.
  276. */
  277. static char *sqfs_get_abs_path(const char *base, const char *rel)
  278. {
  279. char **base_tokens, **rel_tokens, *resolved = NULL;
  280. int ret, bc, rc, i, updir = 0, resolved_size = 0, offset = 0;
  281. base_tokens = NULL;
  282. rel_tokens = NULL;
  283. /* Memory allocation for the token lists */
  284. bc = sqfs_count_tokens(base);
  285. rc = sqfs_count_tokens(rel);
  286. if (bc < 1 || rc < 1)
  287. return NULL;
  288. base_tokens = calloc(bc, sizeof(char *));
  289. if (!base_tokens)
  290. return NULL;
  291. rel_tokens = calloc(rc, sizeof(char *));
  292. if (!rel_tokens)
  293. goto out;
  294. /* Fill token lists */
  295. ret = sqfs_tokenize(base_tokens, bc, base);
  296. if (ret)
  297. goto out;
  298. ret = sqfs_tokenize(rel_tokens, rc, rel);
  299. if (ret)
  300. goto out;
  301. /* count '..' occurrences in target path */
  302. for (i = 0; i < rc; i++) {
  303. if (!strcmp(rel_tokens[i], ".."))
  304. updir++;
  305. }
  306. /* Remove the last token and the '..' occurrences */
  307. bc = sqfs_clean_base_path(base_tokens, bc, updir);
  308. if (bc < 0)
  309. goto out;
  310. /* Calculate resolved path size */
  311. if (!bc)
  312. resolved_size++;
  313. resolved_size += sqfs_get_tokens_length(base_tokens, bc) +
  314. sqfs_get_tokens_length(rel_tokens, rc);
  315. resolved = malloc(resolved_size + 1);
  316. if (!resolved)
  317. goto out;
  318. /* Set resolved path */
  319. memset(resolved, '\0', resolved_size + 1);
  320. offset += sqfs_join(base_tokens, resolved + offset, 0, bc, '/');
  321. resolved[offset++] = '/';
  322. offset += sqfs_join(rel_tokens, resolved + offset, updir, rc, '/');
  323. out:
  324. if (rel_tokens)
  325. for (i = 0; i < rc; i++)
  326. free(rel_tokens[i]);
  327. if (base_tokens)
  328. for (i = 0; i < bc; i++)
  329. free(base_tokens[i]);
  330. free(rel_tokens);
  331. free(base_tokens);
  332. return resolved;
  333. }
  334. static char *sqfs_resolve_symlink(struct squashfs_symlink_inode *sym,
  335. const char *base_path)
  336. {
  337. char *resolved, *target;
  338. u32 sz;
  339. sz = get_unaligned_le32(&sym->symlink_size);
  340. target = malloc(sz + 1);
  341. if (!target)
  342. return NULL;
  343. /*
  344. * There is no trailling null byte in the symlink's target path, so a
  345. * copy is made and a '\0' is added at its end.
  346. */
  347. target[sz] = '\0';
  348. /* Get target name (relative path) */
  349. strncpy(target, sym->symlink, sz);
  350. /* Relative -> absolute path conversion */
  351. resolved = sqfs_get_abs_path(base_path, target);
  352. free(target);
  353. return resolved;
  354. }
  355. /*
  356. * m_list contains each metadata block's position, and m_count is the number of
  357. * elements of m_list. Those metadata blocks come from the compressed directory
  358. * table.
  359. */
  360. static int sqfs_search_dir(struct squashfs_dir_stream *dirs, char **token_list,
  361. int token_count, u32 *m_list, int m_count)
  362. {
  363. struct squashfs_super_block *sblk = ctxt.sblk;
  364. char *path, *target, **sym_tokens, *res, *rem;
  365. int j, ret = 0, new_inode_number, offset;
  366. struct squashfs_symlink_inode *sym;
  367. struct squashfs_ldir_inode *ldir;
  368. struct squashfs_dir_inode *dir;
  369. struct fs_dir_stream *dirsp;
  370. struct fs_dirent *dent;
  371. unsigned char *table;
  372. res = NULL;
  373. rem = NULL;
  374. path = NULL;
  375. target = NULL;
  376. sym_tokens = NULL;
  377. dirsp = (struct fs_dir_stream *)dirs;
  378. /* Start by root inode */
  379. table = sqfs_find_inode(dirs->inode_table, le32_to_cpu(sblk->inodes),
  380. sblk->inodes, sblk->block_size);
  381. dir = (struct squashfs_dir_inode *)table;
  382. ldir = (struct squashfs_ldir_inode *)table;
  383. /* get directory offset in directory table */
  384. offset = sqfs_dir_offset(table, m_list, m_count);
  385. dirs->table = &dirs->dir_table[offset];
  386. /* Setup directory header */
  387. dirs->dir_header = malloc(SQFS_DIR_HEADER_SIZE);
  388. if (!dirs->dir_header)
  389. return -ENOMEM;
  390. memcpy(dirs->dir_header, dirs->table, SQFS_DIR_HEADER_SIZE);
  391. /* Initialize squashfs_dir_stream members */
  392. dirs->table += SQFS_DIR_HEADER_SIZE;
  393. dirs->size = get_unaligned_le16(&dir->file_size) - SQFS_DIR_HEADER_SIZE;
  394. dirs->entry_count = dirs->dir_header->count + 1;
  395. /* No path given -> root directory */
  396. if (!strcmp(token_list[0], "/")) {
  397. dirs->table = &dirs->dir_table[offset];
  398. memcpy(&dirs->i_dir, dir, sizeof(*dir));
  399. return 0;
  400. }
  401. for (j = 0; j < token_count; j++) {
  402. if (!sqfs_is_dir(get_unaligned_le16(&dir->inode_type))) {
  403. printf("** Cannot find directory. **\n");
  404. ret = -EINVAL;
  405. goto out;
  406. }
  407. while (!sqfs_readdir(dirsp, &dent)) {
  408. ret = strcmp(dent->name, token_list[j]);
  409. if (!ret)
  410. break;
  411. free(dirs->entry);
  412. dirs->entry = NULL;
  413. }
  414. if (ret) {
  415. printf("** Cannot find directory. **\n");
  416. ret = -EINVAL;
  417. goto out;
  418. }
  419. /* Redefine inode as the found token */
  420. new_inode_number = dirs->entry->inode_offset +
  421. dirs->dir_header->inode_number;
  422. /* Get reference to inode in the inode table */
  423. table = sqfs_find_inode(dirs->inode_table, new_inode_number,
  424. sblk->inodes, sblk->block_size);
  425. dir = (struct squashfs_dir_inode *)table;
  426. /* Check for symbolic link and inode type sanity */
  427. if (get_unaligned_le16(&dir->inode_type) == SQFS_SYMLINK_TYPE) {
  428. sym = (struct squashfs_symlink_inode *)table;
  429. /* Get first j + 1 tokens */
  430. path = sqfs_concat_tokens(token_list, j + 1);
  431. if (!path) {
  432. ret = -ENOMEM;
  433. goto out;
  434. }
  435. /* Resolve for these tokens */
  436. target = sqfs_resolve_symlink(sym, path);
  437. if (!target) {
  438. ret = -ENOMEM;
  439. goto out;
  440. }
  441. /* Join remaining tokens */
  442. rem = sqfs_concat_tokens(token_list + j + 1, token_count -
  443. j - 1);
  444. if (!rem) {
  445. ret = -ENOMEM;
  446. goto out;
  447. }
  448. /* Concatenate remaining tokens and symlink's target */
  449. res = malloc(strlen(rem) + strlen(target) + 1);
  450. if (!res) {
  451. ret = -ENOMEM;
  452. goto out;
  453. }
  454. strcpy(res, target);
  455. res[strlen(target)] = '/';
  456. strcpy(res + strlen(target) + 1, rem);
  457. token_count = sqfs_count_tokens(res);
  458. if (token_count < 0) {
  459. ret = -EINVAL;
  460. goto out;
  461. }
  462. sym_tokens = malloc(token_count * sizeof(char *));
  463. if (!sym_tokens) {
  464. ret = -EINVAL;
  465. goto out;
  466. }
  467. /* Fill tokens list */
  468. ret = sqfs_tokenize(sym_tokens, token_count, res);
  469. if (ret) {
  470. ret = -EINVAL;
  471. goto out;
  472. }
  473. free(dirs->entry);
  474. dirs->entry = NULL;
  475. ret = sqfs_search_dir(dirs, sym_tokens, token_count,
  476. m_list, m_count);
  477. goto out;
  478. } else if (!sqfs_is_dir(get_unaligned_le16(&dir->inode_type))) {
  479. printf("** Cannot find directory. **\n");
  480. free(dirs->entry);
  481. dirs->entry = NULL;
  482. ret = -EINVAL;
  483. goto out;
  484. }
  485. /* Check if it is an extended dir. */
  486. if (get_unaligned_le16(&dir->inode_type) == SQFS_LDIR_TYPE)
  487. ldir = (struct squashfs_ldir_inode *)table;
  488. /* Get dir. offset into the directory table */
  489. offset = sqfs_dir_offset(table, m_list, m_count);
  490. dirs->table = &dirs->dir_table[offset];
  491. /* Copy directory header */
  492. memcpy(dirs->dir_header, &dirs->dir_table[offset],
  493. SQFS_DIR_HEADER_SIZE);
  494. /* Check for empty directory */
  495. if (sqfs_is_empty_dir(table)) {
  496. printf("Empty directory.\n");
  497. free(dirs->entry);
  498. dirs->entry = NULL;
  499. ret = SQFS_EMPTY_DIR;
  500. goto out;
  501. }
  502. dirs->table += SQFS_DIR_HEADER_SIZE;
  503. dirs->size = get_unaligned_le16(&dir->file_size);
  504. dirs->entry_count = dirs->dir_header->count + 1;
  505. dirs->size -= SQFS_DIR_HEADER_SIZE;
  506. free(dirs->entry);
  507. dirs->entry = NULL;
  508. }
  509. offset = sqfs_dir_offset(table, m_list, m_count);
  510. dirs->table = &dirs->dir_table[offset];
  511. if (get_unaligned_le16(&dir->inode_type) == SQFS_DIR_TYPE)
  512. memcpy(&dirs->i_dir, dir, sizeof(*dir));
  513. else
  514. memcpy(&dirs->i_ldir, ldir, sizeof(*ldir));
  515. out:
  516. free(res);
  517. free(rem);
  518. free(path);
  519. free(target);
  520. free(sym_tokens);
  521. return ret;
  522. }
  523. /*
  524. * Inode and directory tables are stored as a series of metadata blocks, and
  525. * given the compressed size of this table, we can calculate how much metadata
  526. * blocks are needed to store the result of the decompression, since a
  527. * decompressed metadata block should have a size of 8KiB.
  528. */
  529. static int sqfs_count_metablks(void *table, u32 offset, int table_size)
  530. {
  531. int count = 0, cur_size = 0, ret;
  532. u32 data_size;
  533. bool comp;
  534. do {
  535. ret = sqfs_read_metablock(table, offset + cur_size, &comp,
  536. &data_size);
  537. if (ret)
  538. return -EINVAL;
  539. cur_size += data_size + SQFS_HEADER_SIZE;
  540. count++;
  541. } while (cur_size < table_size);
  542. return count;
  543. }
  544. /*
  545. * Storing the metadata blocks header's positions will be useful while looking
  546. * for an entry in the directory table, using the reference (index and offset)
  547. * given by its inode.
  548. */
  549. static int sqfs_get_metablk_pos(u32 *pos_list, void *table, u32 offset,
  550. int metablks_count)
  551. {
  552. u32 data_size, cur_size = 0;
  553. int j, ret = 0;
  554. bool comp;
  555. if (!metablks_count)
  556. return -EINVAL;
  557. for (j = 0; j < metablks_count; j++) {
  558. ret = sqfs_read_metablock(table, offset + cur_size, &comp,
  559. &data_size);
  560. if (ret)
  561. return -EINVAL;
  562. cur_size += data_size + SQFS_HEADER_SIZE;
  563. pos_list[j] = cur_size;
  564. }
  565. return ret;
  566. }
  567. static int sqfs_read_inode_table(unsigned char **inode_table)
  568. {
  569. struct squashfs_super_block *sblk = ctxt.sblk;
  570. u64 start, n_blks, table_offset, table_size;
  571. int j, ret = 0, metablks_count;
  572. unsigned char *src_table, *itb;
  573. u32 src_len, dest_offset = 0;
  574. unsigned long dest_len = 0;
  575. bool compressed;
  576. table_size = get_unaligned_le64(&sblk->directory_table_start) -
  577. get_unaligned_le64(&sblk->inode_table_start);
  578. start = get_unaligned_le64(&sblk->inode_table_start) /
  579. ctxt.cur_dev->blksz;
  580. n_blks = sqfs_calc_n_blks(sblk->inode_table_start,
  581. sblk->directory_table_start, &table_offset);
  582. /* Allocate a proper sized buffer (itb) to store the inode table */
  583. itb = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
  584. if (!itb)
  585. return -ENOMEM;
  586. if (sqfs_disk_read(start, n_blks, itb) < 0) {
  587. ret = -EINVAL;
  588. goto free_itb;
  589. }
  590. /* Parse inode table (metadata block) header */
  591. ret = sqfs_read_metablock(itb, table_offset, &compressed, &src_len);
  592. if (ret) {
  593. ret = -EINVAL;
  594. goto free_itb;
  595. }
  596. /* Calculate size to store the whole decompressed table */
  597. metablks_count = sqfs_count_metablks(itb, table_offset, table_size);
  598. if (metablks_count < 1) {
  599. ret = -EINVAL;
  600. goto free_itb;
  601. }
  602. *inode_table = malloc(metablks_count * SQFS_METADATA_BLOCK_SIZE);
  603. if (!*inode_table) {
  604. ret = -ENOMEM;
  605. printf("Error: failed to allocate squashfs inode_table of size %i, increasing CONFIG_SYS_MALLOC_LEN could help\n",
  606. metablks_count * SQFS_METADATA_BLOCK_SIZE);
  607. goto free_itb;
  608. }
  609. src_table = itb + table_offset + SQFS_HEADER_SIZE;
  610. /* Extract compressed Inode table */
  611. for (j = 0; j < metablks_count; j++) {
  612. sqfs_read_metablock(itb, table_offset, &compressed, &src_len);
  613. if (compressed) {
  614. dest_len = SQFS_METADATA_BLOCK_SIZE;
  615. ret = sqfs_decompress(&ctxt, *inode_table +
  616. dest_offset, &dest_len,
  617. src_table, src_len);
  618. if (ret) {
  619. free(*inode_table);
  620. *inode_table = NULL;
  621. goto free_itb;
  622. }
  623. dest_offset += dest_len;
  624. } else {
  625. memcpy(*inode_table + (j * SQFS_METADATA_BLOCK_SIZE),
  626. src_table, src_len);
  627. }
  628. /*
  629. * Offsets to the decompression destination, to the metadata
  630. * buffer 'itb' and to the decompression source, respectively.
  631. */
  632. table_offset += src_len + SQFS_HEADER_SIZE;
  633. src_table += src_len + SQFS_HEADER_SIZE;
  634. }
  635. free_itb:
  636. free(itb);
  637. return ret;
  638. }
  639. static int sqfs_read_directory_table(unsigned char **dir_table, u32 **pos_list)
  640. {
  641. u64 start, n_blks, table_offset, table_size;
  642. struct squashfs_super_block *sblk = ctxt.sblk;
  643. int j, ret = 0, metablks_count = -1;
  644. unsigned char *src_table, *dtb;
  645. u32 src_len, dest_offset = 0;
  646. unsigned long dest_len = 0;
  647. bool compressed;
  648. *dir_table = NULL;
  649. *pos_list = NULL;
  650. /* DIRECTORY TABLE */
  651. table_size = get_unaligned_le64(&sblk->fragment_table_start) -
  652. get_unaligned_le64(&sblk->directory_table_start);
  653. start = get_unaligned_le64(&sblk->directory_table_start) /
  654. ctxt.cur_dev->blksz;
  655. n_blks = sqfs_calc_n_blks(sblk->directory_table_start,
  656. sblk->fragment_table_start, &table_offset);
  657. /* Allocate a proper sized buffer (dtb) to store the directory table */
  658. dtb = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
  659. if (!dtb)
  660. return -ENOMEM;
  661. if (sqfs_disk_read(start, n_blks, dtb) < 0)
  662. goto out;
  663. /* Parse directory table (metadata block) header */
  664. ret = sqfs_read_metablock(dtb, table_offset, &compressed, &src_len);
  665. if (ret)
  666. goto out;
  667. /* Calculate total size to store the whole decompressed table */
  668. metablks_count = sqfs_count_metablks(dtb, table_offset, table_size);
  669. if (metablks_count < 1)
  670. goto out;
  671. *dir_table = malloc(metablks_count * SQFS_METADATA_BLOCK_SIZE);
  672. if (!*dir_table)
  673. goto out;
  674. *pos_list = malloc(metablks_count * sizeof(u32));
  675. if (!*pos_list)
  676. goto out;
  677. ret = sqfs_get_metablk_pos(*pos_list, dtb, table_offset,
  678. metablks_count);
  679. if (ret) {
  680. metablks_count = -1;
  681. goto out;
  682. }
  683. src_table = dtb + table_offset + SQFS_HEADER_SIZE;
  684. /* Extract compressed Directory table */
  685. dest_offset = 0;
  686. for (j = 0; j < metablks_count; j++) {
  687. sqfs_read_metablock(dtb, table_offset, &compressed, &src_len);
  688. if (compressed) {
  689. dest_len = SQFS_METADATA_BLOCK_SIZE;
  690. ret = sqfs_decompress(&ctxt, *dir_table +
  691. (j * SQFS_METADATA_BLOCK_SIZE),
  692. &dest_len, src_table, src_len);
  693. if (ret) {
  694. metablks_count = -1;
  695. goto out;
  696. }
  697. if (dest_len < SQFS_METADATA_BLOCK_SIZE) {
  698. dest_offset += dest_len;
  699. break;
  700. }
  701. dest_offset += dest_len;
  702. } else {
  703. memcpy(*dir_table + (j * SQFS_METADATA_BLOCK_SIZE),
  704. src_table, src_len);
  705. }
  706. /*
  707. * Offsets to the decompression destination, to the metadata
  708. * buffer 'dtb' and to the decompression source, respectively.
  709. */
  710. table_offset += src_len + SQFS_HEADER_SIZE;
  711. src_table += src_len + SQFS_HEADER_SIZE;
  712. }
  713. out:
  714. if (metablks_count < 1) {
  715. free(*dir_table);
  716. free(*pos_list);
  717. *dir_table = NULL;
  718. *pos_list = NULL;
  719. }
  720. free(dtb);
  721. return metablks_count;
  722. }
  723. int sqfs_opendir(const char *filename, struct fs_dir_stream **dirsp)
  724. {
  725. unsigned char *inode_table = NULL, *dir_table = NULL;
  726. int j, token_count = 0, ret = 0, metablks_count;
  727. struct squashfs_dir_stream *dirs;
  728. char **token_list = NULL, *path = NULL;
  729. u32 *pos_list = NULL;
  730. dirs = calloc(1, sizeof(*dirs));
  731. if (!dirs)
  732. return -EINVAL;
  733. /* these should be set to NULL to prevent dangling pointers */
  734. dirs->dir_header = NULL;
  735. dirs->entry = NULL;
  736. dirs->table = NULL;
  737. dirs->inode_table = NULL;
  738. dirs->dir_table = NULL;
  739. ret = sqfs_read_inode_table(&inode_table);
  740. if (ret) {
  741. ret = -EINVAL;
  742. goto out;
  743. }
  744. metablks_count = sqfs_read_directory_table(&dir_table, &pos_list);
  745. if (metablks_count < 1) {
  746. ret = -EINVAL;
  747. goto out;
  748. }
  749. /* Tokenize filename */
  750. token_count = sqfs_count_tokens(filename);
  751. if (token_count < 0) {
  752. ret = -EINVAL;
  753. goto out;
  754. }
  755. path = strdup(filename);
  756. if (!path) {
  757. ret = -EINVAL;
  758. goto out;
  759. }
  760. token_list = malloc(token_count * sizeof(char *));
  761. if (!token_list) {
  762. ret = -EINVAL;
  763. goto out;
  764. }
  765. /* Fill tokens list */
  766. ret = sqfs_tokenize(token_list, token_count, path);
  767. if (ret)
  768. goto out;
  769. /*
  770. * ldir's (extended directory) size is greater than dir, so it works as
  771. * a general solution for the malloc size, since 'i' is a union.
  772. */
  773. dirs->inode_table = inode_table;
  774. dirs->dir_table = dir_table;
  775. ret = sqfs_search_dir(dirs, token_list, token_count, pos_list,
  776. metablks_count);
  777. if (ret)
  778. goto out;
  779. if (le16_to_cpu(dirs->i_dir.inode_type) == SQFS_DIR_TYPE)
  780. dirs->size = le16_to_cpu(dirs->i_dir.file_size);
  781. else
  782. dirs->size = le32_to_cpu(dirs->i_ldir.file_size);
  783. /* Setup directory header */
  784. memcpy(dirs->dir_header, dirs->table, SQFS_DIR_HEADER_SIZE);
  785. dirs->entry_count = dirs->dir_header->count + 1;
  786. dirs->size -= SQFS_DIR_HEADER_SIZE;
  787. /* Setup entry */
  788. dirs->entry = NULL;
  789. dirs->table += SQFS_DIR_HEADER_SIZE;
  790. *dirsp = (struct fs_dir_stream *)dirs;
  791. out:
  792. for (j = 0; j < token_count; j++)
  793. free(token_list[j]);
  794. free(token_list);
  795. free(pos_list);
  796. free(path);
  797. if (ret) {
  798. free(inode_table);
  799. free(dirs);
  800. }
  801. return ret;
  802. }
  803. int sqfs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
  804. {
  805. struct squashfs_super_block *sblk = ctxt.sblk;
  806. struct squashfs_dir_stream *dirs;
  807. struct squashfs_lreg_inode *lreg;
  808. struct squashfs_base_inode *base;
  809. struct squashfs_reg_inode *reg;
  810. int i_number, offset = 0, ret;
  811. struct fs_dirent *dent;
  812. unsigned char *ipos;
  813. dirs = (struct squashfs_dir_stream *)fs_dirs;
  814. if (!dirs->size) {
  815. *dentp = NULL;
  816. return -SQFS_STOP_READDIR;
  817. }
  818. dent = &dirs->dentp;
  819. if (!dirs->entry_count) {
  820. if (dirs->size > SQFS_DIR_HEADER_SIZE) {
  821. dirs->size -= SQFS_DIR_HEADER_SIZE;
  822. } else {
  823. *dentp = NULL;
  824. dirs->size = 0;
  825. return -SQFS_STOP_READDIR;
  826. }
  827. if (dirs->size > SQFS_EMPTY_FILE_SIZE) {
  828. /* Read follow-up (emitted) dir. header */
  829. memcpy(dirs->dir_header, dirs->table,
  830. SQFS_DIR_HEADER_SIZE);
  831. dirs->entry_count = dirs->dir_header->count + 1;
  832. ret = sqfs_read_entry(&dirs->entry, dirs->table +
  833. SQFS_DIR_HEADER_SIZE);
  834. if (ret)
  835. return -SQFS_STOP_READDIR;
  836. dirs->table += SQFS_DIR_HEADER_SIZE;
  837. }
  838. } else {
  839. ret = sqfs_read_entry(&dirs->entry, dirs->table);
  840. if (ret)
  841. return -SQFS_STOP_READDIR;
  842. }
  843. i_number = dirs->dir_header->inode_number + dirs->entry->inode_offset;
  844. ipos = sqfs_find_inode(dirs->inode_table, i_number, sblk->inodes,
  845. sblk->block_size);
  846. base = (struct squashfs_base_inode *)ipos;
  847. /* Set entry type and size */
  848. switch (dirs->entry->type) {
  849. case SQFS_DIR_TYPE:
  850. case SQFS_LDIR_TYPE:
  851. dent->type = FS_DT_DIR;
  852. break;
  853. case SQFS_REG_TYPE:
  854. case SQFS_LREG_TYPE:
  855. /*
  856. * Entries do not differentiate extended from regular types, so
  857. * it needs to be verified manually.
  858. */
  859. if (get_unaligned_le16(&base->inode_type) == SQFS_LREG_TYPE) {
  860. lreg = (struct squashfs_lreg_inode *)ipos;
  861. dent->size = get_unaligned_le64(&lreg->file_size);
  862. } else {
  863. reg = (struct squashfs_reg_inode *)ipos;
  864. dent->size = get_unaligned_le32(&reg->file_size);
  865. }
  866. dent->type = FS_DT_REG;
  867. break;
  868. case SQFS_BLKDEV_TYPE:
  869. case SQFS_CHRDEV_TYPE:
  870. case SQFS_LBLKDEV_TYPE:
  871. case SQFS_LCHRDEV_TYPE:
  872. case SQFS_FIFO_TYPE:
  873. case SQFS_SOCKET_TYPE:
  874. case SQFS_LFIFO_TYPE:
  875. case SQFS_LSOCKET_TYPE:
  876. dent->type = SQFS_MISC_ENTRY_TYPE;
  877. break;
  878. case SQFS_SYMLINK_TYPE:
  879. case SQFS_LSYMLINK_TYPE:
  880. dent->type = FS_DT_LNK;
  881. break;
  882. default:
  883. return -SQFS_STOP_READDIR;
  884. }
  885. /* Set entry name */
  886. strncpy(dent->name, dirs->entry->name, dirs->entry->name_size + 1);
  887. dent->name[dirs->entry->name_size + 1] = '\0';
  888. offset = dirs->entry->name_size + 1 + SQFS_ENTRY_BASE_LENGTH;
  889. dirs->entry_count--;
  890. /* Decrement size to be read */
  891. if (dirs->size > offset)
  892. dirs->size -= offset;
  893. else
  894. dirs->size = 0;
  895. /* Keep a reference to the current entry before incrementing it */
  896. dirs->table += offset;
  897. *dentp = dent;
  898. return 0;
  899. }
  900. int sqfs_probe(struct blk_desc *fs_dev_desc, struct disk_partition *fs_partition)
  901. {
  902. struct squashfs_super_block *sblk;
  903. int ret;
  904. ctxt.cur_dev = fs_dev_desc;
  905. ctxt.cur_part_info = *fs_partition;
  906. ret = sqfs_read_sblk(&sblk);
  907. if (ret)
  908. goto error;
  909. /* Make sure it has a valid SquashFS magic number*/
  910. if (get_unaligned_le32(&sblk->s_magic) != SQFS_MAGIC_NUMBER) {
  911. debug("Bad magic number for SquashFS image.\n");
  912. ret = -EINVAL;
  913. goto error;
  914. }
  915. ctxt.sblk = sblk;
  916. ret = sqfs_decompressor_init(&ctxt);
  917. if (ret) {
  918. goto error;
  919. }
  920. return 0;
  921. error:
  922. ctxt.cur_dev = NULL;
  923. free(ctxt.sblk);
  924. ctxt.sblk = NULL;
  925. return ret;
  926. }
  927. static char *sqfs_basename(char *path)
  928. {
  929. char *fname;
  930. fname = path + strlen(path) - 1;
  931. while (fname >= path) {
  932. if (*fname == '/') {
  933. fname++;
  934. break;
  935. }
  936. fname--;
  937. }
  938. return fname;
  939. }
  940. static char *sqfs_dirname(char *path)
  941. {
  942. char *fname;
  943. fname = sqfs_basename(path);
  944. --fname;
  945. *fname = '\0';
  946. return path;
  947. }
  948. /*
  949. * Takes a path to file and splits it in two parts: the filename itself and the
  950. * directory's path, e.g.:
  951. * path: /path/to/file.txt
  952. * file: file.txt
  953. * dir: /path/to
  954. */
  955. static int sqfs_split_path(char **file, char **dir, const char *path)
  956. {
  957. char *dirc, *basec, *bname, *dname, *tmp_path;
  958. int ret = 0;
  959. *file = NULL;
  960. *dir = NULL;
  961. dirc = NULL;
  962. basec = NULL;
  963. bname = NULL;
  964. dname = NULL;
  965. tmp_path = NULL;
  966. /* check for first slash in path*/
  967. if (path[0] == '/') {
  968. tmp_path = strdup(path);
  969. if (!tmp_path) {
  970. ret = -ENOMEM;
  971. goto out;
  972. }
  973. } else {
  974. tmp_path = malloc(strlen(path) + 2);
  975. if (!tmp_path) {
  976. ret = -ENOMEM;
  977. goto out;
  978. }
  979. tmp_path[0] = '/';
  980. strcpy(tmp_path + 1, path);
  981. }
  982. /* String duplicates */
  983. dirc = strdup(tmp_path);
  984. if (!dirc) {
  985. ret = -ENOMEM;
  986. goto out;
  987. }
  988. basec = strdup(tmp_path);
  989. if (!basec) {
  990. ret = -ENOMEM;
  991. goto out;
  992. }
  993. dname = sqfs_dirname(dirc);
  994. bname = sqfs_basename(basec);
  995. *file = strdup(bname);
  996. if (!*file) {
  997. ret = -ENOMEM;
  998. goto out;
  999. }
  1000. if (*dname == '\0') {
  1001. *dir = malloc(2);
  1002. if (!*dir) {
  1003. ret = -ENOMEM;
  1004. goto out;
  1005. }
  1006. (*dir)[0] = '/';
  1007. (*dir)[1] = '\0';
  1008. } else {
  1009. *dir = strdup(dname);
  1010. if (!*dir) {
  1011. ret = -ENOMEM;
  1012. goto out;
  1013. }
  1014. }
  1015. out:
  1016. if (ret) {
  1017. free(*file);
  1018. free(*dir);
  1019. *dir = NULL;
  1020. *file = NULL;
  1021. }
  1022. free(basec);
  1023. free(dirc);
  1024. free(tmp_path);
  1025. return ret;
  1026. }
  1027. static int sqfs_get_regfile_info(struct squashfs_reg_inode *reg,
  1028. struct squashfs_file_info *finfo,
  1029. struct squashfs_fragment_block_entry *fentry,
  1030. __le32 blksz)
  1031. {
  1032. int datablk_count = 0, ret;
  1033. finfo->size = get_unaligned_le32(&reg->file_size);
  1034. finfo->offset = get_unaligned_le32(&reg->offset);
  1035. finfo->start = get_unaligned_le32(&reg->start_block);
  1036. finfo->frag = SQFS_IS_FRAGMENTED(get_unaligned_le32(&reg->fragment));
  1037. if (finfo->frag && finfo->offset == 0xFFFFFFFF)
  1038. return -EINVAL;
  1039. if (finfo->size < 1 || finfo->start == 0xFFFFFFFF)
  1040. return -EINVAL;
  1041. if (finfo->frag) {
  1042. datablk_count = finfo->size / le32_to_cpu(blksz);
  1043. ret = sqfs_frag_lookup(get_unaligned_le32(&reg->fragment),
  1044. fentry);
  1045. if (ret < 0)
  1046. return -EINVAL;
  1047. finfo->comp = ret;
  1048. if (fentry->size < 1 || fentry->start == 0x7FFFFFFF)
  1049. return -EINVAL;
  1050. } else {
  1051. datablk_count = DIV_ROUND_UP(finfo->size, le32_to_cpu(blksz));
  1052. }
  1053. finfo->blk_sizes = malloc(datablk_count * sizeof(u32));
  1054. if (!finfo->blk_sizes)
  1055. return -ENOMEM;
  1056. return datablk_count;
  1057. }
  1058. static int sqfs_get_lregfile_info(struct squashfs_lreg_inode *lreg,
  1059. struct squashfs_file_info *finfo,
  1060. struct squashfs_fragment_block_entry *fentry,
  1061. __le32 blksz)
  1062. {
  1063. int datablk_count = 0, ret;
  1064. finfo->size = get_unaligned_le64(&lreg->file_size);
  1065. finfo->offset = get_unaligned_le32(&lreg->offset);
  1066. finfo->start = get_unaligned_le64(&lreg->start_block);
  1067. finfo->frag = SQFS_IS_FRAGMENTED(get_unaligned_le32(&lreg->fragment));
  1068. if (finfo->frag && finfo->offset == 0xFFFFFFFF)
  1069. return -EINVAL;
  1070. if (finfo->size < 1 || finfo->start == 0x7FFFFFFF)
  1071. return -EINVAL;
  1072. if (finfo->frag) {
  1073. datablk_count = finfo->size / le32_to_cpu(blksz);
  1074. ret = sqfs_frag_lookup(get_unaligned_le32(&lreg->fragment),
  1075. fentry);
  1076. if (ret < 0)
  1077. return -EINVAL;
  1078. finfo->comp = ret;
  1079. if (fentry->size < 1 || fentry->start == 0x7FFFFFFF)
  1080. return -EINVAL;
  1081. } else {
  1082. datablk_count = DIV_ROUND_UP(finfo->size, le32_to_cpu(blksz));
  1083. }
  1084. finfo->blk_sizes = malloc(datablk_count * sizeof(u32));
  1085. if (!finfo->blk_sizes)
  1086. return -ENOMEM;
  1087. return datablk_count;
  1088. }
  1089. int sqfs_read(const char *filename, void *buf, loff_t offset, loff_t len,
  1090. loff_t *actread)
  1091. {
  1092. char *dir = NULL, *fragment_block, *datablock = NULL, *data_buffer = NULL;
  1093. char *fragment = NULL, *file = NULL, *resolved, *data;
  1094. u64 start, n_blks, table_size, data_offset, table_offset, sparse_size;
  1095. int ret, j, i_number, datablk_count = 0;
  1096. struct squashfs_super_block *sblk = ctxt.sblk;
  1097. struct squashfs_fragment_block_entry frag_entry;
  1098. struct squashfs_file_info finfo = {0};
  1099. struct squashfs_symlink_inode *symlink;
  1100. struct fs_dir_stream *dirsp = NULL;
  1101. struct squashfs_dir_stream *dirs;
  1102. struct squashfs_lreg_inode *lreg;
  1103. struct squashfs_base_inode *base;
  1104. struct squashfs_reg_inode *reg;
  1105. unsigned long dest_len;
  1106. struct fs_dirent *dent;
  1107. unsigned char *ipos;
  1108. *actread = 0;
  1109. if (offset) {
  1110. /*
  1111. * TODO: implement reading at an offset in file
  1112. */
  1113. printf("Error: reading at a specific offset in a squashfs file is not supported yet.\n");
  1114. return -EINVAL;
  1115. }
  1116. /*
  1117. * sqfs_opendir will uncompress inode and directory tables, and will
  1118. * return a pointer to the directory that contains the requested file.
  1119. */
  1120. sqfs_split_path(&file, &dir, filename);
  1121. ret = sqfs_opendir(dir, &dirsp);
  1122. if (ret) {
  1123. goto out;
  1124. }
  1125. dirs = (struct squashfs_dir_stream *)dirsp;
  1126. /* For now, only regular files are able to be loaded */
  1127. while (!sqfs_readdir(dirsp, &dent)) {
  1128. ret = strcmp(dent->name, file);
  1129. if (!ret)
  1130. break;
  1131. free(dirs->entry);
  1132. dirs->entry = NULL;
  1133. }
  1134. if (ret) {
  1135. printf("File not found.\n");
  1136. *actread = 0;
  1137. ret = -ENOENT;
  1138. goto out;
  1139. }
  1140. i_number = dirs->dir_header->inode_number + dirs->entry->inode_offset;
  1141. ipos = sqfs_find_inode(dirs->inode_table, i_number, sblk->inodes,
  1142. sblk->block_size);
  1143. base = (struct squashfs_base_inode *)ipos;
  1144. switch (get_unaligned_le16(&base->inode_type)) {
  1145. case SQFS_REG_TYPE:
  1146. reg = (struct squashfs_reg_inode *)ipos;
  1147. datablk_count = sqfs_get_regfile_info(reg, &finfo, &frag_entry,
  1148. sblk->block_size);
  1149. if (datablk_count < 0) {
  1150. ret = -EINVAL;
  1151. goto out;
  1152. }
  1153. memcpy(finfo.blk_sizes, ipos + sizeof(*reg),
  1154. datablk_count * sizeof(u32));
  1155. break;
  1156. case SQFS_LREG_TYPE:
  1157. lreg = (struct squashfs_lreg_inode *)ipos;
  1158. datablk_count = sqfs_get_lregfile_info(lreg, &finfo,
  1159. &frag_entry,
  1160. sblk->block_size);
  1161. if (datablk_count < 0) {
  1162. ret = -EINVAL;
  1163. goto out;
  1164. }
  1165. memcpy(finfo.blk_sizes, ipos + sizeof(*lreg),
  1166. datablk_count * sizeof(u32));
  1167. break;
  1168. case SQFS_SYMLINK_TYPE:
  1169. case SQFS_LSYMLINK_TYPE:
  1170. symlink = (struct squashfs_symlink_inode *)ipos;
  1171. resolved = sqfs_resolve_symlink(symlink, filename);
  1172. ret = sqfs_read(resolved, buf, offset, len, actread);
  1173. free(resolved);
  1174. goto out;
  1175. case SQFS_BLKDEV_TYPE:
  1176. case SQFS_CHRDEV_TYPE:
  1177. case SQFS_LBLKDEV_TYPE:
  1178. case SQFS_LCHRDEV_TYPE:
  1179. case SQFS_FIFO_TYPE:
  1180. case SQFS_SOCKET_TYPE:
  1181. case SQFS_LFIFO_TYPE:
  1182. case SQFS_LSOCKET_TYPE:
  1183. default:
  1184. printf("Unsupported entry type\n");
  1185. ret = -EINVAL;
  1186. goto out;
  1187. }
  1188. /* If the user specifies a length, check its sanity */
  1189. if (len) {
  1190. if (len > finfo.size) {
  1191. ret = -EINVAL;
  1192. goto out;
  1193. }
  1194. finfo.size = len;
  1195. } else {
  1196. len = finfo.size;
  1197. }
  1198. if (datablk_count) {
  1199. data_offset = finfo.start;
  1200. datablock = malloc(get_unaligned_le32(&sblk->block_size));
  1201. if (!datablock) {
  1202. ret = -ENOMEM;
  1203. goto out;
  1204. }
  1205. }
  1206. for (j = 0; j < datablk_count; j++) {
  1207. start = data_offset / ctxt.cur_dev->blksz;
  1208. table_size = SQFS_BLOCK_SIZE(finfo.blk_sizes[j]);
  1209. table_offset = data_offset - (start * ctxt.cur_dev->blksz);
  1210. n_blks = DIV_ROUND_UP(table_size + table_offset,
  1211. ctxt.cur_dev->blksz);
  1212. /* Don't load any data for sparse blocks */
  1213. if (finfo.blk_sizes[j] == 0) {
  1214. n_blks = 0;
  1215. table_offset = 0;
  1216. data_buffer = NULL;
  1217. data = NULL;
  1218. } else {
  1219. data_buffer = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
  1220. if (!data_buffer) {
  1221. ret = -ENOMEM;
  1222. goto out;
  1223. }
  1224. ret = sqfs_disk_read(start, n_blks, data_buffer);
  1225. if (ret < 0) {
  1226. /*
  1227. * Possible causes: too many data blocks or too large
  1228. * SquashFS block size. Tip: re-compile the SquashFS
  1229. * image with mksquashfs's -b <block_size> option.
  1230. */
  1231. printf("Error: too many data blocks to be read.\n");
  1232. goto out;
  1233. }
  1234. data = data_buffer + table_offset;
  1235. }
  1236. /* Load the data */
  1237. if (finfo.blk_sizes[j] == 0) {
  1238. /* This is a sparse block */
  1239. sparse_size = get_unaligned_le32(&sblk->block_size);
  1240. if ((*actread + sparse_size) > len)
  1241. sparse_size = len - *actread;
  1242. memset(buf + *actread, 0, sparse_size);
  1243. *actread += sparse_size;
  1244. } else if (SQFS_COMPRESSED_BLOCK(finfo.blk_sizes[j])) {
  1245. dest_len = get_unaligned_le32(&sblk->block_size);
  1246. ret = sqfs_decompress(&ctxt, datablock, &dest_len,
  1247. data, table_size);
  1248. if (ret)
  1249. goto out;
  1250. if ((*actread + dest_len) > len)
  1251. dest_len = len - *actread;
  1252. memcpy(buf + *actread, datablock, dest_len);
  1253. *actread += dest_len;
  1254. } else {
  1255. if ((*actread + table_size) > len)
  1256. table_size = len - *actread;
  1257. memcpy(buf + *actread, data, table_size);
  1258. *actread += table_size;
  1259. }
  1260. data_offset += table_size;
  1261. if (data_buffer)
  1262. free(data_buffer);
  1263. data_buffer = NULL;
  1264. if (*actread >= len)
  1265. break;
  1266. }
  1267. /*
  1268. * There is no need to continue if the file is not fragmented.
  1269. */
  1270. if (!finfo.frag) {
  1271. ret = 0;
  1272. goto out;
  1273. }
  1274. start = frag_entry.start / ctxt.cur_dev->blksz;
  1275. table_size = SQFS_BLOCK_SIZE(frag_entry.size);
  1276. table_offset = frag_entry.start - (start * ctxt.cur_dev->blksz);
  1277. n_blks = DIV_ROUND_UP(table_size + table_offset, ctxt.cur_dev->blksz);
  1278. fragment = malloc_cache_aligned(n_blks * ctxt.cur_dev->blksz);
  1279. if (!fragment) {
  1280. ret = -ENOMEM;
  1281. goto out;
  1282. }
  1283. ret = sqfs_disk_read(start, n_blks, fragment);
  1284. if (ret < 0)
  1285. goto out;
  1286. /* File compressed and fragmented */
  1287. if (finfo.frag && finfo.comp) {
  1288. dest_len = get_unaligned_le32(&sblk->block_size);
  1289. fragment_block = malloc(dest_len);
  1290. if (!fragment_block) {
  1291. ret = -ENOMEM;
  1292. goto out;
  1293. }
  1294. ret = sqfs_decompress(&ctxt, fragment_block, &dest_len,
  1295. (void *)fragment + table_offset,
  1296. frag_entry.size);
  1297. if (ret) {
  1298. free(fragment_block);
  1299. goto out;
  1300. }
  1301. memcpy(buf + *actread, &fragment_block[finfo.offset], finfo.size - *actread);
  1302. *actread = finfo.size;
  1303. free(fragment_block);
  1304. } else if (finfo.frag && !finfo.comp) {
  1305. fragment_block = (void *)fragment + table_offset;
  1306. memcpy(buf + *actread, &fragment_block[finfo.offset], finfo.size - *actread);
  1307. *actread = finfo.size;
  1308. }
  1309. out:
  1310. free(fragment);
  1311. if (datablk_count) {
  1312. free(data_buffer);
  1313. free(datablock);
  1314. }
  1315. free(file);
  1316. free(dir);
  1317. free(finfo.blk_sizes);
  1318. sqfs_closedir(dirsp);
  1319. return ret;
  1320. }
  1321. int sqfs_size(const char *filename, loff_t *size)
  1322. {
  1323. struct squashfs_super_block *sblk = ctxt.sblk;
  1324. struct squashfs_symlink_inode *symlink;
  1325. struct fs_dir_stream *dirsp = NULL;
  1326. struct squashfs_base_inode *base;
  1327. struct squashfs_dir_stream *dirs;
  1328. struct squashfs_lreg_inode *lreg;
  1329. struct squashfs_reg_inode *reg;
  1330. char *dir, *file, *resolved;
  1331. struct fs_dirent *dent;
  1332. unsigned char *ipos;
  1333. int ret, i_number;
  1334. sqfs_split_path(&file, &dir, filename);
  1335. /*
  1336. * sqfs_opendir will uncompress inode and directory tables, and will
  1337. * return a pointer to the directory that contains the requested file.
  1338. */
  1339. ret = sqfs_opendir(dir, &dirsp);
  1340. if (ret) {
  1341. ret = -EINVAL;
  1342. goto free_strings;
  1343. }
  1344. dirs = (struct squashfs_dir_stream *)dirsp;
  1345. while (!sqfs_readdir(dirsp, &dent)) {
  1346. ret = strcmp(dent->name, file);
  1347. if (!ret)
  1348. break;
  1349. free(dirs->entry);
  1350. dirs->entry = NULL;
  1351. }
  1352. if (ret) {
  1353. printf("File not found.\n");
  1354. *size = 0;
  1355. ret = -EINVAL;
  1356. goto free_strings;
  1357. }
  1358. i_number = dirs->dir_header->inode_number + dirs->entry->inode_offset;
  1359. ipos = sqfs_find_inode(dirs->inode_table, i_number, sblk->inodes,
  1360. sblk->block_size);
  1361. free(dirs->entry);
  1362. dirs->entry = NULL;
  1363. base = (struct squashfs_base_inode *)ipos;
  1364. switch (get_unaligned_le16(&base->inode_type)) {
  1365. case SQFS_REG_TYPE:
  1366. reg = (struct squashfs_reg_inode *)ipos;
  1367. *size = get_unaligned_le32(&reg->file_size);
  1368. break;
  1369. case SQFS_LREG_TYPE:
  1370. lreg = (struct squashfs_lreg_inode *)ipos;
  1371. *size = get_unaligned_le64(&lreg->file_size);
  1372. break;
  1373. case SQFS_SYMLINK_TYPE:
  1374. case SQFS_LSYMLINK_TYPE:
  1375. symlink = (struct squashfs_symlink_inode *)ipos;
  1376. resolved = sqfs_resolve_symlink(symlink, filename);
  1377. ret = sqfs_size(resolved, size);
  1378. free(resolved);
  1379. break;
  1380. case SQFS_BLKDEV_TYPE:
  1381. case SQFS_CHRDEV_TYPE:
  1382. case SQFS_LBLKDEV_TYPE:
  1383. case SQFS_LCHRDEV_TYPE:
  1384. case SQFS_FIFO_TYPE:
  1385. case SQFS_SOCKET_TYPE:
  1386. case SQFS_LFIFO_TYPE:
  1387. case SQFS_LSOCKET_TYPE:
  1388. default:
  1389. printf("Unable to recover entry's size.\n");
  1390. *size = 0;
  1391. ret = -EINVAL;
  1392. break;
  1393. }
  1394. free_strings:
  1395. free(dir);
  1396. free(file);
  1397. sqfs_closedir(dirsp);
  1398. return ret;
  1399. }
  1400. int sqfs_exists(const char *filename)
  1401. {
  1402. struct fs_dir_stream *dirsp = NULL;
  1403. struct squashfs_dir_stream *dirs;
  1404. char *dir, *file;
  1405. struct fs_dirent *dent;
  1406. int ret;
  1407. sqfs_split_path(&file, &dir, filename);
  1408. /*
  1409. * sqfs_opendir will uncompress inode and directory tables, and will
  1410. * return a pointer to the directory that contains the requested file.
  1411. */
  1412. ret = sqfs_opendir(dir, &dirsp);
  1413. if (ret) {
  1414. ret = -EINVAL;
  1415. goto free_strings;
  1416. }
  1417. dirs = (struct squashfs_dir_stream *)dirsp;
  1418. while (!sqfs_readdir(dirsp, &dent)) {
  1419. ret = strcmp(dent->name, file);
  1420. if (!ret)
  1421. break;
  1422. free(dirs->entry);
  1423. dirs->entry = NULL;
  1424. }
  1425. sqfs_closedir(dirsp);
  1426. free_strings:
  1427. free(dir);
  1428. free(file);
  1429. return ret == 0;
  1430. }
  1431. void sqfs_close(void)
  1432. {
  1433. sqfs_decompressor_cleanup(&ctxt);
  1434. free(ctxt.sblk);
  1435. ctxt.sblk = NULL;
  1436. ctxt.cur_dev = NULL;
  1437. }
  1438. void sqfs_closedir(struct fs_dir_stream *dirs)
  1439. {
  1440. struct squashfs_dir_stream *sqfs_dirs;
  1441. if (!dirs)
  1442. return;
  1443. sqfs_dirs = (struct squashfs_dir_stream *)dirs;
  1444. free(sqfs_dirs->inode_table);
  1445. free(sqfs_dirs->dir_table);
  1446. free(sqfs_dirs->dir_header);
  1447. free(sqfs_dirs);
  1448. }