1 /* $NetBSD: libhfs.h,v 1.3 2007/03/22 13:21:28 dillo Exp $ */
4 * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Yevgeny Binder, Dieter Baron, and Pelle Johansson.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #ifndef _FS_HFS_LIBHFS_H_
33 #define _FS_HFS_LIBHFS_H_
35 #include <sys/endian.h>
36 #include <sys/param.h>
37 #include <sys/mount.h> /* needs to go after sys/param.h or compile fails */
38 #include <sys/types.h>
40 #include <sys/kernel.h>
41 #include <sys/systm.h>
42 #include <machine/stdarg.h>
43 #include <sys/fcntl.h>
44 #endif /* defined(_KERNEL) */
46 #if !defined(_KERNEL) && !defined(STANDALONE)
54 #endif /* !defined(_KERNEL) && !defined(STANDALONE) */
57 #define va_list _BSD_VA_LIST_
60 #define max(A,B) ((A) > (B) ? (A):(B))
61 #define min(A,B) ((A) < (B) ? (A):(B))
64 /* Macros to handle errors in this library. Not recommended outside libhfs.c */
66 #define HFS_LIBERR(format, ...) \
67 do{ hfslib_error(format, __FILE__, __LINE__); \
68 goto error; } while(/*CONSTCOND*/ 0)
70 #define HFS_LIBERR(format, ...) \
71 do{ hfslib_error(format, __FILE__, __LINE__, ##__VA_ARGS__); \
72 goto error; } while(/*CONSTCOND*/ 0)
76 #pragma mark Constants (on-disk)
82 HFS_SIG_HFSP
= 0x482B, /* 'H+' */
83 HFS_SIG_HFSX
= 0x4858, /* 'HX' */
84 HFS_SIG_HFS
= 0x4244 /* 'BD' */
85 }; /* volume signatures */
89 /* bits 0-6 are reserved */
91 HFS_VOL_UNMOUNTED
= 8,
92 HFS_VOL_BADBLOCKS
= 9,
95 HFS_VOL_CNIDS_RECYCLED
= 12,
96 HFS_VOL_JOURNALED
= 13,
97 /* bit 14 is reserved */
99 /* bits 16-31 are reserved */
100 } hfs_volume_attribute_bit
; /* volume header attribute bits */
108 } hfs_node_kind
; /* btree node kinds */
112 HFS_BAD_CLOSE_MASK
= 0x00000001,
113 HFS_BIG_KEYS_MASK
= 0x00000002,
114 HFS_VAR_INDEX_KEYS_MASK
= 0x00000004
115 }; /* btree header attribute masks */
119 HFS_CNID_ROOT_PARENT
= 1,
120 HFS_CNID_ROOT_FOLDER
= 2,
121 HFS_CNID_EXTENTS
= 3,
122 HFS_CNID_CATALOG
= 4,
123 HFS_CNID_BADBLOCKS
= 5,
124 HFS_CNID_ALLOCATION
= 6,
125 HFS_CNID_STARTUP
= 7,
126 HFS_CNID_ATTRIBUTES
= 8,
127 /* CNIDs 9-13 are reserved */
128 HFS_CNID_REPAIR
= 14,
131 } hfs_special_cnid
; /* special CNID values */
135 HFS_REC_FLDR
= 0x0001,
136 HFS_REC_FILE
= 0x0002,
137 HFS_REC_FLDR_THREAD
= 0x0003,
138 HFS_REC_FILE_THREAD
= 0x0004
139 } hfs_catalog_rec_kind
; /* catalog record types */
143 HFS_JOURNAL_ON_DISK_MASK
= 0x00000001, /* journal on same volume */
144 HFS_JOURNAL_ON_OTHER_MASK
= 0x00000002, /* journal elsewhere */
145 HFS_JOURNAL_NEEDS_INIT_MASK
= 0x00000004
146 }; /* journal flag masks */
150 HFS_JOURNAL_HEADER_MAGIC
= 0x4a4e4c78,
151 HFS_JOURNAL_ENDIAN_MAGIC
= 0x12345678
152 }; /* journal magic numbers */
158 }; /* common fork types */
162 HFS_KEY_CASEFOLD
= 0xCF,
163 HFS_KEY_BINARY
= 0XBC
164 }; /* catalog key comparison method types */
168 HFS_MIN_CAT_KEY_LEN
= 6,
169 HFS_MAX_CAT_KEY_LEN
= 516,
170 HFS_MAX_EXT_KEY_LEN
= 10
174 HFS_HARD_LINK_FILE_TYPE
= 0x686C6E6B, /* 'hlnk' */
175 HFS_HFSLUS_CREATOR
= 0x6866732B /* 'hfs+' */
181 #pragma mark Constants (custom)
185 /* number of bytes between start of volume and volume header */
186 #define HFS_VOLUME_HEAD_RESERVE_SIZE 1024
190 HFS_CATALOG_FILE
= 1,
191 HFS_EXTENTS_FILE
= 2,
192 HFS_ATTRIBUTES_FILE
= 3
193 } hfs_btree_file_type
; /* btree file kinds */
198 #pragma mark On-Disk Types (Mac OS specific)
201 typedef uint32_t hfs_macos_type_code
; /* four 1-byte char field */
212 int16_t l
; /* left */
213 int16_t b
; /* bottom */
214 int16_t r
; /* right */
219 hfs_macos_type_code file_type
;
220 hfs_macos_type_code file_creator
;
221 uint16_t finder_flags
;
222 hfs_macos_point_t location
;
224 } hfs_macos_file_info_t
;
229 uint16_t extended_finder_flags
;
231 int32_t put_away_folder_cnid
;
232 } hfs_macos_extended_file_info_t
;
236 hfs_macos_rect_t window_bounds
;
237 uint16_t finder_flags
;
238 hfs_macos_point_t location
;
240 } hfs_macos_folder_info_t
;
244 hfs_macos_point_t scroll_position
;
246 uint16_t extended_finder_flags
;
248 int32_t put_away_folder_cnid
;
249 } hfs_macos_extended_folder_info_t
;
254 #pragma mark On-Disk Types
257 typedef uint16_t unichar_t
;
259 typedef uint32_t hfs_cnid_t
;
265 unichar_t unicode
[255];
270 uint32_t start_block
;
271 uint32_t block_count
;
272 } hfs_extent_descriptor_t
;
274 typedef hfs_extent_descriptor_t hfs_extent_record_t
[8];
276 typedef struct hfs_fork_t
278 uint64_t logical_size
;
280 uint32_t total_blocks
;
281 hfs_extent_record_t extents
;
289 uint32_t last_mounting_version
;
290 uint32_t journal_info_block
;
292 uint32_t date_created
;
293 uint32_t date_modified
;
294 uint32_t date_backedup
;
295 uint32_t date_checked
;
298 uint32_t folder_count
;
301 uint32_t total_blocks
;
302 uint32_t free_blocks
;
304 uint32_t next_alloc_block
;
305 uint32_t rsrc_clump_size
;
306 uint32_t data_clump_size
;
307 hfs_cnid_t next_cnid
;
309 uint32_t write_count
;
312 uint32_t finder_info
[8];
314 hfs_fork_t allocation_file
;
315 hfs_fork_t extents_file
;
316 hfs_fork_t catalog_file
;
317 hfs_fork_t attributes_file
;
318 hfs_fork_t startup_file
;
319 } hfs_volume_header_t
;
329 } hfs_node_descriptor_t
;
339 uint16_t max_key_len
;
340 uint32_t total_nodes
;
343 uint32_t clump_size
; /* misaligned */
345 uint8_t keycomp_type
;
346 uint32_t attributes
; /* long aligned again */
347 uint32_t reserved2
[16];
348 } hfs_header_record_t
;
353 hfs_cnid_t parent_cnid
;
354 hfs_unistr255_t name
;
362 hfs_cnid_t file_cnid
;
363 uint32_t start_block
;
387 uint32_t date_created
;
388 uint32_t date_content_mod
;
389 uint32_t date_attrib_mod
;
390 uint32_t date_accessed
;
391 uint32_t date_backedup
;
393 hfs_macos_folder_info_t user_info
;
394 hfs_macos_extended_folder_info_t finder_info
;
395 uint32_t text_encoding
;
397 } hfs_folder_record_t
;
405 uint32_t date_created
;
406 uint32_t date_content_mod
;
407 uint32_t date_attrib_mod
;
408 uint32_t date_accessed
;
409 uint32_t date_backedup
;
411 hfs_macos_file_info_t user_info
;
412 hfs_macos_extended_file_info_t finder_info
;
413 uint32_t text_encoding
;
415 hfs_fork_t data_fork
;
416 hfs_fork_t rsrc_fork
;
423 hfs_cnid_t parent_cnid
;
424 hfs_unistr255_t name
;
425 } hfs_thread_record_t
;
430 uint32_t device_signature
[8];
433 uint64_t reserved
[32];
434 } hfs_journal_info_t
;
443 uint32_t blocklist_header_size
;
445 uint32_t journal_header_size
;
446 } hfs_journal_header_t
;
448 /* plain HFS structures needed for hfs wrapper support */
452 uint16_t start_block
;
453 uint16_t block_count
;
454 } hfs_hfs_extent_descriptor_t
;
456 typedef hfs_hfs_extent_descriptor_t hfs_hfs_extent_record_t
[3];
461 uint32_t date_created
;
462 uint32_t date_modified
;
464 uint16_t root_file_count
;
465 uint16_t volume_bitmap
;
466 uint16_t next_alloc_block
;
467 uint16_t total_blocks
;
470 uint16_t first_block
;
471 hfs_cnid_t next_cnid
;
472 uint16_t free_blocks
;
473 unsigned char volume_name
[28];
474 uint32_t date_backedup
;
475 uint16_t backup_seqnum
;
476 uint32_t write_count
;
477 uint32_t extents_clump_size
;
478 uint32_t catalog_clump_size
;
479 uint16_t root_folder_count
;
481 uint32_t folder_count
;
482 uint32_t finder_info
[8];
483 uint16_t embedded_signature
;
484 hfs_hfs_extent_descriptor_t embedded_extent
;
485 uint32_t extents_size
;
486 hfs_hfs_extent_record_t extents_extents
;
487 uint32_t catalog_size
;
488 hfs_hfs_extent_record_t catalog_extents
;
489 } hfs_hfs_master_directory_block_t
;
493 #pragma mark Custom Types
498 hfs_volume_header_t vh
; /* volume header */
499 hfs_header_record_t chr
; /* catalog file header node record*/
500 hfs_header_record_t ehr
; /* extent overflow file header node record*/
501 uint8_t catkeysizefieldsize
; /* size of catalog file key_len field in
502 * bytes (1 or 2); always 2 for HFS+ */
503 uint8_t extkeysizefieldsize
; /* size of extent file key_len field in
504 * bytes (1 or 2); always 2 for HFS+ */
505 hfs_unistr255_t name
; /* volume name */
507 /* pointer to catalog file key comparison function */
508 int (*keycmp
) (const void*, const void*);
510 int journaled
; /* 1 if volume is journaled, else 0 */
511 hfs_journal_info_t jib
; /* journal info block */
512 hfs_journal_header_t jh
; /* journal header */
514 uint64_t offset
; /* offset, in bytes, of HFS+ volume */
515 int readonly
; /* 0 if mounted r/w, 1 if mounted r/o */
516 void* cbdata
; /* application-specific data; allocated, defined and
517 * used (if desired) by the program, usually within
518 * callback routines */
524 int16_t type
; /* type of record: folder, file, or thread */
525 hfs_folder_record_t folder
;
526 hfs_file_record_t file
;
527 hfs_thread_record_t thread
;
529 /* for pointer nodes */
530 /* (using this large union for just one tiny field is not memory-efficient,
531 * so change this if it becomes problematic) */
532 uint32_t child
; /* node number of this node's child node */
533 } hfs_catalog_keyed_record_t
;
536 * These arguments are passed among libhfs without any inspection. This struct
537 * is accepted by all public functions of libhfs, and passed to each callback.
538 * An application dereferences each pointer to its own specific struct of
539 * arguments. Callbacks must be prepared to deal with NULL values for any of
540 * these fields (by providing default values to be used in lieu of that
541 * argument). However, a NULL pointer to this struct is an error.
543 * It was decided to make one unified argument structure, rather than many
544 * separate, operand-specific structures, because, when this structure is passed
545 * to a public function (e.g., hfslib_open_volume()), the function may make
546 * several calls (and subcalls) to various facilities, e.g., read(), malloc(),
547 * and free(), all of which require their own particular arguments. The
548 * facilities to be used are quite impractical to foreshadow, so the application
549 * takes care of all possible calls at once. This also reinforces the idea that
550 * a public call is an umbrella to a set of system calls, and all of these calls
551 * must be passed arguments which do not change within the context of this
552 * umbrella. (E.g., if a public function makes two calls to read(), one call
553 * should not be passed a uid of root and the other passed a uid of daemon.)
557 /* The 'error' function does not take an argument. All others do. */
569 /* error(in_format, in_file, in_line, in_args) */
570 void (*error
) (const char*, const char*, int, va_list);
572 /* allocmem(in_size, cbargs) */
573 void* (*allocmem
) (size_t, hfs_callback_args
*);
575 /* reallocmem(in_ptr, in_size, cbargs) */
576 void* (*reallocmem
) (void*, size_t, hfs_callback_args
*);
578 /* freemem(in_ptr, cbargs) */
579 void (*freemem
) (void*, hfs_callback_args
*);
581 /* openvol(in_volume, in_devicepath, cbargs)
582 * returns 0 on success */
583 int (*openvol
) (hfs_volume
*, const char*, hfs_callback_args
*);
585 /* closevol(in_volume, cbargs) */
586 void (*closevol
) (hfs_volume
*, hfs_callback_args
*);
588 /* read(in_volume, out_buffer, in_length, in_offset, cbargs)
589 * returns 0 on success */
590 int (*read
) (hfs_volume
*, void*, uint64_t, uint64_t,
595 hfs_callbacks hfs_gcb
; /* global callbacks */
598 * global case folding table
599 * (lazily initialized; see comments at bottom of hfs_open_volume())
605 #pragma mark Functions
608 void hfslib_init(hfs_callbacks
*);
609 void hfslib_done(void);
610 void hfslib_init_cbargs(hfs_callback_args
*);
612 int hfslib_open_volume(const char*, int, hfs_volume
*,
614 void hfslib_close_volume(hfs_volume
*, hfs_callback_args
*);
616 int hfslib_path_to_cnid(hfs_volume
*, hfs_cnid_t
, char**, uint16_t*,
618 hfs_cnid_t
hfslib_find_parent_thread(hfs_volume
*, hfs_cnid_t
,
619 hfs_thread_record_t
*, hfs_callback_args
*);
620 int hfslib_find_catalog_record_with_cnid(hfs_volume
*, hfs_cnid_t
,
621 hfs_catalog_keyed_record_t
*, hfs_catalog_key_t
*, hfs_callback_args
*);
622 int hfslib_find_catalog_record_with_key(hfs_volume
*, hfs_catalog_key_t
*,
623 hfs_catalog_keyed_record_t
*, hfs_callback_args
*);
624 int hfslib_find_extent_record_with_key(hfs_volume
*, hfs_extent_key_t
*,
625 hfs_extent_record_t
*, hfs_callback_args
*);
626 int hfslib_get_directory_contents(hfs_volume
*, hfs_cnid_t
,
627 hfs_catalog_keyed_record_t
**, hfs_unistr255_t
**, uint32_t*,
629 int hfslib_is_journal_clean(hfs_volume
*);
630 int hfslib_is_private_file(hfs_catalog_key_t
*);
632 int hfslib_get_hardlink(hfs_volume
*, uint32_t,
633 hfs_catalog_keyed_record_t
*, hfs_callback_args
*);
635 size_t hfslib_read_volume_header(void*, hfs_volume_header_t
*);
636 size_t hfslib_read_master_directory_block(void*,
637 hfs_hfs_master_directory_block_t
*);
638 size_t hfslib_reada_node(void*, hfs_node_descriptor_t
*, void***, uint16_t**,
639 hfs_btree_file_type
, hfs_volume
*, hfs_callback_args
*);
640 size_t hfslib_reada_node_offsets(void*, uint16_t*);
641 size_t hfslib_read_header_node(void**, uint16_t*, uint16_t,
642 hfs_header_record_t
*, void*, void*);
643 size_t hfslib_read_catalog_keyed_record(void*, hfs_catalog_keyed_record_t
*,
644 int16_t*, hfs_catalog_key_t
*, hfs_volume
*);
645 size_t hfslib_read_extent_record(void*, hfs_extent_record_t
*, hfs_node_kind
,
646 hfs_extent_key_t
*, hfs_volume
*);
647 void hfslib_free_recs(void***, uint16_t**, uint16_t*, hfs_callback_args
*);
649 size_t hfslib_read_fork_descriptor(void*, hfs_fork_t
*);
650 size_t hfslib_read_extent_descriptors(void*, hfs_extent_record_t
*);
651 size_t hfslib_read_unistr255(void*, hfs_unistr255_t
*);
652 size_t hfslib_read_bsd_data(void*, hfs_bsd_data_t
*);
653 size_t hfslib_read_file_userinfo(void*, hfs_macos_file_info_t
*);
654 size_t hfslib_read_file_finderinfo(void*, hfs_macos_extended_file_info_t
*);
655 size_t hfslib_read_folder_userinfo(void*, hfs_macos_folder_info_t
*);
656 size_t hfslib_read_folder_finderinfo(void*, hfs_macos_extended_folder_info_t
*);
657 size_t hfslib_read_journal_info(void*, hfs_journal_info_t
*);
658 size_t hfslib_read_journal_header(void*, hfs_journal_header_t
*);
660 uint16_t hfslib_make_catalog_key(hfs_cnid_t
, uint16_t, unichar_t
*,
662 uint16_t hfslib_make_extent_key(hfs_cnid_t
, uint8_t, uint32_t,
664 uint16_t hfslib_get_file_extents(hfs_volume
*, hfs_cnid_t
, uint8_t,
665 hfs_extent_descriptor_t
**, hfs_callback_args
*);
666 int hfslib_readd_with_extents(hfs_volume
*, void*, uint64_t*, uint64_t,
667 uint64_t, hfs_extent_descriptor_t
*, uint16_t, hfs_callback_args
*);
669 int hfslib_compare_catalog_keys_cf(const void*, const void*);
670 int hfslib_compare_catalog_keys_bc(const void*, const void*);
671 int hfslib_compare_extent_keys(const void*, const void*);
674 /* callback wrappers */
675 void hfslib_error(const char*, const char*, int, ...) __attribute__ ((format (printf
, 1, 4)));
676 void* hfslib_malloc(size_t, hfs_callback_args
*);
677 void* hfslib_realloc(void*, size_t, hfs_callback_args
*);
678 void hfslib_free(void*, hfs_callback_args
*);
679 int hfslib_openvoldevice(hfs_volume
*, const char*, hfs_callback_args
*);
680 void hfslib_closevoldevice(hfs_volume
*, hfs_callback_args
*);
681 int hfslib_readd(hfs_volume
*, void*, uint64_t, uint64_t, hfs_callback_args
*);
683 #endif /* !_FS_HFS_LIBHFS_H_ */