]>
Commit | Line | Data |
---|---|---|
86cb4f54 | 1 | /* afs.c - The native AtheOS file-system. */ |
2 | /* | |
3 | * GRUB -- GRand Unified Bootloader | |
4 | * Copyright (C) 2008 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 | ||
20 | #include <grub/err.h> | |
21 | #include <grub/file.h> | |
22 | #include <grub/mm.h> | |
23 | #include <grub/misc.h> | |
24 | #include <grub/disk.h> | |
25 | #include <grub/dl.h> | |
26 | #include <grub/types.h> | |
27 | #include <grub/fshelp.h> | |
28 | ||
29 | #define GRUB_AFS_DIRECT_BLOCK_COUNT 12 | |
30 | #define GRUB_AFS_BLOCKS_PER_DI_RUN 4 | |
31 | ||
32 | #define GRUB_AFS_SBLOCK_MAGIC1 0x41465331 /* AFS1 */ | |
33 | #define GRUB_AFS_SBLOCK_MAGIC2 0xdd121031 | |
34 | #define GRUB_AFS_SBLOCK_MAGIC3 0x15b6830e | |
35 | ||
36 | #define GRUB_AFS_INODE_MAGIC 0x64358428 | |
37 | ||
38 | #define GRUB_AFS_BTREE_MAGIC 0x65768995 | |
39 | ||
40 | #define GRUB_AFS_BNODE_SIZE 1024 | |
41 | ||
42 | #define GRUB_AFS_S_IFMT 00170000 | |
43 | #define GRUB_AFS_S_IFLNK 0120000 | |
44 | ||
45 | #define GRUB_AFS_S_IFREG 0100000 | |
46 | #define GRUB_AFS_S_IFDIR 0040000 | |
47 | #define GRUB_AFS_S_IFIFO 0010000 | |
48 | ||
49 | #define GRUB_AFS_NULL_VAL ((grub_afs_bvalue_t)-1) | |
50 | ||
51 | #define U16(sb, u) (((sb)->byte_order == GRUB_AFS_BO_LITTLE_ENDIAN) ? \ | |
52 | grub_le_to_cpu16 (u) : grub_be_to_cpu16 (u)) | |
53 | ||
54 | #define U32(sb, u) (((sb)->byte_order == GRUB_AFS_BO_LITTLE_ENDIAN) ? \ | |
55 | grub_le_to_cpu32 (u) : grub_be_to_cpu32 (u)) | |
56 | ||
57 | #define U64(sb, u) (((sb)->byte_order == GRUB_AFS_BO_LITTLE_ENDIAN) ? \ | |
58 | grub_le_to_cpu64 (u) : grub_be_to_cpu64 (u)) | |
59 | ||
60 | #define B_KEY_INDEX_OFFSET(node) ((grub_uint16_t *) \ | |
61 | ((char *) (node) + \ | |
62 | sizeof (struct grub_afs_bnode) + \ | |
63 | ((node->key_size + 3) & ~3))) | |
64 | ||
65 | #define B_KEY_VALUE_OFFSET(node) ((grub_afs_bvalue_t *) \ | |
66 | ((char *) B_KEY_INDEX_OFFSET (node) + \ | |
67 | node->key_count * 2)) | |
68 | ||
69 | enum | |
70 | { | |
71 | GRUB_AFS_BO_LITTLE_ENDIAN, | |
72 | GRUB_AFS_BO_BIG_ENDIAN | |
73 | }; | |
74 | ||
75 | typedef grub_uint64_t grub_afs_off_t; | |
76 | typedef grub_uint64_t grub_afs_bigtime; | |
77 | typedef grub_uint64_t grub_afs_bvalue_t; | |
78 | ||
79 | struct grub_afs_blockrun | |
80 | { | |
81 | grub_uint32_t group; | |
82 | grub_uint16_t start; | |
83 | grub_uint16_t len; | |
84 | }; | |
85 | ||
86 | struct grub_afs_datastream | |
87 | { | |
88 | struct grub_afs_blockrun direct[GRUB_AFS_DIRECT_BLOCK_COUNT]; | |
89 | grub_afs_off_t max_direct_range; | |
90 | struct grub_afs_blockrun indirect; | |
91 | grub_afs_off_t max_indirect_range; | |
92 | struct grub_afs_blockrun double_indirect; | |
93 | grub_afs_off_t max_double_indirect_range; | |
94 | grub_afs_off_t size; | |
95 | }; | |
96 | ||
97 | struct grub_afs_bnode | |
98 | { | |
99 | grub_afs_bvalue_t left; | |
100 | grub_afs_bvalue_t right; | |
101 | grub_afs_bvalue_t overflow; | |
102 | grub_uint32_t key_count; | |
103 | grub_uint32_t key_size; | |
104 | char key_data[0]; | |
105 | }; | |
106 | ||
107 | struct grub_afs_btree | |
108 | { | |
109 | grub_uint32_t magic; | |
110 | grub_afs_bvalue_t root; | |
111 | grub_uint32_t tree_depth; | |
112 | grub_afs_bvalue_t last_node; | |
113 | grub_afs_bvalue_t first_free; | |
114 | } ; | |
115 | ||
116 | struct grub_afs_sblock | |
117 | { | |
118 | grub_uint8_t name[32]; | |
119 | grub_uint32_t magic1; | |
120 | grub_uint32_t byte_order; | |
121 | grub_uint32_t block_size; | |
122 | grub_uint32_t block_shift; | |
123 | grub_afs_off_t num_blocks; | |
124 | grub_afs_off_t used_blocks; | |
125 | grub_uint32_t inode_size; | |
126 | grub_uint32_t magic2; | |
127 | grub_uint32_t block_per_group; // Number of blocks per allocation group (Max 65536) | |
128 | grub_uint32_t alloc_group_shift; // Number of bits to shift a group number to get a byte address. | |
129 | grub_uint32_t alloc_group_count; | |
130 | grub_uint32_t flags; | |
131 | struct grub_afs_blockrun log_block; | |
132 | grub_afs_off_t log_start; | |
133 | grub_uint32_t valid_log_blocks; | |
134 | grub_uint32_t log_size; | |
135 | grub_uint32_t magic3; | |
136 | struct grub_afs_blockrun root_dir; // Root dir inode. | |
137 | struct grub_afs_blockrun deleted_files; // Directory containing files scheduled for deletion. | |
138 | struct grub_afs_blockrun index_dir; // Directory of index files. | |
139 | grub_uint32_t boot_loader_size; | |
140 | grub_uint32_t pad[7]; | |
141 | }; | |
142 | ||
143 | struct grub_afs_inode | |
144 | { | |
145 | grub_uint32_t magic1; | |
146 | struct grub_afs_blockrun inode_num; | |
147 | grub_uint32_t uid; | |
148 | grub_uint32_t gid; | |
149 | grub_uint32_t mode; | |
150 | grub_uint32_t flags; | |
151 | grub_uint32_t link_count; | |
152 | grub_afs_bigtime create_time; | |
153 | grub_afs_bigtime modified_time; | |
154 | struct grub_afs_blockrun parent; | |
155 | struct grub_afs_blockrun attrib_dir; | |
156 | grub_uint32_t index_type; /* Key data-key only used for index files */ | |
157 | grub_uint32_t inode_size; | |
158 | void* vnode; | |
159 | struct grub_afs_datastream stream; | |
160 | grub_uint32_t pad[4]; | |
161 | grub_uint32_t small_data[1]; | |
162 | }; | |
163 | ||
164 | struct grub_fshelp_node | |
165 | { | |
166 | struct grub_afs_data *data; | |
167 | struct grub_afs_inode inode; | |
168 | }; | |
169 | ||
170 | struct grub_afs_data | |
171 | { | |
172 | grub_disk_t disk; | |
173 | struct grub_afs_sblock sblock; | |
174 | struct grub_afs_inode *inode; | |
175 | struct grub_fshelp_node diropen; | |
176 | }; | |
177 | ||
178 | #ifndef GRUB_UTIL | |
179 | static grub_dl_t my_mod; | |
180 | #endif | |
181 | ||
182 | static grub_afs_off_t | |
183 | grub_afs_run_to_num (struct grub_afs_sblock *sb, | |
184 | struct grub_afs_blockrun *run) | |
185 | { | |
186 | return ((grub_afs_off_t) U32 (sb, run->group) * sb->block_per_group + | |
187 | U16 (sb, run->start)); | |
188 | } | |
189 | ||
190 | static grub_err_t | |
191 | grub_afs_read_inode (struct grub_afs_data *data, | |
192 | grub_uint32_t ino, struct grub_afs_inode *inode) | |
193 | { | |
194 | return grub_disk_read (data->disk, | |
195 | ino * | |
196 | (data->sblock.block_size >> GRUB_DISK_SECTOR_BITS), | |
197 | 0, sizeof (struct grub_afs_inode), | |
198 | (char *) inode); | |
199 | } | |
200 | ||
29d7e38a | 201 | static grub_disk_addr_t |
887d2619 | 202 | grub_afs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) |
86cb4f54 | 203 | { |
204 | struct grub_afs_sblock *sb = &node->data->sblock; | |
205 | struct grub_afs_datastream *ds = &node->inode.stream; | |
206 | ||
887d2619 | 207 | if (fileblock < U64 (sb, ds->max_direct_range)) |
86cb4f54 | 208 | { |
209 | int i; | |
210 | ||
211 | for (i = 0; i < GRUB_AFS_DIRECT_BLOCK_COUNT; i++) | |
212 | { | |
213 | if (fileblock < U16 (sb, ds->direct[i].len)) | |
214 | return grub_afs_run_to_num (sb, &ds->direct[i]) + fileblock; | |
215 | fileblock -= U16 (sb, ds->direct[i].len); | |
216 | } | |
217 | } | |
887d2619 | 218 | else if (fileblock < U64 (sb, ds->max_indirect_range)) |
86cb4f54 | 219 | { |
220 | int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun); | |
221 | struct grub_afs_blockrun indir[ptrs_per_blk]; | |
222 | grub_afs_off_t blk = grub_afs_run_to_num (sb, &ds->indirect); | |
223 | int i; | |
224 | ||
225 | fileblock -= U64 (sb, ds->max_direct_range); | |
226 | for (i = 0; i < ds->indirect.len; i++, blk++) | |
227 | { | |
228 | int j; | |
229 | ||
230 | if (grub_disk_read (node->data->disk, | |
231 | blk * (sb->block_size >> GRUB_DISK_SECTOR_BITS), | |
232 | 0, sizeof (indir), | |
233 | (char *) indir)) | |
234 | return 0; | |
235 | ||
236 | for (j = 0; j < ptrs_per_blk; j++) | |
237 | { | |
238 | if (fileblock < U16 (sb, indir[j].len)) | |
239 | return grub_afs_run_to_num (sb, &indir[j]) + fileblock; | |
240 | ||
241 | fileblock -= U16 (sb, indir[j].len); | |
242 | } | |
243 | } | |
244 | } | |
245 | else | |
246 | { | |
247 | int ptrs_per_blk = sb->block_size / sizeof (struct grub_afs_blockrun); | |
248 | struct grub_afs_blockrun indir[ptrs_per_blk]; | |
249 | ||
250 | /* ([idblk][idptr]) ([dblk][dptr]) [blk] */ | |
251 | int cur_pos = fileblock - U64 (sb, ds->max_indirect_range); | |
252 | ||
253 | int dptr_size = GRUB_AFS_BLOCKS_PER_DI_RUN; | |
254 | int dblk_size = dptr_size * ptrs_per_blk; | |
255 | int idptr_size = dblk_size * GRUB_AFS_BLOCKS_PER_DI_RUN; | |
256 | int idblk_size = idptr_size * ptrs_per_blk; | |
257 | ||
258 | int off = cur_pos % GRUB_AFS_BLOCKS_PER_DI_RUN; | |
259 | int dptr = (cur_pos / dptr_size) % ptrs_per_blk; | |
260 | int dblk = (cur_pos / dblk_size) % GRUB_AFS_BLOCKS_PER_DI_RUN; | |
261 | int idptr = (cur_pos / idptr_size) % ptrs_per_blk; | |
262 | int idblk = (cur_pos / idblk_size); | |
263 | ||
264 | if (grub_disk_read (node->data->disk, | |
265 | (grub_afs_run_to_num (sb, &ds->double_indirect) | |
266 | + idblk) * | |
267 | (sb->block_size >> GRUB_DISK_SECTOR_BITS), | |
268 | 0, sizeof (indir), | |
269 | (char *) indir)) | |
270 | return 0; | |
271 | ||
272 | if (grub_disk_read (node->data->disk, | |
273 | (grub_afs_run_to_num (sb, &indir[idptr]) + dblk) * | |
274 | (sb->block_size >> GRUB_DISK_SECTOR_BITS), | |
275 | 0, sizeof (indir), | |
276 | (char *) indir)) | |
277 | return 0; | |
278 | ||
279 | return grub_afs_run_to_num (sb, &indir[dptr]) + off; | |
280 | } | |
281 | ||
282 | return 0; | |
283 | } | |
284 | ||
285 | static grub_ssize_t | |
286 | grub_afs_read_file (grub_fshelp_node_t node, | |
287 | void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector, | |
288 | unsigned offset, unsigned length), | |
289 | int pos, grub_size_t len, char *buf) | |
290 | { | |
291 | return grub_fshelp_read_file (node->data->disk, node, read_hook, | |
292 | pos, len, buf, grub_afs_read_block, | |
293 | U64 (&node->data->sblock, | |
294 | node->inode.stream.size), | |
295 | node->data->sblock.block_shift | |
296 | - GRUB_DISK_SECTOR_BITS); | |
297 | } | |
298 | ||
299 | static int | |
300 | grub_afs_iterate_dir (grub_fshelp_node_t dir, | |
301 | int NESTED_FUNC_ATTR | |
302 | (*hook) (const char *filename, | |
303 | enum grub_fshelp_filetype filetype, | |
304 | grub_fshelp_node_t node)) | |
305 | { | |
306 | struct grub_afs_btree head; | |
307 | char node_data [GRUB_AFS_BNODE_SIZE]; | |
308 | struct grub_afs_bnode *node = (struct grub_afs_bnode *) node_data; | |
309 | struct grub_afs_sblock *sb = &dir->data->sblock; | |
310 | int i; | |
311 | ||
312 | if ((! dir->inode.stream.size) || | |
313 | ((U32 (sb, dir->inode.mode) & GRUB_AFS_S_IFMT) != GRUB_AFS_S_IFDIR)) | |
314 | return 0; | |
315 | ||
316 | grub_afs_read_file (dir, 0, 0, sizeof (head), (char *) &head); | |
317 | if (grub_errno) | |
318 | return 0; | |
319 | ||
320 | grub_afs_read_file (dir, 0, U64 (sb, head.root), | |
321 | GRUB_AFS_BNODE_SIZE, (char *) node); | |
322 | if (grub_errno) | |
323 | return 0; | |
324 | ||
325 | for (i = 0; i < (int) U32 (sb, head.tree_depth) - 1; i++) | |
326 | { | |
327 | grub_afs_bvalue_t blk; | |
328 | ||
329 | blk = U64(sb, B_KEY_VALUE_OFFSET (node) [0]); | |
330 | grub_afs_read_file (dir, 0, blk, GRUB_AFS_BNODE_SIZE, (char *) node); | |
331 | if (grub_errno) | |
332 | return 0; | |
333 | } | |
334 | ||
335 | if (node->key_count) | |
336 | { | |
337 | grub_uint32_t cur_key = 0; | |
338 | ||
339 | while (1) | |
340 | { | |
341 | int key_start, key_size; | |
342 | grub_uint16_t *index; | |
343 | ||
344 | index = B_KEY_INDEX_OFFSET (node); | |
345 | ||
346 | key_start = U16 (sb, (cur_key > 0) ? index[cur_key - 1] : 0); | |
347 | key_size = U16 (sb, index[cur_key]) - key_start; | |
348 | if (key_size) | |
349 | { | |
350 | char filename [key_size + 1]; | |
351 | struct grub_fshelp_node *fdiro; | |
352 | int mode, type; | |
353 | ||
354 | fdiro = grub_malloc (sizeof (struct grub_fshelp_node)); | |
355 | if (! fdiro) | |
356 | return 0; | |
357 | ||
358 | fdiro->data = dir->data; | |
359 | if (grub_afs_read_inode (dir->data, | |
360 | U64 (sb, B_KEY_VALUE_OFFSET (node) [cur_key]), | |
361 | &fdiro->inode)) | |
362 | return 0; | |
363 | ||
364 | grub_memcpy (filename, &node->key_data[key_start], key_size); | |
365 | filename [key_size] = 0; | |
366 | ||
367 | mode = (U32 (sb, fdiro->inode.mode) & GRUB_AFS_S_IFMT); | |
368 | if (mode == GRUB_AFS_S_IFDIR) | |
369 | type = GRUB_FSHELP_DIR; | |
370 | else if (mode == GRUB_AFS_S_IFREG) | |
371 | type = GRUB_FSHELP_REG; | |
372 | else | |
373 | type = GRUB_FSHELP_UNKNOWN; | |
374 | ||
375 | if (hook (filename, type, fdiro)) | |
376 | return 1; | |
377 | } | |
378 | ||
379 | cur_key++; | |
380 | if (cur_key >= U32 (sb, node->key_count)) | |
381 | { | |
382 | if (node->right == GRUB_AFS_NULL_VAL) | |
383 | break; | |
384 | ||
385 | grub_afs_read_file (dir, 0, U64 (sb, node->right), | |
386 | GRUB_AFS_BNODE_SIZE, (char *) node); | |
387 | if (grub_errno) | |
388 | return 0; | |
389 | ||
390 | cur_key = 0; | |
391 | } | |
392 | } | |
393 | } | |
394 | ||
395 | return 0; | |
396 | } | |
397 | ||
398 | static int | |
399 | grub_afs_validate_sblock (struct grub_afs_sblock *sb) | |
400 | { | |
401 | if (grub_le_to_cpu32 (sb->magic1) == GRUB_AFS_SBLOCK_MAGIC1) | |
402 | { | |
403 | if (grub_le_to_cpu32 (sb->byte_order) != GRUB_AFS_BO_LITTLE_ENDIAN) | |
404 | return 0; | |
405 | ||
406 | sb->byte_order = GRUB_AFS_BO_LITTLE_ENDIAN; | |
407 | sb->magic2 = grub_le_to_cpu32 (sb->magic2); | |
408 | sb->magic3 = grub_le_to_cpu32 (sb->magic3); | |
409 | sb->block_shift = grub_le_to_cpu32 (sb->block_shift); | |
410 | sb->block_size = grub_le_to_cpu32 (sb->block_size); | |
411 | sb->used_blocks = grub_le_to_cpu64 (sb->used_blocks); | |
412 | sb->num_blocks = grub_le_to_cpu64 (sb->num_blocks); | |
413 | sb->inode_size = grub_le_to_cpu32 (sb->inode_size); | |
414 | sb->alloc_group_count = grub_le_to_cpu32 (sb->alloc_group_count); | |
415 | sb->alloc_group_shift = grub_le_to_cpu32 (sb->alloc_group_shift); | |
416 | sb->block_per_group = grub_le_to_cpu32 (sb->block_per_group); | |
417 | sb->alloc_group_count = grub_le_to_cpu32 (sb->alloc_group_count); | |
418 | sb->log_size = grub_le_to_cpu32 (sb->log_size); | |
419 | } | |
420 | else if (grub_be_to_cpu32 (sb->magic1) == GRUB_AFS_SBLOCK_MAGIC1) | |
421 | { | |
422 | if (grub_be_to_cpu32 (sb->byte_order) != GRUB_AFS_BO_BIG_ENDIAN) | |
423 | return 0; | |
424 | ||
425 | sb->byte_order = GRUB_AFS_BO_BIG_ENDIAN; | |
426 | sb->magic2 = grub_be_to_cpu32 (sb->magic2); | |
427 | sb->magic3 = grub_be_to_cpu32 (sb->magic3); | |
428 | sb->block_shift = grub_be_to_cpu32 (sb->block_shift); | |
429 | sb->block_size = grub_be_to_cpu32 (sb->block_size); | |
430 | sb->used_blocks = grub_be_to_cpu64 (sb->used_blocks); | |
431 | sb->num_blocks = grub_be_to_cpu64 (sb->num_blocks); | |
432 | sb->inode_size = grub_be_to_cpu32 (sb->inode_size); | |
433 | sb->alloc_group_count = grub_be_to_cpu32 (sb->alloc_group_count); | |
434 | sb->alloc_group_shift = grub_be_to_cpu32 (sb->alloc_group_shift); | |
435 | sb->block_per_group = grub_be_to_cpu32 (sb->block_per_group); | |
436 | sb->alloc_group_count = grub_be_to_cpu32 (sb->alloc_group_count); | |
437 | sb->log_size = grub_be_to_cpu32 (sb->log_size); | |
438 | } | |
439 | else | |
440 | return 0; | |
441 | ||
442 | if ((sb->magic2 != GRUB_AFS_SBLOCK_MAGIC2) || | |
443 | (sb->magic3 != GRUB_AFS_SBLOCK_MAGIC3)) | |
444 | return 0; | |
445 | ||
446 | if (((grub_uint32_t) (1 << sb->block_shift) != sb->block_size) || | |
447 | (sb->used_blocks > sb->num_blocks ) || | |
448 | (sb->inode_size != sb->block_size) || | |
449 | (0 == sb->block_size) || | |
450 | ((grub_uint32_t) (1 << sb->alloc_group_shift) != | |
451 | sb->block_per_group * sb->block_size) || | |
452 | (sb->alloc_group_count * sb->block_per_group < sb->num_blocks) || | |
453 | (U16 (sb, sb->log_block.len) != sb->log_size) || | |
454 | (U32 (sb, sb->valid_log_blocks) > sb->log_size)) | |
455 | return 0; | |
456 | ||
457 | return 1; | |
458 | } | |
459 | ||
460 | static struct grub_afs_data * | |
461 | grub_afs_mount (grub_disk_t disk) | |
462 | { | |
463 | struct grub_afs_data *data = 0; | |
464 | ||
465 | data = grub_malloc (sizeof (struct grub_afs_data)); | |
466 | if (!data) | |
467 | return 0; | |
468 | ||
469 | /* Read the superblock. */ | |
470 | if (grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_afs_sblock), | |
471 | (char *) &data->sblock)) | |
472 | goto fail; | |
473 | ||
474 | if (! grub_afs_validate_sblock (&data->sblock)) | |
475 | { | |
476 | if (grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_afs_sblock), | |
477 | (char *) &data->sblock)) | |
478 | goto fail; | |
479 | ||
480 | if (! grub_afs_validate_sblock (&data->sblock)) | |
481 | goto fail; | |
482 | } | |
483 | ||
484 | data->diropen.data = data; | |
485 | data->inode = &data->diropen.inode; | |
486 | data->disk = disk; | |
487 | ||
488 | if (grub_afs_read_inode (data, | |
489 | grub_afs_run_to_num (&data->sblock, | |
490 | &data->sblock.root_dir), | |
491 | data->inode)) | |
492 | goto fail; | |
493 | ||
494 | return data; | |
495 | ||
496 | fail: | |
497 | grub_error (GRUB_ERR_BAD_FS, "not an afs filesystem"); | |
498 | grub_free (data); | |
499 | return 0; | |
500 | } | |
501 | ||
502 | static grub_err_t | |
503 | grub_afs_open (struct grub_file *file, const char *name) | |
504 | { | |
505 | struct grub_afs_data *data; | |
506 | struct grub_fshelp_node *fdiro = 0; | |
507 | ||
508 | #ifndef GRUB_UTIL | |
509 | grub_dl_ref (my_mod); | |
510 | #endif | |
511 | ||
512 | data = grub_afs_mount (file->device->disk); | |
513 | if (! data) | |
514 | goto fail; | |
515 | ||
516 | grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_afs_iterate_dir, | |
517 | 0, GRUB_FSHELP_REG); | |
518 | if (grub_errno) | |
519 | goto fail; | |
520 | ||
521 | grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_afs_inode)); | |
522 | grub_free (fdiro); | |
523 | ||
524 | file->size = U64 (&data->sblock, data->inode->stream.size); | |
525 | file->data = data; | |
526 | file->offset = 0; | |
527 | ||
528 | return 0; | |
529 | ||
530 | fail: | |
531 | if (fdiro != &data->diropen) | |
532 | grub_free (fdiro); | |
533 | grub_free (data); | |
534 | ||
535 | #ifndef GRUB_UTIL | |
536 | grub_dl_unref (my_mod); | |
537 | #endif | |
538 | ||
539 | return grub_errno; | |
540 | } | |
541 | ||
542 | static grub_ssize_t | |
543 | grub_afs_read (grub_file_t file, char *buf, grub_size_t len) | |
544 | { | |
545 | struct grub_afs_data *data = (struct grub_afs_data *) file->data; | |
546 | ||
547 | return grub_afs_read_file (&data->diropen, file->read_hook, | |
548 | file->offset, len, buf); | |
549 | } | |
550 | ||
551 | static grub_err_t | |
552 | grub_afs_close (grub_file_t file) | |
553 | { | |
554 | grub_free (file->data); | |
555 | ||
556 | #ifndef GRUB_UTIL | |
557 | grub_dl_unref (my_mod); | |
558 | #endif | |
559 | ||
560 | return GRUB_ERR_NONE; | |
561 | } | |
562 | ||
563 | static grub_err_t | |
564 | grub_afs_dir (grub_device_t device, const char *path, | |
05aaebfb | 565 | int (*hook) (const char *filename, |
566 | const struct grub_dirhook_info *info)) | |
86cb4f54 | 567 | { |
568 | struct grub_afs_data *data = 0;; | |
569 | struct grub_fshelp_node *fdiro = 0; | |
570 | ||
571 | auto int NESTED_FUNC_ATTR iterate (const char *filename, | |
572 | enum grub_fshelp_filetype filetype, | |
573 | grub_fshelp_node_t node); | |
574 | ||
575 | int NESTED_FUNC_ATTR iterate (const char *filename, | |
576 | enum grub_fshelp_filetype filetype, | |
577 | grub_fshelp_node_t node) | |
578 | { | |
05aaebfb | 579 | struct grub_dirhook_info info; |
580 | grub_memset (&info, 0, sizeof (info)); | |
581 | info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); | |
86cb4f54 | 582 | grub_free (node); |
05aaebfb | 583 | return hook (filename, &info); |
86cb4f54 | 584 | } |
585 | ||
586 | #ifndef GRUB_UTIL | |
587 | grub_dl_ref (my_mod); | |
588 | #endif | |
589 | ||
590 | data = grub_afs_mount (device->disk); | |
591 | if (! data) | |
592 | goto fail; | |
593 | ||
594 | grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_afs_iterate_dir, | |
595 | 0, GRUB_FSHELP_DIR); | |
596 | if (grub_errno) | |
597 | goto fail; | |
598 | ||
599 | grub_afs_iterate_dir (fdiro, iterate); | |
600 | ||
601 | fail: | |
602 | if (fdiro != &data->diropen) | |
603 | grub_free (fdiro); | |
604 | grub_free (data); | |
605 | ||
606 | #ifndef GRUB_UTIL | |
607 | grub_dl_unref (my_mod); | |
608 | #endif | |
609 | ||
610 | return grub_errno; | |
611 | } | |
612 | ||
613 | static struct grub_fs grub_afs_fs = { | |
614 | .name = "afs", | |
615 | .dir = grub_afs_dir, | |
616 | .open = grub_afs_open, | |
617 | .read = grub_afs_read, | |
618 | .close = grub_afs_close, | |
619 | .label = 0, | |
620 | .next = 0 | |
621 | }; | |
622 | ||
623 | GRUB_MOD_INIT (afs) | |
624 | { | |
625 | grub_fs_register (&grub_afs_fs); | |
626 | #ifndef GRUB_UTIL | |
627 | my_mod = mod; | |
628 | #endif | |
629 | } | |
630 | ||
631 | GRUB_MOD_FINI (afs) | |
632 | { | |
633 | grub_fs_unregister (&grub_afs_fs); | |
634 | } |