sfs.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. /* sfs.c - Amiga Smart FileSystem. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/err.h>
  20. #include <grub/file.h>
  21. #include <grub/mm.h>
  22. #include <grub/misc.h>
  23. #include <grub/disk.h>
  24. #include <grub/dl.h>
  25. #include <grub/types.h>
  26. #include <grub/fshelp.h>
  27. #include <grub/charset.h>
  28. GRUB_MOD_LICENSE ("GPLv3+");
  29. /* The common header for a block. */
  30. struct grub_sfs_bheader
  31. {
  32. grub_uint8_t magic[4];
  33. grub_uint32_t chksum;
  34. grub_uint32_t ipointtomyself;
  35. } GRUB_PACKED;
  36. /* The sfs rootblock. */
  37. struct grub_sfs_rblock
  38. {
  39. struct grub_sfs_bheader header;
  40. grub_uint32_t version;
  41. grub_uint32_t createtime;
  42. grub_uint8_t flags;
  43. grub_uint8_t unused1[31];
  44. grub_uint32_t blocksize;
  45. grub_uint8_t unused2[40];
  46. grub_uint8_t unused3[8];
  47. grub_uint32_t rootobject;
  48. grub_uint32_t btree;
  49. } GRUB_PACKED;
  50. enum
  51. {
  52. FLAGS_CASE_SENSITIVE = 0x80
  53. };
  54. /* A SFS object container. */
  55. struct grub_sfs_obj
  56. {
  57. grub_uint8_t unused1[4];
  58. grub_uint32_t nodeid;
  59. grub_uint8_t unused2[4];
  60. union
  61. {
  62. struct
  63. {
  64. grub_uint32_t first_block;
  65. grub_uint32_t size;
  66. } GRUB_PACKED file;
  67. struct
  68. {
  69. grub_uint32_t hashtable;
  70. grub_uint32_t dir_objc;
  71. } GRUB_PACKED dir;
  72. } file_dir;
  73. grub_uint32_t mtime;
  74. grub_uint8_t type;
  75. grub_uint8_t filename[1];
  76. grub_uint8_t comment[1];
  77. } GRUB_PACKED;
  78. #define GRUB_SFS_TYPE_DELETED 32
  79. #define GRUB_SFS_TYPE_SYMLINK 64
  80. #define GRUB_SFS_TYPE_DIR 128
  81. /* A SFS object container. */
  82. struct grub_sfs_objc
  83. {
  84. struct grub_sfs_bheader header;
  85. grub_uint32_t parent;
  86. grub_uint32_t next;
  87. grub_uint32_t prev;
  88. /* The amount of objects depends on the blocksize. */
  89. struct grub_sfs_obj objects[1];
  90. } GRUB_PACKED;
  91. struct grub_sfs_btree_node
  92. {
  93. grub_uint32_t key;
  94. grub_uint32_t data;
  95. } GRUB_PACKED;
  96. struct grub_sfs_btree_extent
  97. {
  98. grub_uint32_t key;
  99. grub_uint32_t next;
  100. grub_uint32_t prev;
  101. grub_uint16_t size;
  102. } GRUB_PACKED;
  103. struct grub_sfs_btree
  104. {
  105. struct grub_sfs_bheader header;
  106. grub_uint16_t nodes;
  107. grub_uint8_t leaf;
  108. grub_uint8_t nodesize;
  109. /* Normally this can be kind of node, but just extents are
  110. supported. */
  111. struct grub_sfs_btree_node node[1];
  112. } GRUB_PACKED;
  113. struct cache_entry
  114. {
  115. grub_uint32_t off;
  116. grub_uint32_t block;
  117. };
  118. struct grub_fshelp_node
  119. {
  120. struct grub_sfs_data *data;
  121. grub_uint32_t block;
  122. grub_uint32_t size;
  123. grub_uint32_t mtime;
  124. grub_uint32_t cache_off;
  125. grub_uint32_t next_extent;
  126. grub_size_t cache_allocated;
  127. grub_size_t cache_size;
  128. struct cache_entry *cache;
  129. };
  130. /* Information about a "mounted" sfs filesystem. */
  131. struct grub_sfs_data
  132. {
  133. struct grub_sfs_rblock rblock;
  134. struct grub_fshelp_node diropen;
  135. grub_disk_t disk;
  136. /* Log of blocksize in sectors. */
  137. int log_blocksize;
  138. int fshelp_flags;
  139. /* Label of the filesystem. */
  140. char *label;
  141. };
  142. static grub_dl_t my_mod;
  143. /* Lookup the extent starting with BLOCK in the filesystem described
  144. by DATA. Return the extent size in SIZE and the following extent
  145. in NEXTEXT. */
  146. static grub_err_t
  147. grub_sfs_read_extent (struct grub_sfs_data *data, unsigned int block,
  148. grub_uint32_t *size, grub_uint32_t *nextext)
  149. {
  150. char *treeblock;
  151. struct grub_sfs_btree *tree;
  152. int i;
  153. grub_uint32_t next;
  154. grub_size_t blocksize = GRUB_DISK_SECTOR_SIZE << data->log_blocksize;
  155. treeblock = grub_malloc (blocksize);
  156. if (!treeblock)
  157. return grub_errno;
  158. next = grub_be_to_cpu32 (data->rblock.btree);
  159. tree = (struct grub_sfs_btree *) treeblock;
  160. /* Handle this level in the btree. */
  161. do
  162. {
  163. grub_uint16_t nnodes;
  164. grub_disk_read (data->disk,
  165. ((grub_disk_addr_t) next) << data->log_blocksize,
  166. 0, blocksize, treeblock);
  167. if (grub_errno)
  168. {
  169. grub_free (treeblock);
  170. return grub_errno;
  171. }
  172. nnodes = grub_be_to_cpu16 (tree->nodes);
  173. if (nnodes * (grub_uint32_t) (tree)->nodesize > blocksize)
  174. break;
  175. for (i = (int) nnodes - 1; i >= 0; i--)
  176. {
  177. #define EXTNODE(tree, index) \
  178. ((struct grub_sfs_btree_node *) (((char *) &(tree)->node[0]) \
  179. + (index) * (tree)->nodesize))
  180. /* Follow the tree down to the leaf level. */
  181. if ((grub_be_to_cpu32 (EXTNODE(tree, i)->key) <= block)
  182. && !tree->leaf)
  183. {
  184. next = grub_be_to_cpu32 (EXTNODE (tree, i)->data);
  185. break;
  186. }
  187. /* If the leaf level is reached, just find the correct extent. */
  188. if (grub_be_to_cpu32 (EXTNODE (tree, i)->key) == block && tree->leaf)
  189. {
  190. struct grub_sfs_btree_extent *extent;
  191. extent = (struct grub_sfs_btree_extent *) EXTNODE (tree, i);
  192. /* We found a correct leaf. */
  193. *size = grub_be_to_cpu16 (extent->size);
  194. *nextext = grub_be_to_cpu32 (extent->next);
  195. grub_free (treeblock);
  196. return 0;
  197. }
  198. #undef EXTNODE
  199. }
  200. } while (!tree->leaf);
  201. grub_free (treeblock);
  202. return grub_error (GRUB_ERR_FILE_READ_ERROR, "SFS extent not found");
  203. }
  204. static grub_disk_addr_t
  205. grub_sfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
  206. {
  207. grub_uint32_t blk;
  208. grub_uint32_t size = 0;
  209. grub_uint32_t next = 0;
  210. grub_disk_addr_t off;
  211. struct grub_sfs_data *data = node->data;
  212. /* In case of the first block we don't have to lookup the
  213. extent, the minimum size is always 1. */
  214. if (fileblock == 0)
  215. return node->block;
  216. if (!node->cache)
  217. {
  218. grub_size_t cache_size;
  219. /* Assume half-max extents (32768 sectors). */
  220. cache_size = ((node->size >> (data->log_blocksize + GRUB_DISK_SECTOR_BITS
  221. + 15))
  222. + 3);
  223. if (cache_size < 8)
  224. cache_size = 8;
  225. node->cache_off = 0;
  226. node->next_extent = node->block;
  227. node->cache_size = 0;
  228. node->cache = grub_malloc (sizeof (node->cache[0]) * cache_size);
  229. if (!node->cache)
  230. {
  231. grub_errno = 0;
  232. node->cache_allocated = 0;
  233. }
  234. else
  235. {
  236. node->cache_allocated = cache_size;
  237. node->cache[0].off = 0;
  238. node->cache[0].block = node->block;
  239. }
  240. }
  241. if (fileblock < node->cache_off)
  242. {
  243. unsigned int i = 0;
  244. int j, lg;
  245. for (lg = 0; node->cache_size >> lg; lg++);
  246. for (j = lg - 1; j >= 0; j--)
  247. if ((i | (1 << j)) < node->cache_size
  248. && node->cache[(i | (1 << j))].off <= fileblock)
  249. i |= (1 << j);
  250. return node->cache[i].block + fileblock - node->cache[i].off;
  251. }
  252. off = node->cache_off;
  253. blk = node->next_extent;
  254. while (blk)
  255. {
  256. grub_err_t err;
  257. err = grub_sfs_read_extent (node->data, blk, &size, &next);
  258. if (err)
  259. return 0;
  260. if (node->cache && node->cache_size >= node->cache_allocated)
  261. {
  262. struct cache_entry *e = node->cache;
  263. e = grub_realloc (node->cache,node->cache_allocated * 2
  264. * sizeof (e[0]));
  265. if (!e)
  266. {
  267. grub_errno = 0;
  268. grub_free (node->cache);
  269. node->cache = 0;
  270. }
  271. else
  272. {
  273. node->cache_allocated *= 2;
  274. node->cache = e;
  275. }
  276. }
  277. if (node->cache)
  278. {
  279. node->cache_off = off + size;
  280. node->next_extent = next;
  281. node->cache[node->cache_size].off = off;
  282. node->cache[node->cache_size].block = blk;
  283. node->cache_size++;
  284. }
  285. if (fileblock - off < size)
  286. return fileblock - off + blk;
  287. off += size;
  288. blk = next;
  289. }
  290. grub_error (GRUB_ERR_FILE_READ_ERROR,
  291. "reading a SFS block outside the extent");
  292. return 0;
  293. }
  294. /* Read LEN bytes from the file described by DATA starting with byte
  295. POS. Return the amount of read bytes in READ. */
  296. static grub_ssize_t
  297. grub_sfs_read_file (grub_fshelp_node_t node,
  298. grub_disk_read_hook_t read_hook, void *read_hook_data,
  299. grub_off_t pos, grub_size_t len, char *buf)
  300. {
  301. return grub_fshelp_read_file (node->data->disk, node,
  302. read_hook, read_hook_data,
  303. pos, len, buf, grub_sfs_read_block,
  304. node->size, node->data->log_blocksize, 0);
  305. }
  306. static struct grub_sfs_data *
  307. grub_sfs_mount (grub_disk_t disk)
  308. {
  309. struct grub_sfs_data *data;
  310. struct grub_sfs_objc *rootobjc;
  311. char *rootobjc_data = 0;
  312. grub_uint32_t blk;
  313. data = grub_malloc (sizeof (*data));
  314. if (!data)
  315. return 0;
  316. /* Read the rootblock. */
  317. grub_disk_read (disk, 0, 0, sizeof (struct grub_sfs_rblock),
  318. &data->rblock);
  319. if (grub_errno)
  320. goto fail;
  321. /* Make sure this is a sfs filesystem. */
  322. if (grub_strncmp ((char *) (data->rblock.header.magic), "SFS", 4)
  323. || data->rblock.blocksize == 0
  324. || (data->rblock.blocksize & (data->rblock.blocksize - 1)) != 0
  325. || (data->rblock.blocksize & grub_cpu_to_be32_compile_time (0xf00001ff)))
  326. {
  327. grub_error (GRUB_ERR_BAD_FS, "not a SFS filesystem");
  328. goto fail;
  329. }
  330. for (data->log_blocksize = 9;
  331. (1U << data->log_blocksize) < grub_be_to_cpu32 (data->rblock.blocksize);
  332. data->log_blocksize++);
  333. data->log_blocksize -= GRUB_DISK_SECTOR_BITS;
  334. if (data->rblock.flags & FLAGS_CASE_SENSITIVE)
  335. data->fshelp_flags = 0;
  336. else
  337. data->fshelp_flags = GRUB_FSHELP_CASE_INSENSITIVE;
  338. rootobjc_data = grub_malloc (GRUB_DISK_SECTOR_SIZE << data->log_blocksize);
  339. if (! rootobjc_data)
  340. goto fail;
  341. /* Read the root object container. */
  342. grub_disk_read (disk, ((grub_disk_addr_t) grub_be_to_cpu32 (data->rblock.rootobject))
  343. << data->log_blocksize, 0,
  344. GRUB_DISK_SECTOR_SIZE << data->log_blocksize, rootobjc_data);
  345. if (grub_errno)
  346. goto fail;
  347. rootobjc = (struct grub_sfs_objc *) rootobjc_data;
  348. blk = grub_be_to_cpu32 (rootobjc->objects[0].file_dir.dir.dir_objc);
  349. data->diropen.size = 0;
  350. data->diropen.block = blk;
  351. data->diropen.data = data;
  352. data->diropen.cache = 0;
  353. data->disk = disk;
  354. data->label = grub_strdup ((char *) (rootobjc->objects[0].filename));
  355. grub_free (rootobjc_data);
  356. return data;
  357. fail:
  358. if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
  359. grub_error (GRUB_ERR_BAD_FS, "not an SFS filesystem");
  360. grub_free (data);
  361. grub_free (rootobjc_data);
  362. return 0;
  363. }
  364. static char *
  365. grub_sfs_read_symlink (grub_fshelp_node_t node)
  366. {
  367. struct grub_sfs_data *data = node->data;
  368. char *symlink;
  369. char *block;
  370. block = grub_malloc (GRUB_DISK_SECTOR_SIZE << data->log_blocksize);
  371. if (!block)
  372. return 0;
  373. grub_disk_read (data->disk, ((grub_disk_addr_t) node->block)
  374. << data->log_blocksize,
  375. 0, GRUB_DISK_SECTOR_SIZE << data->log_blocksize, block);
  376. if (grub_errno)
  377. {
  378. grub_free (block);
  379. return 0;
  380. }
  381. /* This is just a wild guess, but it always worked for me. How the
  382. SLNK block looks like is not documented in the SFS docs. */
  383. symlink = grub_malloc (((GRUB_DISK_SECTOR_SIZE << data->log_blocksize)
  384. - 24) * GRUB_MAX_UTF8_PER_LATIN1 + 1);
  385. if (!symlink)
  386. {
  387. grub_free (block);
  388. return 0;
  389. }
  390. *grub_latin1_to_utf8 ((grub_uint8_t *) symlink, (grub_uint8_t *) &block[24],
  391. (GRUB_DISK_SECTOR_SIZE << data->log_blocksize) - 24) = '\0';
  392. grub_free (block);
  393. return symlink;
  394. }
  395. /* Helper for grub_sfs_iterate_dir. */
  396. static int
  397. grub_sfs_create_node (struct grub_fshelp_node **node,
  398. struct grub_sfs_data *data,
  399. const char *name,
  400. grub_uint32_t block, grub_uint32_t size, int type,
  401. grub_uint32_t mtime,
  402. grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
  403. {
  404. grub_size_t len = grub_strlen (name);
  405. grub_uint8_t *name_u8;
  406. int ret;
  407. *node = grub_malloc (sizeof (**node));
  408. if (!*node)
  409. return 1;
  410. name_u8 = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1);
  411. if (!name_u8)
  412. {
  413. grub_free (*node);
  414. return 1;
  415. }
  416. (*node)->data = data;
  417. (*node)->size = size;
  418. (*node)->block = block;
  419. (*node)->mtime = mtime;
  420. (*node)->cache = 0;
  421. (*node)->cache_off = 0;
  422. (*node)->next_extent = block;
  423. (*node)->cache_size = 0;
  424. (*node)->cache_allocated = 0;
  425. *grub_latin1_to_utf8 (name_u8, (const grub_uint8_t *) name, len) = '\0';
  426. ret = hook ((char *) name_u8, type | data->fshelp_flags, *node, hook_data);
  427. grub_free (name_u8);
  428. return ret;
  429. }
  430. static int
  431. grub_sfs_iterate_dir (grub_fshelp_node_t dir,
  432. grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
  433. {
  434. struct grub_fshelp_node *node = 0;
  435. struct grub_sfs_data *data = dir->data;
  436. char *objc_data;
  437. struct grub_sfs_objc *objc;
  438. unsigned int next = dir->block;
  439. grub_uint32_t pos;
  440. objc_data = grub_malloc (GRUB_DISK_SECTOR_SIZE << data->log_blocksize);
  441. if (!objc_data)
  442. goto fail;
  443. /* The Object container can consist of multiple blocks, iterate over
  444. every block. */
  445. while (next)
  446. {
  447. grub_disk_read (data->disk, ((grub_disk_addr_t) next)
  448. << data->log_blocksize, 0,
  449. GRUB_DISK_SECTOR_SIZE << data->log_blocksize, objc_data);
  450. if (grub_errno)
  451. goto fail;
  452. objc = (struct grub_sfs_objc *) objc_data;
  453. pos = (char *) &objc->objects[0] - (char *) objc;
  454. /* Iterate over all entries in this block. */
  455. while (pos + sizeof (struct grub_sfs_obj)
  456. < (1U << (GRUB_DISK_SECTOR_BITS + data->log_blocksize)))
  457. {
  458. struct grub_sfs_obj *obj;
  459. obj = (struct grub_sfs_obj *) ((char *) objc + pos);
  460. const char *filename = (const char *) obj->filename;
  461. grub_size_t len;
  462. enum grub_fshelp_filetype type;
  463. grub_uint32_t block;
  464. /* The filename and comment dynamically increase the size of
  465. the object. */
  466. len = grub_strlen (filename);
  467. len += grub_strlen (filename + len + 1);
  468. pos += sizeof (*obj) + len;
  469. /* Round up to a multiple of two bytes. */
  470. pos = ((pos + 1) >> 1) << 1;
  471. if (filename[0] == 0)
  472. continue;
  473. /* First check if the file was not deleted. */
  474. if (obj->type & GRUB_SFS_TYPE_DELETED)
  475. continue;
  476. else if (obj->type & GRUB_SFS_TYPE_SYMLINK)
  477. type = GRUB_FSHELP_SYMLINK;
  478. else if (obj->type & GRUB_SFS_TYPE_DIR)
  479. type = GRUB_FSHELP_DIR;
  480. else
  481. type = GRUB_FSHELP_REG;
  482. if (type == GRUB_FSHELP_DIR)
  483. block = grub_be_to_cpu32 (obj->file_dir.dir.dir_objc);
  484. else
  485. block = grub_be_to_cpu32 (obj->file_dir.file.first_block);
  486. if (grub_sfs_create_node (&node, data, filename, block,
  487. grub_be_to_cpu32 (obj->file_dir.file.size),
  488. type, grub_be_to_cpu32 (obj->mtime),
  489. hook, hook_data))
  490. {
  491. grub_free (objc_data);
  492. return 1;
  493. }
  494. }
  495. next = grub_be_to_cpu32 (objc->next);
  496. }
  497. fail:
  498. grub_free (objc_data);
  499. return 0;
  500. }
  501. /* Open a file named NAME and initialize FILE. */
  502. static grub_err_t
  503. grub_sfs_open (struct grub_file *file, const char *name)
  504. {
  505. struct grub_sfs_data *data;
  506. struct grub_fshelp_node *fdiro = 0;
  507. grub_dl_ref (my_mod);
  508. data = grub_sfs_mount (file->device->disk);
  509. if (!data)
  510. goto fail;
  511. grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_sfs_iterate_dir,
  512. grub_sfs_read_symlink, GRUB_FSHELP_REG);
  513. if (grub_errno)
  514. goto fail;
  515. file->size = fdiro->size;
  516. data->diropen = *fdiro;
  517. grub_free (fdiro);
  518. file->data = data;
  519. file->offset = 0;
  520. return 0;
  521. fail:
  522. if (data && fdiro != &data->diropen)
  523. grub_free (fdiro);
  524. if (data)
  525. grub_free (data->label);
  526. grub_free (data);
  527. grub_dl_unref (my_mod);
  528. return grub_errno;
  529. }
  530. static grub_err_t
  531. grub_sfs_close (grub_file_t file)
  532. {
  533. struct grub_sfs_data *data = (struct grub_sfs_data *) file->data;
  534. grub_free (data->diropen.cache);
  535. grub_free (data->label);
  536. grub_free (data);
  537. grub_dl_unref (my_mod);
  538. return GRUB_ERR_NONE;
  539. }
  540. /* Read LEN bytes data from FILE into BUF. */
  541. static grub_ssize_t
  542. grub_sfs_read (grub_file_t file, char *buf, grub_size_t len)
  543. {
  544. struct grub_sfs_data *data = (struct grub_sfs_data *) file->data;
  545. return grub_sfs_read_file (&data->diropen,
  546. file->read_hook, file->read_hook_data,
  547. file->offset, len, buf);
  548. }
  549. /* Context for grub_sfs_dir. */
  550. struct grub_sfs_dir_ctx
  551. {
  552. grub_fs_dir_hook_t hook;
  553. void *hook_data;
  554. };
  555. /* Helper for grub_sfs_dir. */
  556. static int
  557. grub_sfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
  558. grub_fshelp_node_t node, void *data)
  559. {
  560. struct grub_sfs_dir_ctx *ctx = data;
  561. struct grub_dirhook_info info;
  562. grub_memset (&info, 0, sizeof (info));
  563. info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
  564. info.mtime = node->mtime + 8 * 365 * 86400 + 86400 * 2;
  565. info.mtimeset = 1;
  566. grub_free (node->cache);
  567. grub_free (node);
  568. return ctx->hook (filename, &info, ctx->hook_data);
  569. }
  570. static grub_err_t
  571. grub_sfs_dir (grub_device_t device, const char *path,
  572. grub_fs_dir_hook_t hook, void *hook_data)
  573. {
  574. struct grub_sfs_dir_ctx ctx = { hook, hook_data };
  575. struct grub_sfs_data *data = 0;
  576. struct grub_fshelp_node *fdiro = 0;
  577. grub_dl_ref (my_mod);
  578. data = grub_sfs_mount (device->disk);
  579. if (!data)
  580. goto fail;
  581. grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_sfs_iterate_dir,
  582. grub_sfs_read_symlink, GRUB_FSHELP_DIR);
  583. if (grub_errno)
  584. goto fail;
  585. grub_sfs_iterate_dir (fdiro, grub_sfs_dir_iter, &ctx);
  586. fail:
  587. if (data && fdiro != &data->diropen)
  588. grub_free (fdiro);
  589. if (data)
  590. grub_free (data->label);
  591. grub_free (data);
  592. grub_dl_unref (my_mod);
  593. return grub_errno;
  594. }
  595. static grub_err_t
  596. grub_sfs_label (grub_device_t device, char **label)
  597. {
  598. struct grub_sfs_data *data;
  599. grub_disk_t disk = device->disk;
  600. data = grub_sfs_mount (disk);
  601. if (data)
  602. {
  603. grub_size_t len = grub_strlen (data->label);
  604. *label = grub_malloc (len * GRUB_MAX_UTF8_PER_LATIN1 + 1);
  605. if (*label)
  606. *grub_latin1_to_utf8 ((grub_uint8_t *) *label,
  607. (const grub_uint8_t *) data->label,
  608. len) = '\0';
  609. grub_free (data->label);
  610. }
  611. grub_free (data);
  612. return grub_errno;
  613. }
  614. static struct grub_fs grub_sfs_fs =
  615. {
  616. .name = "sfs",
  617. .dir = grub_sfs_dir,
  618. .open = grub_sfs_open,
  619. .read = grub_sfs_read,
  620. .close = grub_sfs_close,
  621. .label = grub_sfs_label,
  622. #ifdef GRUB_UTIL
  623. .reserved_first_sector = 0,
  624. .blocklist_install = 1,
  625. #endif
  626. .next = 0
  627. };
  628. GRUB_MOD_INIT(sfs)
  629. {
  630. grub_fs_register (&grub_sfs_fs);
  631. my_mod = mod;
  632. }
  633. GRUB_MOD_FINI(sfs)
  634. {
  635. grub_fs_unregister (&grub_sfs_fs);
  636. }