1 /* afs.c - The native AtheOS file-system. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
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.
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.
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/>.
21 #include <grub/file.h>
23 #include <grub/misc.h>
24 #include <grub/disk.h>
26 #include <grub/types.h>
27 #include <grub/fshelp.h>
29 #define GRUB_AFS_DIRECT_BLOCK_COUNT 12
30 #define GRUB_AFS_BLOCKS_PER_DI_RUN 4
32 #define GRUB_AFS_SBLOCK_MAGIC1 0x41465331 /* AFS1 */
33 #define GRUB_AFS_SBLOCK_MAGIC2 0xdd121031
34 #define GRUB_AFS_SBLOCK_MAGIC3 0x15b6830e
36 #define GRUB_AFS_INODE_MAGIC 0x64358428
38 #define GRUB_AFS_BTREE_MAGIC 0x65768995
40 #define GRUB_AFS_BNODE_SIZE 1024
42 #define GRUB_AFS_S_IFMT 00170000
43 #define GRUB_AFS_S_IFLNK 0120000
45 #define GRUB_AFS_S_IFREG 0100000
46 #define GRUB_AFS_S_IFDIR 0040000
47 #define GRUB_AFS_S_IFIFO 0010000
49 #define GRUB_AFS_NULL_VAL ((grub_afs_bvalue_t)-1)
51 #define U16(sb, u) (((sb)->byte_order == GRUB_AFS_BO_LITTLE_ENDIAN) ? \
52 grub_le_to_cpu16 (u) : grub_be_to_cpu16 (u))
54 #define U32(sb, u) (((sb)->byte_order == GRUB_AFS_BO_LITTLE_ENDIAN) ? \
55 grub_le_to_cpu32 (u) : grub_be_to_cpu32 (u))
57 #define U64(sb, u) (((sb)->byte_order == GRUB_AFS_BO_LITTLE_ENDIAN) ? \
58 grub_le_to_cpu64 (u) : grub_be_to_cpu64 (u))
60 #define B_KEY_INDEX_OFFSET(node) ((grub_uint16_t *) \
62 sizeof (struct grub_afs_bnode) + \
63 ((node->key_size + 3) & ~3)))
65 #define B_KEY_VALUE_OFFSET(node) ((grub_afs_bvalue_t *) \
66 ((char *) B_KEY_INDEX_OFFSET (node) + \
71 GRUB_AFS_BO_LITTLE_ENDIAN
,
72 GRUB_AFS_BO_BIG_ENDIAN
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
;
79 struct grub_afs_blockrun
86 struct grub_afs_datastream
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
;
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
;
107 struct grub_afs_btree
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
;
116 struct grub_afs_sblock
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
;
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];
143 struct grub_afs_inode
145 grub_uint32_t magic1
;
146 struct grub_afs_blockrun inode_num
;
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
;
159 struct grub_afs_datastream stream
;
160 grub_uint32_t pad
[4];
161 grub_uint32_t small_data
[1];
164 struct grub_fshelp_node
166 struct grub_afs_data
*data
;
167 struct grub_afs_inode inode
;
173 struct grub_afs_sblock sblock
;
174 struct grub_afs_inode
*inode
;
175 struct grub_fshelp_node diropen
;
179 static grub_dl_t my_mod
;
182 static grub_afs_off_t
183 grub_afs_run_to_num (struct grub_afs_sblock
*sb
,
184 struct grub_afs_blockrun
*run
)
186 return ((grub_afs_off_t
) U32 (sb
, run
->group
) * sb
->block_per_group
+
187 U16 (sb
, run
->start
));
191 grub_afs_read_inode (struct grub_afs_data
*data
,
192 grub_uint32_t ino
, struct grub_afs_inode
*inode
)
194 return grub_disk_read (data
->disk
,
196 (data
->sblock
.block_size
>> GRUB_DISK_SECTOR_BITS
),
197 0, sizeof (struct grub_afs_inode
),
201 static grub_disk_addr_t
202 grub_afs_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
204 struct grub_afs_sblock
*sb
= &node
->data
->sblock
;
205 struct grub_afs_datastream
*ds
= &node
->inode
.stream
;
207 if (fileblock
< U64 (sb
, ds
->max_direct_range
))
211 for (i
= 0; i
< GRUB_AFS_DIRECT_BLOCK_COUNT
; i
++)
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
);
218 else if (fileblock
< U64 (sb
, ds
->max_indirect_range
))
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
);
225 fileblock
-= U64 (sb
, ds
->max_direct_range
);
226 for (i
= 0; i
< ds
->indirect
.len
; i
++, blk
++)
230 if (grub_disk_read (node
->data
->disk
,
231 blk
* (sb
->block_size
>> GRUB_DISK_SECTOR_BITS
),
236 for (j
= 0; j
< ptrs_per_blk
; j
++)
238 if (fileblock
< U16 (sb
, indir
[j
].len
))
239 return grub_afs_run_to_num (sb
, &indir
[j
]) + fileblock
;
241 fileblock
-= U16 (sb
, indir
[j
].len
);
247 int ptrs_per_blk
= sb
->block_size
/ sizeof (struct grub_afs_blockrun
);
248 struct grub_afs_blockrun indir
[ptrs_per_blk
];
250 /* ([idblk][idptr]) ([dblk][dptr]) [blk] */
251 int cur_pos
= fileblock
- U64 (sb
, ds
->max_indirect_range
);
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
;
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
);
264 if (grub_disk_read (node
->data
->disk
,
265 (grub_afs_run_to_num (sb
, &ds
->double_indirect
)
267 (sb
->block_size
>> GRUB_DISK_SECTOR_BITS
),
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
),
279 return grub_afs_run_to_num (sb
, &indir
[dptr
]) + off
;
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
)
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
);
300 grub_afs_iterate_dir (grub_fshelp_node_t dir
,
302 (*hook
) (const char *filename
,
303 enum grub_fshelp_filetype filetype
,
304 grub_fshelp_node_t node
))
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
;
312 if ((! dir
->inode
.stream
.size
) ||
313 ((U32 (sb
, dir
->inode
.mode
) & GRUB_AFS_S_IFMT
) != GRUB_AFS_S_IFDIR
))
316 grub_afs_read_file (dir
, 0, 0, sizeof (head
), (char *) &head
);
320 grub_afs_read_file (dir
, 0, U64 (sb
, head
.root
),
321 GRUB_AFS_BNODE_SIZE
, (char *) node
);
325 for (i
= 0; i
< (int) U32 (sb
, head
.tree_depth
) - 1; i
++)
327 grub_afs_bvalue_t blk
;
329 blk
= U64(sb
, B_KEY_VALUE_OFFSET (node
) [0]);
330 grub_afs_read_file (dir
, 0, blk
, GRUB_AFS_BNODE_SIZE
, (char *) node
);
337 grub_uint32_t cur_key
= 0;
341 int key_start
, key_size
;
342 grub_uint16_t
*index
;
344 index
= B_KEY_INDEX_OFFSET (node
);
346 key_start
= U16 (sb
, (cur_key
> 0) ? index
[cur_key
- 1] : 0);
347 key_size
= U16 (sb
, index
[cur_key
]) - key_start
;
350 char filename
[key_size
+ 1];
351 struct grub_fshelp_node
*fdiro
;
354 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
358 fdiro
->data
= dir
->data
;
359 if (grub_afs_read_inode (dir
->data
,
360 U64 (sb
, B_KEY_VALUE_OFFSET (node
) [cur_key
]),
364 grub_memcpy (filename
, &node
->key_data
[key_start
], key_size
);
365 filename
[key_size
] = 0;
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
;
373 type
= GRUB_FSHELP_UNKNOWN
;
375 if (hook (filename
, type
, fdiro
))
380 if (cur_key
>= U32 (sb
, node
->key_count
))
382 if (node
->right
== GRUB_AFS_NULL_VAL
)
385 grub_afs_read_file (dir
, 0, U64 (sb
, node
->right
),
386 GRUB_AFS_BNODE_SIZE
, (char *) node
);
399 grub_afs_validate_sblock (struct grub_afs_sblock
*sb
)
401 if (grub_le_to_cpu32 (sb
->magic1
) == GRUB_AFS_SBLOCK_MAGIC1
)
403 if (grub_le_to_cpu32 (sb
->byte_order
) != GRUB_AFS_BO_LITTLE_ENDIAN
)
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
);
420 else if (grub_be_to_cpu32 (sb
->magic1
) == GRUB_AFS_SBLOCK_MAGIC1
)
422 if (grub_be_to_cpu32 (sb
->byte_order
) != GRUB_AFS_BO_BIG_ENDIAN
)
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
);
442 if ((sb
->magic2
!= GRUB_AFS_SBLOCK_MAGIC2
) ||
443 (sb
->magic3
!= GRUB_AFS_SBLOCK_MAGIC3
))
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
))
460 static struct grub_afs_data
*
461 grub_afs_mount (grub_disk_t disk
)
463 struct grub_afs_data
*data
= 0;
465 data
= grub_malloc (sizeof (struct grub_afs_data
));
469 /* Read the superblock. */
470 if (grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_afs_sblock
),
471 (char *) &data
->sblock
))
474 if (! grub_afs_validate_sblock (&data
->sblock
))
476 if (grub_disk_read (disk
, 1 * 2, 0, sizeof (struct grub_afs_sblock
),
477 (char *) &data
->sblock
))
480 if (! grub_afs_validate_sblock (&data
->sblock
))
484 data
->diropen
.data
= data
;
485 data
->inode
= &data
->diropen
.inode
;
488 if (grub_afs_read_inode (data
,
489 grub_afs_run_to_num (&data
->sblock
,
490 &data
->sblock
.root_dir
),
497 grub_error (GRUB_ERR_BAD_FS
, "not an afs filesystem");
503 grub_afs_open (struct grub_file
*file
, const char *name
)
505 struct grub_afs_data
*data
;
506 struct grub_fshelp_node
*fdiro
= 0;
509 grub_dl_ref (my_mod
);
512 data
= grub_afs_mount (file
->device
->disk
);
516 grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
, grub_afs_iterate_dir
,
521 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_afs_inode
));
524 file
->size
= U64 (&data
->sblock
, data
->inode
->stream
.size
);
531 if (fdiro
!= &data
->diropen
)
536 grub_dl_unref (my_mod
);
543 grub_afs_read (grub_file_t file
, char *buf
, grub_size_t len
)
545 struct grub_afs_data
*data
= (struct grub_afs_data
*) file
->data
;
547 return grub_afs_read_file (&data
->diropen
, file
->read_hook
,
548 file
->offset
, len
, buf
);
552 grub_afs_close (grub_file_t file
)
554 grub_free (file
->data
);
557 grub_dl_unref (my_mod
);
560 return GRUB_ERR_NONE
;
564 grub_afs_dir (grub_device_t device
, const char *path
,
565 int (*hook
) (const char *filename
, int dir
))
567 struct grub_afs_data
*data
= 0;;
568 struct grub_fshelp_node
*fdiro
= 0;
570 auto int NESTED_FUNC_ATTR
iterate (const char *filename
,
571 enum grub_fshelp_filetype filetype
,
572 grub_fshelp_node_t node
);
574 int NESTED_FUNC_ATTR
iterate (const char *filename
,
575 enum grub_fshelp_filetype filetype
,
576 grub_fshelp_node_t node
)
580 if (filetype
== GRUB_FSHELP_DIR
)
581 return hook (filename
, 1);
583 return hook (filename
, 0);
589 grub_dl_ref (my_mod
);
592 data
= grub_afs_mount (device
->disk
);
596 grub_fshelp_find_file (path
, &data
->diropen
, &fdiro
, grub_afs_iterate_dir
,
601 grub_afs_iterate_dir (fdiro
, iterate
);
604 if (fdiro
!= &data
->diropen
)
609 grub_dl_unref (my_mod
);
615 static struct grub_fs grub_afs_fs
= {
618 .open
= grub_afs_open
,
619 .read
= grub_afs_read
,
620 .close
= grub_afs_close
,
627 grub_fs_register (&grub_afs_fs
);
635 grub_fs_unregister (&grub_afs_fs
);