affs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. /* affs.c - Amiga Fast 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. #include <grub/lockdown.h>
  29. GRUB_MOD_LICENSE ("GPLv3+");
  30. /* The affs bootblock. */
  31. struct grub_affs_bblock
  32. {
  33. grub_uint8_t type[3];
  34. grub_uint8_t flags;
  35. grub_uint32_t checksum;
  36. grub_uint32_t rootblock;
  37. } GRUB_PACKED;
  38. /* Set if the filesystem is a AFFS filesystem. Otherwise this is an
  39. OFS filesystem. */
  40. #define GRUB_AFFS_FLAG_FFS 1
  41. /* The affs rootblock. */
  42. struct grub_affs_rblock
  43. {
  44. grub_uint32_t type;
  45. grub_uint8_t unused1[8];
  46. grub_uint32_t htsize;
  47. grub_uint32_t unused2;
  48. grub_uint32_t checksum;
  49. grub_uint32_t hashtable[1];
  50. } GRUB_PACKED;
  51. struct grub_affs_time
  52. {
  53. grub_int32_t day;
  54. grub_uint32_t min;
  55. grub_uint32_t hz;
  56. } GRUB_PACKED;
  57. /* The second part of a file header block. */
  58. struct grub_affs_file
  59. {
  60. grub_uint8_t unused1[12];
  61. grub_uint32_t size;
  62. grub_uint8_t unused2[92];
  63. struct grub_affs_time mtime;
  64. grub_uint8_t namelen;
  65. grub_uint8_t name[30];
  66. grub_uint8_t unused3[5];
  67. grub_uint32_t hardlink;
  68. grub_uint32_t unused4[6];
  69. grub_uint32_t next;
  70. grub_uint32_t parent;
  71. grub_uint32_t extension;
  72. grub_uint32_t type;
  73. } GRUB_PACKED;
  74. /* The location of `struct grub_affs_file' relative to the end of a
  75. file header block. */
  76. #define GRUB_AFFS_FILE_LOCATION 200
  77. /* The offset in both the rootblock and the file header block for the
  78. hashtable, symlink and block pointers (all synonyms). */
  79. #define GRUB_AFFS_HASHTABLE_OFFSET 24
  80. #define GRUB_AFFS_BLOCKPTR_OFFSET 24
  81. #define GRUB_AFFS_SYMLINK_OFFSET 24
  82. enum
  83. {
  84. GRUB_AFFS_FILETYPE_DIR = 2,
  85. GRUB_AFFS_FILETYPE_SYMLINK = 3,
  86. GRUB_AFFS_FILETYPE_HARDLINK = 0xfffffffc,
  87. GRUB_AFFS_FILETYPE_REG = 0xfffffffd
  88. };
  89. #define AFFS_MAX_LOG_BLOCK_SIZE 4
  90. #define AFFS_MAX_SUPERBLOCK 1
  91. struct grub_fshelp_node
  92. {
  93. struct grub_affs_data *data;
  94. grub_uint32_t block;
  95. struct grub_fshelp_node *parent;
  96. struct grub_affs_file di;
  97. grub_uint32_t *block_cache;
  98. grub_uint32_t last_block_cache;
  99. };
  100. /* Information about a "mounted" affs filesystem. */
  101. struct grub_affs_data
  102. {
  103. struct grub_affs_bblock bblock;
  104. struct grub_fshelp_node diropen;
  105. grub_disk_t disk;
  106. /* Log blocksize in sectors. */
  107. int log_blocksize;
  108. /* The number of entries in the hashtable. */
  109. unsigned int htsize;
  110. };
  111. static grub_dl_t my_mod;
  112. static grub_disk_addr_t
  113. grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
  114. {
  115. grub_uint32_t target, curblock;
  116. grub_uint32_t pos;
  117. struct grub_affs_file file;
  118. struct grub_affs_data *data = node->data;
  119. grub_uint64_t mod;
  120. if (!node->block_cache)
  121. {
  122. node->block_cache = grub_malloc (((grub_be_to_cpu32 (node->di.size)
  123. >> (9 + node->data->log_blocksize))
  124. / data->htsize + 2)
  125. * sizeof (node->block_cache[0]));
  126. if (!node->block_cache)
  127. return -1;
  128. node->last_block_cache = 0;
  129. node->block_cache[0] = node->block;
  130. }
  131. /* Files are at most 2G on AFFS, so no need for 64-bit division. */
  132. target = (grub_uint32_t) fileblock / data->htsize;
  133. mod = (grub_uint32_t) fileblock % data->htsize;
  134. /* Find the block that points to the fileblock we are looking up by
  135. following the chain until the right table is reached. */
  136. for (curblock = node->last_block_cache + 1; curblock < target + 1; curblock++)
  137. {
  138. grub_disk_read (data->disk,
  139. (((grub_uint64_t) node->block_cache[curblock - 1] + 1)
  140. << data->log_blocksize) - 1,
  141. GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
  142. sizeof (file), &file);
  143. if (grub_errno)
  144. return 0;
  145. node->block_cache[curblock] = grub_be_to_cpu32 (file.extension);
  146. node->last_block_cache = curblock;
  147. }
  148. /* Translate the fileblock to the block within the right table. */
  149. grub_disk_read (data->disk, (grub_uint64_t) node->block_cache[target]
  150. << data->log_blocksize,
  151. GRUB_AFFS_BLOCKPTR_OFFSET
  152. + (data->htsize - mod - 1) * sizeof (pos),
  153. sizeof (pos), &pos);
  154. if (grub_errno)
  155. return 0;
  156. return grub_be_to_cpu32 (pos);
  157. }
  158. static struct grub_affs_data *
  159. grub_affs_mount (grub_disk_t disk)
  160. {
  161. struct grub_affs_data *data;
  162. grub_uint32_t *rootblock = 0;
  163. struct grub_affs_rblock *rblock = 0;
  164. int log_blocksize = 0;
  165. int bsnum = 0;
  166. data = grub_zalloc (sizeof (struct grub_affs_data));
  167. if (!data)
  168. return 0;
  169. for (bsnum = 0; bsnum < AFFS_MAX_SUPERBLOCK + 1; bsnum++)
  170. {
  171. /* Read the bootblock. */
  172. grub_disk_read (disk, bsnum, 0, sizeof (struct grub_affs_bblock),
  173. &data->bblock);
  174. if (grub_errno)
  175. goto fail;
  176. /* Make sure this is an affs filesystem. */
  177. if (grub_strncmp ((char *) (data->bblock.type), "DOS", 3) != 0
  178. /* Test if the filesystem is a OFS filesystem. */
  179. || !(data->bblock.flags & GRUB_AFFS_FLAG_FFS))
  180. continue;
  181. /* No sane person uses more than 8KB for a block. At least I hope
  182. for that person because in that case this won't work. */
  183. if (!rootblock)
  184. rootblock = grub_malloc (GRUB_DISK_SECTOR_SIZE
  185. << AFFS_MAX_LOG_BLOCK_SIZE);
  186. if (!rootblock)
  187. goto fail;
  188. rblock = (struct grub_affs_rblock *) rootblock;
  189. /* The filesystem blocksize is not stored anywhere in the filesystem
  190. itself. One way to determine it is try reading blocks for the
  191. rootblock until the checksum is correct. */
  192. for (log_blocksize = 0; log_blocksize <= AFFS_MAX_LOG_BLOCK_SIZE;
  193. log_blocksize++)
  194. {
  195. grub_uint32_t *currblock = rootblock;
  196. unsigned int i;
  197. grub_uint32_t checksum = 0;
  198. /* Read the rootblock. */
  199. grub_disk_read (disk,
  200. (grub_uint64_t) grub_be_to_cpu32 (data->bblock.rootblock)
  201. << log_blocksize, 0,
  202. GRUB_DISK_SECTOR_SIZE << log_blocksize, rootblock);
  203. if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
  204. {
  205. grub_errno = 0;
  206. break;
  207. }
  208. if (grub_errno)
  209. goto fail;
  210. if (rblock->type != grub_cpu_to_be32_compile_time (2)
  211. || rblock->htsize == 0
  212. || currblock[(GRUB_DISK_SECTOR_SIZE << log_blocksize)
  213. / sizeof (*currblock) - 1]
  214. != grub_cpu_to_be32_compile_time (1))
  215. continue;
  216. for (i = 0; i < (GRUB_DISK_SECTOR_SIZE << log_blocksize)
  217. / sizeof (*currblock);
  218. i++)
  219. checksum += grub_be_to_cpu32 (currblock[i]);
  220. if (checksum == 0)
  221. {
  222. data->log_blocksize = log_blocksize;
  223. data->disk = disk;
  224. data->htsize = grub_be_to_cpu32 (rblock->htsize);
  225. data->diropen.data = data;
  226. data->diropen.block = grub_be_to_cpu32 (data->bblock.rootblock);
  227. data->diropen.parent = NULL;
  228. grub_memcpy (&data->diropen.di, rootblock,
  229. sizeof (data->diropen.di));
  230. grub_free (rootblock);
  231. return data;
  232. }
  233. }
  234. }
  235. fail:
  236. if (grub_errno == GRUB_ERR_NONE || grub_errno == GRUB_ERR_OUT_OF_RANGE)
  237. grub_error (GRUB_ERR_BAD_FS, "not an AFFS filesystem");
  238. grub_free (data);
  239. grub_free (rootblock);
  240. return 0;
  241. }
  242. static char *
  243. grub_affs_read_symlink (grub_fshelp_node_t node)
  244. {
  245. struct grub_affs_data *data = node->data;
  246. grub_uint8_t *latin1, *utf8;
  247. const grub_size_t symlink_size = ((GRUB_DISK_SECTOR_SIZE
  248. << data->log_blocksize) - GRUB_AFFS_SYMLINK_OFFSET);
  249. latin1 = grub_malloc (symlink_size + 1);
  250. if (!latin1)
  251. return 0;
  252. grub_disk_read (data->disk,
  253. (grub_uint64_t) node->block << data->log_blocksize,
  254. GRUB_AFFS_SYMLINK_OFFSET,
  255. symlink_size, latin1);
  256. if (grub_errno)
  257. {
  258. grub_free (latin1);
  259. return 0;
  260. }
  261. latin1[symlink_size] = 0;
  262. utf8 = grub_calloc (GRUB_MAX_UTF8_PER_LATIN1 + 1, symlink_size);
  263. if (!utf8)
  264. {
  265. grub_free (latin1);
  266. return 0;
  267. }
  268. *grub_latin1_to_utf8 (utf8, latin1, symlink_size) = '\0';
  269. grub_dprintf ("affs", "Symlink: `%s'\n", utf8);
  270. grub_free (latin1);
  271. if (utf8[0] == ':')
  272. utf8[0] = '/';
  273. return (char *) utf8;
  274. }
  275. /* Helper for grub_affs_iterate_dir. */
  276. static int
  277. grub_affs_create_node (grub_fshelp_node_t dir,
  278. grub_fshelp_iterate_dir_hook_t hook, void *hook_data,
  279. struct grub_fshelp_node **node,
  280. grub_uint32_t block, const struct grub_affs_file *fil)
  281. {
  282. struct grub_affs_data *data = dir->data;
  283. int type = GRUB_FSHELP_REG;
  284. grub_uint8_t name_u8[sizeof (fil->name) * GRUB_MAX_UTF8_PER_LATIN1 + 1];
  285. grub_size_t len;
  286. unsigned int nest;
  287. *node = grub_zalloc (sizeof (**node));
  288. if (!*node)
  289. return 1;
  290. (*node)->data = data;
  291. (*node)->block = block;
  292. (*node)->parent = dir;
  293. len = fil->namelen;
  294. if (len > sizeof (fil->name))
  295. len = sizeof (fil->name);
  296. *grub_latin1_to_utf8 (name_u8, fil->name, len) = '\0';
  297. (*node)->di = *fil;
  298. for (nest = 0; nest < 8; nest++)
  299. {
  300. switch ((*node)->di.type)
  301. {
  302. case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_REG):
  303. type = GRUB_FSHELP_REG;
  304. break;
  305. case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_DIR):
  306. type = GRUB_FSHELP_DIR;
  307. break;
  308. case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_SYMLINK):
  309. type = GRUB_FSHELP_SYMLINK;
  310. break;
  311. case grub_cpu_to_be32_compile_time (GRUB_AFFS_FILETYPE_HARDLINK):
  312. {
  313. grub_err_t err;
  314. (*node)->block = grub_be_to_cpu32 ((*node)->di.hardlink);
  315. err = grub_disk_read (data->disk,
  316. (((grub_uint64_t) (*node)->block + 1) << data->log_blocksize)
  317. - 1,
  318. GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
  319. sizeof ((*node)->di), (char *) &(*node)->di);
  320. if (err)
  321. {
  322. grub_free (*node);
  323. return 1;
  324. }
  325. continue;
  326. }
  327. default:
  328. {
  329. grub_free (*node);
  330. return 0;
  331. }
  332. }
  333. break;
  334. }
  335. if (nest == 8)
  336. {
  337. grub_free (*node);
  338. return 0;
  339. }
  340. type |= GRUB_FSHELP_CASE_INSENSITIVE;
  341. if (hook ((char *) name_u8, type, *node, hook_data))
  342. {
  343. *node = 0;
  344. return 1;
  345. }
  346. *node = 0;
  347. return 0;
  348. }
  349. static int
  350. grub_affs_iterate_dir (grub_fshelp_node_t dir,
  351. grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
  352. {
  353. unsigned int i;
  354. struct grub_affs_file file;
  355. struct grub_fshelp_node *node, *orig_node;
  356. struct grub_affs_data *data = dir->data;
  357. grub_uint32_t *hashtable;
  358. /* Create the directory entries for `.' and `..'. */
  359. node = orig_node = grub_zalloc (sizeof (*node));
  360. if (!node)
  361. return 1;
  362. *node = *dir;
  363. if (hook (".", GRUB_FSHELP_DIR, node, hook_data))
  364. return 1;
  365. if (dir->parent)
  366. {
  367. *node = *dir->parent;
  368. if (hook ("..", GRUB_FSHELP_DIR, node, hook_data))
  369. return 1;
  370. }
  371. hashtable = grub_calloc (data->htsize, sizeof (*hashtable));
  372. if (!hashtable)
  373. return 1;
  374. grub_disk_read (data->disk,
  375. (grub_uint64_t) dir->block << data->log_blocksize,
  376. GRUB_AFFS_HASHTABLE_OFFSET,
  377. data->htsize * sizeof (*hashtable), (char *) hashtable);
  378. if (grub_errno)
  379. goto fail;
  380. for (i = 0; i < data->htsize; i++)
  381. {
  382. grub_uint32_t next;
  383. if (!hashtable[i])
  384. continue;
  385. /* Every entry in the hashtable can be chained. Read the entire
  386. chain. */
  387. next = grub_be_to_cpu32 (hashtable[i]);
  388. while (next)
  389. {
  390. grub_disk_read (data->disk,
  391. (((grub_uint64_t) next + 1) << data->log_blocksize)
  392. - 1,
  393. GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
  394. sizeof (file), (char *) &file);
  395. if (grub_errno)
  396. goto fail;
  397. if (grub_affs_create_node (dir, hook, hook_data, &node, next, &file))
  398. {
  399. /* Node has been replaced in function. */
  400. grub_free (orig_node);
  401. grub_free (hashtable);
  402. return 1;
  403. }
  404. next = grub_be_to_cpu32 (file.next);
  405. }
  406. }
  407. fail:
  408. grub_free (orig_node);
  409. grub_free (hashtable);
  410. return 0;
  411. }
  412. /* Open a file named NAME and initialize FILE. */
  413. static grub_err_t
  414. grub_affs_open (struct grub_file *file, const char *name)
  415. {
  416. struct grub_affs_data *data;
  417. struct grub_fshelp_node *fdiro = 0;
  418. grub_dl_ref (my_mod);
  419. data = grub_affs_mount (file->device->disk);
  420. if (!data)
  421. goto fail;
  422. grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_affs_iterate_dir,
  423. grub_affs_read_symlink, GRUB_FSHELP_REG);
  424. if (grub_errno)
  425. goto fail;
  426. file->size = grub_be_to_cpu32 (fdiro->di.size);
  427. data->diropen = *fdiro;
  428. grub_free (fdiro);
  429. file->data = data;
  430. file->offset = 0;
  431. return 0;
  432. fail:
  433. if (data && fdiro != &data->diropen)
  434. grub_free (fdiro);
  435. grub_free (data);
  436. grub_dl_unref (my_mod);
  437. return grub_errno;
  438. }
  439. static grub_err_t
  440. grub_affs_close (grub_file_t file)
  441. {
  442. struct grub_affs_data *data =
  443. (struct grub_affs_data *) file->data;
  444. grub_free (data->diropen.block_cache);
  445. grub_free (file->data);
  446. grub_dl_unref (my_mod);
  447. return GRUB_ERR_NONE;
  448. }
  449. /* Read LEN bytes data from FILE into BUF. */
  450. static grub_ssize_t
  451. grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
  452. {
  453. struct grub_affs_data *data =
  454. (struct grub_affs_data *) file->data;
  455. return grub_fshelp_read_file (data->diropen.data->disk, &data->diropen,
  456. file->read_hook, file->read_hook_data,
  457. file->offset, len, buf, grub_affs_read_block,
  458. grub_be_to_cpu32 (data->diropen.di.size),
  459. data->log_blocksize, 0);
  460. }
  461. static grub_int32_t
  462. aftime2ctime (const struct grub_affs_time *t)
  463. {
  464. return grub_be_to_cpu32 (t->day) * 86400
  465. + grub_be_to_cpu32 (t->min) * 60
  466. + grub_be_to_cpu32 (t->hz) / 50
  467. + 8 * 365 * 86400 + 86400 * 2;
  468. }
  469. /* Context for grub_affs_dir. */
  470. struct grub_affs_dir_ctx
  471. {
  472. grub_fs_dir_hook_t hook;
  473. void *hook_data;
  474. };
  475. /* Helper for grub_affs_dir. */
  476. static int
  477. grub_affs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
  478. grub_fshelp_node_t node, void *data)
  479. {
  480. struct grub_affs_dir_ctx *ctx = data;
  481. struct grub_dirhook_info info;
  482. grub_memset (&info, 0, sizeof (info));
  483. info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
  484. info.mtimeset = 1;
  485. info.mtime = aftime2ctime (&node->di.mtime);
  486. grub_free (node);
  487. return ctx->hook (filename, &info, ctx->hook_data);
  488. }
  489. static grub_err_t
  490. grub_affs_dir (grub_device_t device, const char *path,
  491. grub_fs_dir_hook_t hook, void *hook_data)
  492. {
  493. struct grub_affs_dir_ctx ctx = { hook, hook_data };
  494. struct grub_affs_data *data = 0;
  495. struct grub_fshelp_node *fdiro = 0;
  496. grub_dl_ref (my_mod);
  497. data = grub_affs_mount (device->disk);
  498. if (!data)
  499. goto fail;
  500. grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_affs_iterate_dir,
  501. grub_affs_read_symlink, GRUB_FSHELP_DIR);
  502. if (grub_errno)
  503. goto fail;
  504. grub_affs_iterate_dir (fdiro, grub_affs_dir_iter, &ctx);
  505. fail:
  506. if (data && fdiro != &data->diropen)
  507. grub_free (fdiro);
  508. grub_free (data);
  509. grub_dl_unref (my_mod);
  510. return grub_errno;
  511. }
  512. static grub_err_t
  513. grub_affs_label (grub_device_t device, char **label)
  514. {
  515. struct grub_affs_data *data;
  516. struct grub_affs_file file;
  517. grub_disk_t disk = device->disk;
  518. grub_dl_ref (my_mod);
  519. data = grub_affs_mount (disk);
  520. if (data)
  521. {
  522. grub_size_t len;
  523. /* The rootblock maps quite well on a file header block, it's
  524. something we can use here. */
  525. grub_disk_read (data->disk,
  526. (((grub_uint64_t)
  527. grub_be_to_cpu32 (data->bblock.rootblock) + 1)
  528. << data->log_blocksize) - 1,
  529. GRUB_DISK_SECTOR_SIZE - GRUB_AFFS_FILE_LOCATION,
  530. sizeof (file), &file);
  531. if (grub_errno)
  532. return grub_errno;
  533. len = file.namelen;
  534. if (len > sizeof (file.name))
  535. len = sizeof (file.name);
  536. *label = grub_calloc (GRUB_MAX_UTF8_PER_LATIN1 + 1, len);
  537. if (*label)
  538. *grub_latin1_to_utf8 ((grub_uint8_t *) *label, file.name, len) = '\0';
  539. }
  540. else
  541. *label = 0;
  542. grub_dl_unref (my_mod);
  543. grub_free (data);
  544. return grub_errno;
  545. }
  546. static grub_err_t
  547. grub_affs_mtime (grub_device_t device, grub_int64_t *t)
  548. {
  549. struct grub_affs_data *data;
  550. grub_disk_t disk = device->disk;
  551. struct grub_affs_time af_time;
  552. *t = 0;
  553. grub_dl_ref (my_mod);
  554. data = grub_affs_mount (disk);
  555. if (!data)
  556. {
  557. grub_dl_unref (my_mod);
  558. return grub_errno;
  559. }
  560. grub_disk_read (data->disk,
  561. (((grub_uint64_t)
  562. grub_be_to_cpu32 (data->bblock.rootblock) + 1)
  563. << data->log_blocksize) - 1,
  564. GRUB_DISK_SECTOR_SIZE - 40,
  565. sizeof (af_time), &af_time);
  566. if (grub_errno)
  567. {
  568. grub_dl_unref (my_mod);
  569. grub_free (data);
  570. return grub_errno;
  571. }
  572. *t = aftime2ctime (&af_time);
  573. grub_dl_unref (my_mod);
  574. grub_free (data);
  575. return GRUB_ERR_NONE;
  576. }
  577. static struct grub_fs grub_affs_fs =
  578. {
  579. .name = "affs",
  580. .fs_dir = grub_affs_dir,
  581. .fs_open = grub_affs_open,
  582. .fs_read = grub_affs_read,
  583. .fs_close = grub_affs_close,
  584. .fs_label = grub_affs_label,
  585. .fs_mtime = grub_affs_mtime,
  586. #ifdef GRUB_UTIL
  587. .reserved_first_sector = 0,
  588. .blocklist_install = 1,
  589. #endif
  590. .next = 0
  591. };
  592. GRUB_MOD_INIT(affs)
  593. {
  594. if (!grub_is_lockdown ())
  595. {
  596. grub_affs_fs.mod = mod;
  597. grub_fs_register (&grub_affs_fs);
  598. }
  599. my_mod = mod;
  600. }
  601. GRUB_MOD_FINI(affs)
  602. {
  603. if (!grub_is_lockdown ())
  604. grub_fs_unregister (&grub_affs_fs);
  605. }