sqfs.c 37 KB

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