sqfs.c 40 KB

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