Files in fs/hfs and fs/hfsplus have same names, this causes problems during linkage.
Use prefix 'hfsp_' for the conflicting files.
Signed-off-by: Blue Swirl blauwirbel@gmail.com --- fs/hfsplus/btree.c | 372 ----------------------- fs/hfsplus/build.xml | 6 +- fs/hfsplus/hfsp_btree.c | 372 +++++++++++++++++++++++ fs/hfsplus/hfsp_record.c | 759 ++++++++++++++++++++++++++++++++++++++++++++++ fs/hfsplus/hfsp_volume.c | 314 +++++++++++++++++++ fs/hfsplus/record.c | 759 ---------------------------------------------- fs/hfsplus/volume.c | 314 ------------------- 7 files changed, 1448 insertions(+), 1448 deletions(-) delete mode 100644 fs/hfsplus/btree.c create mode 100644 fs/hfsplus/hfsp_btree.c create mode 100644 fs/hfsplus/hfsp_record.c create mode 100644 fs/hfsplus/hfsp_volume.c delete mode 100644 fs/hfsplus/record.c delete mode 100644 fs/hfsplus/volume.c
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c deleted file mode 100644 index 5409418..0000000 --- a/fs/hfsplus/btree.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * libhfs - library for reading and writing Macintosh HFS volumes - * The fucntions are used to handle the various forms of btrees - * found on HFS+ volumes. - * - * The fucntions are used to handle the various forms of btrees - * found on HFS+ volumes. - * - * Copyright (C) 2000 Klaus Halfmann khalfmann@libra.de - * Original 1996-1998 Robert Leslie rob@mars.org - * Additional work by Brad Boyer (flar@pants.nu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * $Id: btree.c,v 1.14 2000/10/25 05:43:04 hasi Exp $ - */ - -#include "config.h" -#include "libhfsp.h" -#include "volume.h" -#include "btree.h" -#include "record.h" -#include "swab.h" - -/* Read the node from the given buffer and swap the bytes. - * - * return pointer after reading the structure - */ -static void* btree_readnode(btree_node_desc* node, void *p) -{ - node->next = bswabU32_inc(p); - node->prev = bswabU32_inc(p); - node->kind = bswabU8_inc(p); - node->height = bswabU8_inc(p); - node->num_rec = bswabU16_inc(p); - node->reserved = bswabU16_inc(p); - return p; -} - -/* read a btree header from the given buffer and swap the bytes. - * - * return pointer after reading the structure - */ -static void* btree_readhead(btree_head* head, void *p) -{ - UInt32 *q; - head->depth = bswabU16_inc(p); - head->root = bswabU32_inc(p); - head->leaf_count = bswabU32_inc(p); - head->leaf_head = bswabU32_inc(p); - head->leaf_tail = bswabU32_inc(p); - head->node_size = bswabU16_inc(p); - head->max_key_len = bswabU16_inc(p); - head->node_count = bswabU32_inc(p); - head->free_nodes = bswabU32_inc(p); - head->reserved1 = bswabU16_inc(p); - head->clump_size = bswabU32_inc(p); - head->btree_type = bswabU8_inc(p); - head->reserved2 = bswabU8_inc(p); - head->attributes = bswabU32_inc(p); - // skip reserved bytes - q=((UInt32*) p); - // ((UInt32*) p) += 16; - q+=16; - return q; -} - -/* Priority of the depth of the node compared to LRU value. - * Should be the average number of keys per node but these vary. */ -#define DEPTH_FACTOR 1000 - -/* Cache size is height of tree + this value - * Really big numbers wont help in case of ls -R - */ -#define EXTRA_CACHESIZE 3 - -/* Not in use by now ... */ -#define CACHE_DIRTY 0x0001 - -/* Intialize cache with default cache Size, - * must call node_cache_close to deallocate memory */ -static int node_cache_init(node_cache* cache, btree* tree, int size) -{ - int nodebufsize; - char * buf; - - cache->size = size; - cache->currindex = 0; - nodebufsize = tree->head.node_size + sizeof(node_buf); - buf = malloc(size *(sizeof(node_entry) + nodebufsize)); - if (!buf) - return -1; - cache -> nodebufsize = nodebufsize; - cache -> entries = (node_entry*) buf; - cache -> buffers = (char*) &cache->entries[size]; - bzero(cache->entries, size*sizeof(node_entry)); - return 0; -} - -/* Like cache->buffers[i], since size of node_buf is variable */ -static inline node_buf* node_buf_get(node_cache* cache, int i) -{ - return (node_buf*) (cache->buffers + (i * cache->nodebufsize)); -} - -/* flush the node at index */ -static void node_cache_flush_node(node_cache* cache, int index) -{ - // NYI - cache -> entries[index].index = 0; // invalidate entry -} - -static void node_cache_close(node_cache* cache) -{ - if (!cache->entries) // not (fully) intialized ? - return; - free(cache->entries); -} - -/* Load the cach node indentified by index with - * the node identified by node_index */ - -static node_buf* node_cache_load_buf - (btree* bt, node_cache* cache, int index, UInt16 node_index) -{ - node_buf *result = node_buf_get(cache ,index); - UInt32 blkpernode = bt->blkpernode; - UInt32 block = node_index * blkpernode; - void* p = volume_readfromfork(bt->vol, result->node, bt->fork, - block, blkpernode, HFSP_EXTENT_DATA, bt->cnid); - node_entry *e = &cache->entries[index]; - - if (!p) - return NULL; // evil ... - - result->index = node_index; - btree_readnode(&result->desc, p); - - e -> priority = result->desc.height * DEPTH_FACTOR; - e -> index = node_index; - return result; -} - -/* Read node at given index, using cache. - */ -node_buf* btree_node_by_index(btree* bt, UInt16 index) -{ - node_cache* cache = &bt->cache; - int oldindex, lruindex; - int currindex = cache->currindex; - UInt32 prio; - node_entry *e; - - // Shortcut acces to current node, will not change priorities - if (cache->entries[currindex].index == index) - return node_buf_get(cache ,currindex); - oldindex = currindex; - if (currindex == 0) - currindex = cache->size; - currindex--; - lruindex = oldindex; // entry to be flushed when needed - prio = 0; // current priority - while (currindex != oldindex) // round robin - { - e = &cache->entries[currindex]; - if (e->index == index) // got it - { - if (e->priority != 0) // already top, uuh - e->priority--; - cache->currindex = currindex; - return node_buf_get(cache ,currindex); - } - else - { - if (!e->index) - { - lruindex = currindex; - break; // empty entry, load it - } - if (e->priority != UINT_MAX) // already least, uuh - e->priority++; - } - if (prio < e->priority) - { - lruindex = currindex; - prio = e->priority; - } - if (currindex == 0) - currindex = cache->size; - currindex--; - } - e = &cache->entries[lruindex]; - cache->currindex = lruindex; - if (e->flags & CACHE_DIRTY) - node_cache_flush_node( cache, lruindex); - return node_cache_load_buf (bt, cache, lruindex, index); -} - -/** intialize the btree with the first entry in the fork */ -static int btree_init(btree* bt, volume* vol, hfsp_fork_raw* fork) -{ - void *p; - char buf[vol->blksize]; - UInt16 node_size; - btree_node_desc node; - - bt->vol = vol; - bt->fork = fork; - p = volume_readfromfork(vol, buf, fork, 0, 1, - HFSP_EXTENT_DATA, bt->cnid); - if (!p) - return -1; - p = btree_readnode(&node, p); - if (node.kind != HFSP_NODE_HEAD) - return -1; // should not happen ? - btree_readhead(&bt->head, p); - - node_size = bt->head.node_size; - bt->blkpernode = node_size / vol->blksize; - - if (bt->blkpernode == 0 || vol->blksize * - bt->blkpernode != node_size) - return -1; // should never happen ... - - node_cache_init(&bt->cache, bt, bt->head.depth + EXTRA_CACHESIZE); - - // Allocate buffer - // bt->buf = malloc(node_size); - // if (!bt->buf) - // return ENOMEM; - - return 0; -} - -/** Intialize catalog btree, so that btree_close can safely be called. */ -void btree_reset(btree* bt) -{ - bt->cache.entries = NULL; -} - -/** Intialize catalog btree */ -int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork) -{ - int result = btree_init(bt,vol,fork); // super (...) - bt->cnid = HFSP_CAT_CNID; - bt->kcomp = record_key_compare; - bt->kread = record_readkey; - return result; -} - -/** Intialize catalog btree */ -int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork) -{ - int result = btree_init(bt,vol,fork); // super (...) - bt->cnid = HFSP_EXT_CNID; - bt->kcomp = record_extent_key_compare; - bt->kread = record_extent_readkey; - return result; -} - -/** close the btree and free any resources */ -void btree_close(btree* bt) -{ - node_cache_close(&bt->cache); - // free(bt->buf); -} - -/* returns pointer to key given by index in current node. - * - * Assumes that current node is not NODE_HEAD ... - */ -void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index) -{ - UInt16 node_size = bt->head.node_size; - // The offsets are found at the end of the node ... - UInt16 off_pos = node_size - (index +1) * sizeof(btree_record_offset); - // position of offset at end of node - btree_record_offset* offset = - (btree_record_offset*) (buf->node + off_pos); - - // now we have the offset and can read the key ... -#ifdef CONFIG_LITTLE_ENDIAN - return buf->node + bswabU16(*offset); -#else - return buf->node + *offset; -#endif -} - - -#ifdef DEBUG - -/* print btree header node information */ -void btree_printhead(btree_head* head) -{ - UInt32 attr; - printf(" depth : %#X\n", head->depth); - printf(" root : %#lX\n", head->root); - printf(" leaf_count : %#lX\n", head->leaf_count); - printf(" leaf_head : %#lX\n", head->leaf_head); - printf(" leaf_tail : %#lX\n", head->leaf_tail); - printf(" node_size : %#X\n", head->node_size); - printf(" max_key_len : %#X\n", head->max_key_len); - printf(" node_count : %#lX\n", head->node_count); - printf(" free_nodes : %#lX\n", head->free_nodes); - printf(" reserved1 : %#X\n", head->reserved1); - printf(" clump_size : %#lX\n", head->clump_size); - printf(" btree_type : %#X\n", head->btree_type); - attr = head->attributes; - printf(" reserved2 : %#X\n", head->reserved2); - if (attr & HFSPLUS_BAD_CLOSE) - printf(" HFSPLUS_BAD_CLOSE *** "); - else - printf(" !HFSPLUS_BAD_CLOSE"); - if (attr & HFSPLUS_TREE_BIGKEYS) - printf(" HFSPLUS_TREE_BIGKEYS "); - else - printf(" !HFSPLUS_TREE_BIGKEYS"); - if (attr & HFSPLUS_TREE_VAR_NDXKEY_SIZE) - printf(" HFSPLUS_TREE_VAR_NDXKEY_SIZE"); - else - printf(" !HFSPLUS_TREE_VAR_NDXKEY_SIZE"); - if (attr & HFSPLUS_TREE_UNUSED) - printf(" HFSPLUS_TREE_UNUSED ***\n"); - printf("\n"); -} - -/* Dump all the node information to stdout */ -void btree_print(btree* bt) -{ - btree_node_desc* node; - - btree_printhead(&bt->head); - - node = &bt->node; - printf("next : %#lX\n", node->next); - printf("prev : %#lX\n", node->prev); - printf("height : %#X\n", node->height); - printf("num_rec : %#X\n", node->num_rec); - printf("reserved : %#X\n", node->reserved); - printf("height : %#X\n", node->height); switch(node->kind) - { - case HFSP_NODE_NDX : - printf("HFSP_NODE_NDX\n"); - break; - case HFSP_NODE_HEAD : - printf("HFSP_NODE_HEAD\n"); - break; - case HFSP_NODE_MAP : - printf("HFSP_NODE_MAP\n"); - break; - case HFSP_NODE_LEAF : - printf("HFSP_NODE_LEAF\n"); - break; - default: - printf("*** Unknown Node type ***\n"); - } -} - -#endif diff --git a/fs/hfsplus/build.xml b/fs/hfsplus/build.xml index d3d32cb..f6f5369 100644 --- a/fs/hfsplus/build.xml +++ b/fs/hfsplus/build.xml @@ -1,11 +1,11 @@ <build> <library name="fs" type="static" target="target"> <object source="blockiter.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> - <object source="btree.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> + <object source="hfsp_btree.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> <object source="libhfsp.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> - <object source="record.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> + <object source="hfsp_record.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> <object source="unicode.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> - <object source="volume.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> + <object source="hfsp_volume.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> <object source="hfsp_fs.c" flags="-I$(SRCDIR)/fs/hfsplus/include -I$(SRCDIR)/fs/ -fno-strict-aliasing" condition="HFSP"/> </library> </build> diff --git a/fs/hfsplus/hfsp_btree.c b/fs/hfsplus/hfsp_btree.c new file mode 100644 index 0000000..24eca92 --- /dev/null +++ b/fs/hfsplus/hfsp_btree.c @@ -0,0 +1,372 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * The fucntions are used to handle the various forms of btrees + * found on HFS+ volumes. + * + * Copyright (C) 2000 Klaus Halfmann khalfmann@libra.de + * Original 1996-1998 Robert Leslie rob@mars.org + * Additional work by Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: btree.c,v 1.14 2000/10/25 05:43:04 hasi Exp $ + */ + +#include "config.h" +#include "libhfsp.h" +#include "volume.h" +#include "btree.h" +#include "record.h" +#include "swab.h" + +/* Read the node from the given buffer and swap the bytes. + * + * return pointer after reading the structure + */ +static void* btree_readnode(btree_node_desc* node, void *p) +{ + node->next = bswabU32_inc(p); + node->prev = bswabU32_inc(p); + node->kind = bswabU8_inc(p); + node->height = bswabU8_inc(p); + node->num_rec = bswabU16_inc(p); + node->reserved = bswabU16_inc(p); + return p; +} + +/* read a btree header from the given buffer and swap the bytes. + * + * return pointer after reading the structure + */ +static void* btree_readhead(btree_head* head, void *p) +{ + UInt32 *q; + head->depth = bswabU16_inc(p); + head->root = bswabU32_inc(p); + head->leaf_count = bswabU32_inc(p); + head->leaf_head = bswabU32_inc(p); + head->leaf_tail = bswabU32_inc(p); + head->node_size = bswabU16_inc(p); + head->max_key_len = bswabU16_inc(p); + head->node_count = bswabU32_inc(p); + head->free_nodes = bswabU32_inc(p); + head->reserved1 = bswabU16_inc(p); + head->clump_size = bswabU32_inc(p); + head->btree_type = bswabU8_inc(p); + head->reserved2 = bswabU8_inc(p); + head->attributes = bswabU32_inc(p); + // skip reserved bytes + q=((UInt32*) p); + // ((UInt32*) p) += 16; + q+=16; + return q; +} + +/* Priority of the depth of the node compared to LRU value. + * Should be the average number of keys per node but these vary. */ +#define DEPTH_FACTOR 1000 + +/* Cache size is height of tree + this value + * Really big numbers wont help in case of ls -R + */ +#define EXTRA_CACHESIZE 3 + +/* Not in use by now ... */ +#define CACHE_DIRTY 0x0001 + +/* Intialize cache with default cache Size, + * must call node_cache_close to deallocate memory */ +static int node_cache_init(node_cache* cache, btree* tree, int size) +{ + int nodebufsize; + char * buf; + + cache->size = size; + cache->currindex = 0; + nodebufsize = tree->head.node_size + sizeof(node_buf); + buf = malloc(size *(sizeof(node_entry) + nodebufsize)); + if (!buf) + return -1; + cache -> nodebufsize = nodebufsize; + cache -> entries = (node_entry*) buf; + cache -> buffers = (char*) &cache->entries[size]; + bzero(cache->entries, size*sizeof(node_entry)); + return 0; +} + +/* Like cache->buffers[i], since size of node_buf is variable */ +static inline node_buf* node_buf_get(node_cache* cache, int i) +{ + return (node_buf*) (cache->buffers + (i * cache->nodebufsize)); +} + +/* flush the node at index */ +static void node_cache_flush_node(node_cache* cache, int index) +{ + // NYI + cache -> entries[index].index = 0; // invalidate entry +} + +static void node_cache_close(node_cache* cache) +{ + if (!cache->entries) // not (fully) intialized ? + return; + free(cache->entries); +} + +/* Load the cach node indentified by index with + * the node identified by node_index */ + +static node_buf* node_cache_load_buf + (btree* bt, node_cache* cache, int index, UInt16 node_index) +{ + node_buf *result = node_buf_get(cache ,index); + UInt32 blkpernode = bt->blkpernode; + UInt32 block = node_index * blkpernode; + void* p = volume_readfromfork(bt->vol, result->node, bt->fork, + block, blkpernode, HFSP_EXTENT_DATA, bt->cnid); + node_entry *e = &cache->entries[index]; + + if (!p) + return NULL; // evil ... + + result->index = node_index; + btree_readnode(&result->desc, p); + + e -> priority = result->desc.height * DEPTH_FACTOR; + e -> index = node_index; + return result; +} + +/* Read node at given index, using cache. + */ +node_buf* btree_node_by_index(btree* bt, UInt16 index) +{ + node_cache* cache = &bt->cache; + int oldindex, lruindex; + int currindex = cache->currindex; + UInt32 prio; + node_entry *e; + + // Shortcut acces to current node, will not change priorities + if (cache->entries[currindex].index == index) + return node_buf_get(cache ,currindex); + oldindex = currindex; + if (currindex == 0) + currindex = cache->size; + currindex--; + lruindex = oldindex; // entry to be flushed when needed + prio = 0; // current priority + while (currindex != oldindex) // round robin + { + e = &cache->entries[currindex]; + if (e->index == index) // got it + { + if (e->priority != 0) // already top, uuh + e->priority--; + cache->currindex = currindex; + return node_buf_get(cache ,currindex); + } + else + { + if (!e->index) + { + lruindex = currindex; + break; // empty entry, load it + } + if (e->priority != UINT_MAX) // already least, uuh + e->priority++; + } + if (prio < e->priority) + { + lruindex = currindex; + prio = e->priority; + } + if (currindex == 0) + currindex = cache->size; + currindex--; + } + e = &cache->entries[lruindex]; + cache->currindex = lruindex; + if (e->flags & CACHE_DIRTY) + node_cache_flush_node( cache, lruindex); + return node_cache_load_buf (bt, cache, lruindex, index); +} + +/** intialize the btree with the first entry in the fork */ +static int btree_init(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ + void *p; + char buf[vol->blksize]; + UInt16 node_size; + btree_node_desc node; + + bt->vol = vol; + bt->fork = fork; + p = volume_readfromfork(vol, buf, fork, 0, 1, + HFSP_EXTENT_DATA, bt->cnid); + if (!p) + return -1; + p = btree_readnode(&node, p); + if (node.kind != HFSP_NODE_HEAD) + return -1; // should not happen ? + btree_readhead(&bt->head, p); + + node_size = bt->head.node_size; + bt->blkpernode = node_size / vol->blksize; + + if (bt->blkpernode == 0 || vol->blksize * + bt->blkpernode != node_size) + return -1; // should never happen ... + + node_cache_init(&bt->cache, bt, bt->head.depth + EXTRA_CACHESIZE); + + // Allocate buffer + // bt->buf = malloc(node_size); + // if (!bt->buf) + // return ENOMEM; + + return 0; +} + +/** Intialize catalog btree, so that btree_close can safely be called. */ +void btree_reset(btree* bt) +{ + bt->cache.entries = NULL; +} + +/** Intialize catalog btree */ +int btree_init_cat(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ + int result = btree_init(bt,vol,fork); // super (...) + bt->cnid = HFSP_CAT_CNID; + bt->kcomp = record_key_compare; + bt->kread = record_readkey; + return result; +} + +/** Intialize catalog btree */ +int btree_init_extent(btree* bt, volume* vol, hfsp_fork_raw* fork) +{ + int result = btree_init(bt,vol,fork); // super (...) + bt->cnid = HFSP_EXT_CNID; + bt->kcomp = record_extent_key_compare; + bt->kread = record_extent_readkey; + return result; +} + +/** close the btree and free any resources */ +void btree_close(btree* bt) +{ + node_cache_close(&bt->cache); + // free(bt->buf); +} + +/* returns pointer to key given by index in current node. + * + * Assumes that current node is not NODE_HEAD ... + */ +void* btree_key_by_index(btree* bt, node_buf* buf, UInt16 index) +{ + UInt16 node_size = bt->head.node_size; + // The offsets are found at the end of the node ... + UInt16 off_pos = node_size - (index +1) * sizeof(btree_record_offset); + // position of offset at end of node + btree_record_offset* offset = + (btree_record_offset*) (buf->node + off_pos); + + // now we have the offset and can read the key ... +#ifdef CONFIG_LITTLE_ENDIAN + return buf->node + bswabU16(*offset); +#else + return buf->node + *offset; +#endif +} + + +#ifdef DEBUG + +/* print btree header node information */ +void btree_printhead(btree_head* head) +{ + UInt32 attr; + printf(" depth : %#X\n", head->depth); + printf(" root : %#lX\n", head->root); + printf(" leaf_count : %#lX\n", head->leaf_count); + printf(" leaf_head : %#lX\n", head->leaf_head); + printf(" leaf_tail : %#lX\n", head->leaf_tail); + printf(" node_size : %#X\n", head->node_size); + printf(" max_key_len : %#X\n", head->max_key_len); + printf(" node_count : %#lX\n", head->node_count); + printf(" free_nodes : %#lX\n", head->free_nodes); + printf(" reserved1 : %#X\n", head->reserved1); + printf(" clump_size : %#lX\n", head->clump_size); + printf(" btree_type : %#X\n", head->btree_type); + attr = head->attributes; + printf(" reserved2 : %#X\n", head->reserved2); + if (attr & HFSPLUS_BAD_CLOSE) + printf(" HFSPLUS_BAD_CLOSE *** "); + else + printf(" !HFSPLUS_BAD_CLOSE"); + if (attr & HFSPLUS_TREE_BIGKEYS) + printf(" HFSPLUS_TREE_BIGKEYS "); + else + printf(" !HFSPLUS_TREE_BIGKEYS"); + if (attr & HFSPLUS_TREE_VAR_NDXKEY_SIZE) + printf(" HFSPLUS_TREE_VAR_NDXKEY_SIZE"); + else + printf(" !HFSPLUS_TREE_VAR_NDXKEY_SIZE"); + if (attr & HFSPLUS_TREE_UNUSED) + printf(" HFSPLUS_TREE_UNUSED ***\n"); + printf("\n"); +} + +/* Dump all the node information to stdout */ +void btree_print(btree* bt) +{ + btree_node_desc* node; + + btree_printhead(&bt->head); + + node = &bt->node; + printf("next : %#lX\n", node->next); + printf("prev : %#lX\n", node->prev); + printf("height : %#X\n", node->height); + printf("num_rec : %#X\n", node->num_rec); + printf("reserved : %#X\n", node->reserved); + printf("height : %#X\n", node->height); switch(node->kind) + { + case HFSP_NODE_NDX : + printf("HFSP_NODE_NDX\n"); + break; + case HFSP_NODE_HEAD : + printf("HFSP_NODE_HEAD\n"); + break; + case HFSP_NODE_MAP : + printf("HFSP_NODE_MAP\n"); + break; + case HFSP_NODE_LEAF : + printf("HFSP_NODE_LEAF\n"); + break; + default: + printf("*** Unknown Node type ***\n"); + } +} + +#endif diff --git a/fs/hfsplus/hfsp_record.c b/fs/hfsplus/hfsp_record.c new file mode 100644 index 0000000..d4e7af1 --- /dev/null +++ b/fs/hfsplus/hfsp_record.c @@ -0,0 +1,759 @@ +/* + * libhfsp - library for reading and writing Macintosh HFS+ volumes. + * + * a record contains a key and a folder or file and is part + * of a btree. + * + * Copyright (C) 2000 Klaus Halfmann khalfmann@libra.de + * Original 1996-1998 Robert Leslie rob@mars.org + * Additional work by Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: record.c,v 1.24 2000/10/17 05:58:46 hasi Exp $ + */ + +#include "config.h" +#include "libhfsp.h" +#include "hfstime.h" +#include "record.h" +#include "volume.h" +#include "btree.h" +#include "unicode.h" +#include "swab.h" + +/* read a hfsp_cat_key from memory */ +void* record_readkey(void* p, void* buf) +{ + hfsp_cat_key* key = (hfsp_cat_key*) buf; + const void* check; + UInt16 key_length, len,i; + UInt16* cp; + + key->key_length = key_length = bswabU16_inc(p); + check = p; + key->parent_cnid = bswabU32_inc(p); + key->name.strlen = len = bswabU16_inc(p); + cp = key->name.name; + for (i=0; i < len; i++, cp++) + *cp = bswabU16_inc(p); + /* check if keylenght was correct */ + if (key_length != ((char*) p) - ((char*) check)) + HFSP_ERROR(EINVAL, "Invalid key length in record_readkey"); + return p; + fail: + return NULL; +} + +/* read a hfsp_extent_key from memory */ +void* record_extent_readkey(void* p, void* buf) +{ + hfsp_extent_key* key = (hfsp_extent_key*) buf; + UInt16 key_length; + + key->key_length = key_length = bswabU16_inc(p); + key->fork_type = bswabU8_inc(p); + key->filler = bswabU8_inc(p); + if (key_length != 10) + HFSP_ERROR(-1, "Invalid key length in record_extent_readkey"); + key->file_id = bswabU32_inc(p); + key->start_block = bswabU32_inc(p); + return p; + fail: + return NULL; +} + + +/* read posix permission from memory */ +static inline void* record_readperm(void *p, hfsp_perm* perm) +{ + perm->owner= bswabU32_inc(p); + perm->group= bswabU32_inc(p); + perm->mode = bswabU32_inc(p); + perm->dev = bswabU32_inc(p); + return p; +} + +/* read directory info */ +static inline void* record_readDInfo(void *p, DInfo* info) +{ + info->frRect.top = bswabU16_inc(p); + info->frRect.left = bswabU16_inc(p); + info->frRect.bottom = bswabU16_inc(p); + info->frRect.right = bswabU16_inc(p); + info->frFlags = bswabU16_inc(p); + info->frLocation.v = bswabU16_inc(p); + info->frLocation.h = bswabU16_inc(p); + info->frView = bswabU16_inc(p); + return p; +} + +/* read extra Directory info */ +static inline void* record_readDXInfo(void *p, DXInfo* xinfo) +{ + xinfo->frScroll.v = bswabU16_inc(p); + xinfo->frScroll.h = bswabU16_inc(p); + xinfo->frOpenChain = bswabU32_inc(p); + xinfo->frUnused = bswabU16_inc(p); + xinfo->frComment = bswabU16_inc(p); + xinfo->frPutAway = bswabU32_inc(p); + return p; +} + +/* read a hfsp_cat_folder from memory */ +static void* record_readfolder(void *p, hfsp_cat_folder* folder) +{ + folder->flags = bswabU16_inc(p); + folder->valence = bswabU32_inc(p); + folder->id = bswabU32_inc(p); + folder->create_date = bswabU32_inc(p); + folder->content_mod_date = bswabU32_inc(p); + folder->attribute_mod_date = bswabU32_inc(p); + folder->access_date = bswabU32_inc(p); + folder->backup_date = bswabU32_inc(p); + p = record_readperm (p, &folder->permissions); + p = record_readDInfo (p, &folder->user_info); + p = record_readDXInfo (p, &folder->finder_info); + folder->text_encoding = bswabU32_inc(p); + folder->reserved = bswabU32_inc(p); + return p; +} + +/* read file info */ +static inline void* record_readFInfo(void *p, FInfo* info) +{ + info->fdType = bswabU32_inc(p); + info->fdCreator = bswabU32_inc(p); + info->fdFlags = bswabU16_inc(p); + info->fdLocation.v = bswabU16_inc(p); + info->fdLocation.h = bswabU16_inc(p); + info->fdFldr = bswabU16_inc(p); + return p; +} + +/* read extra File info */ +static inline void* record_readFXInfo(void *p, FXInfo* xinfo) +{ + SInt16 *q; + xinfo->fdIconID = bswabU16_inc(p); + q=(SInt16*) p; + q+=4; // skip unused + p=(void *)q; + xinfo->fdComment = bswabU16_inc(p); + xinfo->fdPutAway = bswabU32_inc(p); + return p; +} + +/* read a hfsp_cat_file from memory */ +static void* record_readfile(void *p, hfsp_cat_file* file) +{ + file->flags = bswabU16_inc(p); + file->reserved1 = bswabU32_inc(p); + file->id = bswabU32_inc(p); + file->create_date = bswabU32_inc(p); + file->content_mod_date = bswabU32_inc(p); + file->attribute_mod_date = bswabU32_inc(p); + file->access_date = bswabU32_inc(p); + file->backup_date = bswabU32_inc(p); + p = record_readperm (p, &file->permissions); + p = record_readFInfo (p, &file->user_info); + p = record_readFXInfo (p, &file->finder_info); + file->text_encoding = bswabU32_inc(p); + file->reserved2 = bswabU32_inc(p); + p = volume_readfork (p, &file->data_fork); + return volume_readfork (p, &file->res_fork); +} + +/* read a hfsp_cat_thread from memory */ +static void* record_readthread(void *p, hfsp_cat_thread* entry) +{ + int i; + UInt16 len; + UInt16* cp; + + entry-> reserved = bswabU16_inc(p); + entry-> parentID = bswabU32_inc(p); + entry->nodeName.strlen = len= bswabU16_inc(p); + cp = entry->nodeName.name; + if (len > 255) + HFSP_ERROR(-1, "Invalid key length in record thread"); + for (i=0; i < len; i++, cp++) + *cp = bswabU16_inc(p); + return p; + fail: + return NULL; +} + +/* read a hfsp_cat_entry from memory */ +static void* record_readentry(void *p, hfsp_cat_entry* entry) +{ + UInt16 type = bswabU16_inc(p); + entry->type = type; + switch (type) + { + case HFSP_FOLDER: + return record_readfolder(p, &entry->u.folder); + case HFSP_FILE: + return record_readfile (p, &entry->u.file); + case HFSP_FOLDER_THREAD: + case HFSP_FILE_THREAD: + return record_readthread(p, &entry->u.thread); + default: + HFSP_ERROR(-1, "Unexpected record type in record_readentry"); + } ; + fail: + return NULL; +} + + +/* Most of the functions here will not change the node in the btree, + But this must be changed in the future ... */ + + +/* intialize the record with the given index entry in the btree. */ +static int record_init(record* r, btree* bt, node_buf* buf, UInt16 index) +{ + void *p; + r-> tree = bt; + p = btree_key_by_index(bt,buf,index); + if (!p) + return -1; + p = record_readkey (p, &r->key); + if (!p) + return -1; + p = record_readentry(p, &r->record); + if (!p) + return -1; + r->node_index = buf->index; + r-> keyind = index; + + return 0; +} + +/* intialize the record with the given index entry in the btree. */ +static int record_init_extent(extent_record* r, btree* bt, node_buf* buf, UInt16 index) +{ + void *p; + r-> tree = bt; + p = btree_key_by_index(bt, buf,index); + if (!p) + return -1; + p = record_extent_readkey(p, &r->key); + if (!p) + return -1; + p = volume_readextent(p, r->extent); + if (!p) + return -1; + r->node_index = buf->index; + r-> keyind = index; + + return 0; +} + +/* intialize the record to the first record of the tree + * which is (per design) the root node. + */ +int record_init_root(record* r, btree* tree) +{ + // Position to first leaf node ... + UInt32 leaf_head = tree->head.leaf_head; + node_buf* buf = btree_node_by_index(tree, leaf_head); + if (!buf) + return -1; + return record_init(r, tree, buf, 0); +} + +/* Compare two cat_keys ... */ +int record_key_compare(void* k1, void* k2) +{ + hfsp_cat_key* key1 = (hfsp_cat_key*) k1; + hfsp_cat_key* key2 = (hfsp_cat_key*) k2; + int diff = key2->parent_cnid - key1->parent_cnid; + if (!diff) // same parent + diff = fast_unicode_compare(&key1->name, &key2->name); + return diff; +} + +/* Compare two extent_keys ... */ +int record_extent_key_compare(void* k1, void* k2) +{ + hfsp_extent_key* key1 = (hfsp_extent_key*) k1; + hfsp_extent_key* key2 = (hfsp_extent_key*) k2; + int diff = key2->fork_type - key1->fork_type; + if (!diff) // same type + { + diff = key2->file_id - key1->file_id; + if (!diff) // same file + diff = key2->start_block - key1->start_block; + } + return diff; +} + +/* Position node in btree so that key might be inside */ +static node_buf* record_find_node(btree* tree, void *key) +{ + int start, end, mid, comp; // components of a binary search + void *p = NULL; + char curr_key[tree->head.max_key_len]; + // The current key under examination + hfsp_key_read readkey = tree->kread; + hfsp_key_compare key_compare = tree->kcomp; + UInt32 index; + node_buf* node = btree_node_by_index(tree, tree->head.root); + if (!node) + HFSP_ERROR(-1, "record_find_node: Cant position to root node"); + while (node->desc.kind == HFSP_NODE_NDX) + { + mid = start = 0; + end = node->desc.num_rec; + comp = -1; + while (start < end) + { + mid = (start + end) >> 1; + p = btree_key_by_index(tree, node, mid); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + p = readkey (p, curr_key); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + comp = key_compare(curr_key, key); + if (comp > 0) + start = mid + 1; + else if (comp < 0) + end = mid; + else + break; + } + if (!p) // Empty tree, fascinating ... + HFSP_ERROR(-1, "record_find_node: unexpected empty node"); + if (comp < 0) // mmh interesting key is before this key ... + { + if (mid == 0) + return NULL; // nothing before this key .. + p = btree_key_by_index(tree, node, mid-1); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + p = readkey (p, curr_key); + if (!p) + HFSP_ERROR(-1, "record_find_node: unexpected error"); + } + + index = bswabU32_inc(p); + node = btree_node_by_index(tree, index); + } + return node; // go on and use the found node + fail: + return NULL; +} + +/* search for the given key in the btree. + * + * returns pointer to memory just after key or NULL + * In any case *keyind recives the index where the + * key was found (or could be inserted.) + */ +static void * +record_find_key(btree* tree, void* key, int* keyind, UInt16* node_index) +{ + node_buf* buf = record_find_node(tree, key); + if (buf) + { + int comp = -1; + int start = 0; // components of a binary search + int end = buf->desc.num_rec; + int mid = -1; + void *p = NULL; + char curr_key[tree->head.max_key_len]; + hfsp_key_read readkey = tree->kread; + hfsp_key_compare key_compare = tree->kcomp; + while (start < end) + { + mid = (start + end) >> 1; + p = btree_key_by_index(tree, buf, mid); + if (!p) + HFSP_ERROR(-1, "record_init_key: unexpected error"); + p = readkey (p, curr_key); + if (!p) + HFSP_ERROR(-1, "record_init_cat_key: unexpected error"); + comp = key_compare(curr_key, key); + if (comp > 0) + start = mid + 1; + else if (comp < 0) + end = mid; + else + break; + } + if (!p) // Empty tree, fascinating ... + HFSP_ERROR(ENOENT, "record_init_key: unexpected empty node"); + *keyind = mid; + *node_index = buf->index; + if (!comp) // found something ... + return p; + } + HFSP_ERROR(ENOENT, NULL); + fail: + return NULL; +} + +/* intialize the record by searching for the given key in the btree. + * + * r is umodified on error. + */ +static int +record_init_key(record* r, btree* tree, hfsp_cat_key* key) +{ + int keyind; + UInt16 node_index; + void *p = record_find_key(tree, key, &keyind, &node_index); + + if (p) + { + r -> tree = tree; + r -> node_index= node_index; + r -> keyind = keyind; + r -> key = *key; // Better use a record_key_copy ... + p = record_readentry(p, &r->record); + if (!p) + HFSP_ERROR(-1, "record_init_key: unexpected error"); + return 0; + } + fail: + return -1; +} + +/* intialize the extent_record to the extent identified by the + * (first) blockindex. + * + * forktype: either HFSP_EXTEND_DATA or HFSP_EXTEND_RSRC + */ +int record_init_file(extent_record* r, btree* tree, + UInt8 forktype, UInt32 fileId, UInt32 blockindex) +{ + int keyind; + UInt16 node_index; + hfsp_extent_key key = { 10, forktype, 0, fileId, blockindex }; + void *p = record_find_key(tree, &key, &keyind, &node_index); + + if (p) + { + r -> tree = tree; + r -> node_index= node_index; + r -> keyind = keyind; + r -> key = key; // Better use a record_key_copy ... + p = volume_readextent(p, r->extent); + if (!p) + HFSP_ERROR(-1, "record_init_file: unexpected error"); + return 0; + } + fail: + return -1; +} + +/* intialize the record to the folder identified by cnid + */ +int record_init_cnid(record* r, btree* tree, UInt32 cnid) +{ + hfsp_cat_key thread_key; // the thread is the first record + + thread_key.key_length = 6; // null name (like '.' in unix ) + thread_key.parent_cnid = cnid; + thread_key.name.strlen = 0; + + return record_init_key(r, tree, &thread_key); +} + +/* intialize the record to the first record of the parent. + */ +int record_init_parent(record* r, record* parent) +{ + if (parent->record.type == HFSP_FOLDER) + return record_init_cnid(r, parent->tree, parent->record.u.folder.id); + else if(parent->record.type == HFSP_FOLDER_THREAD) + { + if (r != parent) + *r = *parent; // The folder thread is in fact the first entry, like '.' + return 0; + } + HFSP_ERROR(EINVAL, + "record_init_parent: parent is neither folder nor folder thread."); + + fail: + return EINVAL; +} + + +/* find correct node record for given node and *pindex. + * + * index of record in this (or next) node + * */ +static node_buf* prepare_next(btree* tree, UInt16 node_index, UInt16* pindex) +{ + node_buf* buf = btree_node_by_index(tree, node_index); + btree_node_desc* desc = &buf->desc; + UInt32 numrec = desc->num_rec; + if (*pindex >= numrec) // move on to next node + { + UInt16 next = desc->next; + *pindex = 0; + if (!next /* is there a next node ? */ + || !( buf = btree_node_by_index(tree, next))) + return NULL; + } + return buf; +} +/* move record foreward to next entry. + * + * In case of an error the value of *r is undefined ! + */ +int record_next(record* r) +{ + btree* tree = r->tree; + UInt16 index = r->keyind +1; + UInt32 parent; + node_buf* buf = prepare_next(tree, r->node_index, &index); + + if (!buf) + return ENOENT; // No (more) such file or directory + + parent = r->key.parent_cnid; + + if (record_init(r, tree, buf, index)) + return -1; + + if (r->key.parent_cnid != parent || // end of current directory + index != r->keyind) // internal error ? + return ENOENT; // No (more) such file or directory + + return 0; +} + +/* move record foreward to next extent record. + * + * In case of an error the value of *r is undefined ! + */ +int record_next_extent(extent_record* r) +{ + btree* tree = r->tree; + UInt16 index = r->keyind +1; + UInt32 file_id; + UInt8 fork_type; + node_buf* buf = prepare_next(tree, r->node_index, &index); + + if (!buf) + return ENOENT; // No (more) such file or directory + + file_id = r->key.file_id; + fork_type = r->key.fork_type; + + if (record_init_extent(r, tree, buf, index)) + return -1; + + if (r->key.file_id != file_id || // end of current file + r->key.fork_type != fork_type || // end of current fork + index != r->keyind) // internal error ? + return ENOENT; // No (more) such file or directory + + return 0; +} + +/* intialize the record by searching for the given string in the given folder. + * + * parent and r may be the same. + */ +int record_init_string_parent(record* r, record* parent, char* name) +{ + hfsp_cat_key key; + + if (parent->record.type == HFSP_FOLDER) + key.parent_cnid = parent->record.u.folder.id; + else if(parent->record.type == HFSP_FOLDER_THREAD) + key.parent_cnid = parent->key.parent_cnid; + else + HFSP_ERROR(-1, "record_init_string_parent: parent is not a folder."); + + key.key_length = 6 + unicode_asc2uni(&key.name,name); // 6 for minumum size + return record_init_key(r, parent->tree, &key); + + fail: + return -1; +} + +/* move record up in folder hierarchy (if possible) */ +int record_up(record* r) +{ + if (r->record.type == HFSP_FOLDER) + { + // locate folder thread + if (record_init_cnid(r, r->tree, r->record.u.folder.id)) + return -1; + } + else if(r->record.type == HFSP_FOLDER_THREAD) + { + // do nothing were are already where we want to be + } + else + HFSP_ERROR(-1, "record_up: record is neither folder nor folder thread."); + + if(r->record.type != HFSP_FOLDER_THREAD) + HFSP_ERROR(-1, "record_up: unable to locate parent"); + return record_init_cnid(r, r->tree, r->record.u.thread.parentID); + + fail: + return -1; +} + +#ifdef DEBUG + +/* print Quickdraw Point */ +static void record_print_Point(Point* p) +{ + printf("[ v=%d, h=%d ]", p->v, p->h); +} + +/* print Quickdraw Rect */ +static void record_print_Rect(Rect* r) +{ + printf("[ top=%d, left=%d, bottom=%d, right=%d ]", + r->top, r->left, r->bottom, r->right); +} + +/* print the key of a record */ +static void record_print_key(hfsp_cat_key* key) +{ + char buf[255]; // mh this _might_ overflow + unicode_uni2asc(buf, &key->name, 255); + printf("parent cnid : %ld\n", key->parent_cnid); + printf("name : %s\n", buf); +} + +/* print permissions */ +static void record_print_perm(hfsp_perm* perm) +{ + printf("owner :\t%ld\n", perm->owner); + printf("group :\t%ld\n", perm->group); + printf("perm :\t0x%lX\n",perm->mode); + printf("dev :\t%ld\n", perm->dev); +} + +/* print Directory info */ +static void record_print_DInfo(DInfo* dinfo) +{ + printf( "frRect :\t"); record_print_Rect(&dinfo->frRect); + printf("\nfrFlags :\t0X%X\n", dinfo->frFlags); + printf( "frLocation :\t"); record_print_Point(&dinfo->frLocation); + printf("\nfrView :\t0X%X\n", dinfo->frView); +} + +/* print extended Directory info */ +static void record_print_DXInfo(DXInfo* xinfo) +{ + printf( "frScroll :\t"); record_print_Point(&xinfo->frScroll); + printf("\nfrOpenChain :\t%ld\n", xinfo->frOpenChain); + printf( "frUnused :\t%d\n", xinfo->frUnused); + printf( "frComment :\t%d\n", xinfo->frComment); + printf( "frPutAway :\t%ld\n", xinfo->frPutAway); +} + +static void record_print_folder(hfsp_cat_folder* folder) +{ + printf("flags :\t0x%X\n", folder->flags); + printf("valence :\t0x%lX\n", folder->valence); + printf("id :\t%ld\n", folder->id); + record_print_perm (&folder->permissions); + record_print_DInfo (&folder->user_info); + record_print_DXInfo (&folder->finder_info); + printf("text_encoding :\t0x%lX\n", folder->text_encoding); + printf("reserved :\t0x%lX\n", folder->reserved); +} + +/* print File info */ +static void record_print_FInfo(FInfo* finfo) +{ + printf( "fdType :\t%4.4s\n", (char*) &finfo->fdType); + printf( "fdCreator :\t%4.4s\n", (char*) &finfo->fdCreator); + printf( "fdFlags :\t0X%X\n", finfo->fdFlags); + printf( "fdLocation :\t"); record_print_Point(&finfo->fdLocation); + printf("\nfdFldr :\t%d\n", finfo->fdFldr); +} + +/* print extended File info */ +static void record_print_FXInfo(FXInfo* xinfo) +{ + printf( "fdIconID :\t%d\n", xinfo->fdIconID); + // xinfo -> fdUnused; + printf( "fdComment :\t%d\n", xinfo->fdComment); + printf( "fdPutAway :\t%ld\n", xinfo->fdPutAway); +} + +/* print folder entry */ + +/* print file entry */ +static void record_print_file(hfsp_cat_file* file) +{ + printf("flags :\t0x%X\n", file->flags); + printf("reserved1 :\t0x%lX\n", file->reserved1); + printf("id :\t%ld\n", file->id); + record_print_perm (&file->permissions); + record_print_FInfo (&file->user_info); + record_print_FXInfo (&file->finder_info); + printf("text_encoding :\t0x%lX\n", file->text_encoding); + printf("reserved :\t0x%lX\n", file->reserved2); + printf("Datafork:\n"); + volume_print_fork (&file->data_fork); + printf("Rsrcfork:\n"); + volume_print_fork (&file->res_fork); +} + +/* print info for a file or folder thread */ +static void record_print_thread(hfsp_cat_thread* entry) +{ + char buf[255]; // mh this _might_ overflow + unicode_uni2asc(buf, &entry->nodeName, 255); + printf("parent cnid :\t%ld\n", entry->parentID); + printf("name :\t%s\n" , buf); +} + +/* print the information for a record */ +static void record_print_entry(hfsp_cat_entry* entry) +{ + switch (entry->type) + { + case HFSP_FOLDER: + printf("=== Folder ===\n"); + return record_print_folder(&entry->u.folder); + case HFSP_FILE: + printf("=== File ===\n"); + return record_print_file (&entry->u.file); + case HFSP_FOLDER_THREAD: + printf("=== Folder Thread ===\n"); + return record_print_thread(&entry->u.thread); + case HFSP_FILE_THREAD: + printf("=== File Thread ==\n"); + return record_print_thread(&entry->u.thread); + default: + printf("=== Unknown Record Type ===\n"); + } ; +} + + /* Dump all the record information to stdout */ +void record_print(record* r) +{ + printf ("keyind : %u\n", r->keyind); + record_print_key (&r->key); + record_print_entry(&r->record); +} + +#endif diff --git a/fs/hfsplus/hfsp_volume.c b/fs/hfsplus/hfsp_volume.c new file mode 100644 index 0000000..802d700 --- /dev/null +++ b/fs/hfsplus/hfsp_volume.c @@ -0,0 +1,314 @@ +/* + * libhfs - library for reading and writing Macintosh HFS volumes + * + * Code to acces the basic volume information of a HFS+ volume. + * + * Copyright (C) 2000 Klaus Halfmann khalfmann@libra.de + * Original work by 1996-1998 Robert Leslie rob@mars.org + * other work 2000 from Brad Boyer (flar@pants.nu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * $Id: volume.c,v 1.21 2000/10/25 05:43:04 hasi Exp $ + */ + +#include "config.h" +#include "libhfsp.h" +#include "volume.h" +#include "record.h" +#include "btree.h" +#include "blockiter.h" +#include "os.h" +#include "swab.h" +#include "hfstime.h" + + +/* Fill a given buffer with the given block in volume. + */ +int +volume_readinbuf(volume * vol,void* buf, long block) +{ + UInt16 blksize_bits; + ASSERT( block < vol->maxblocks); + + blksize_bits = vol->blksize_bits; + block += vol->startblock; + if( os_seek(vol->os_fd, block, blksize_bits) == block) + if( 1 == os_read(vol->os_fd, buf, 1, blksize_bits)) + return 0; + return -1; +} + +/* read multiple blocks into given memory. + * + * returns given pinter or NULL on failure. + */ +void* +volume_readfromfork(volume* vol, void* buf, + hfsp_fork_raw* f, UInt32 block, + UInt32 count, UInt8 forktype, UInt32 fileId) +{ + blockiter iter; + char *cbuf = buf; + + blockiter_init(&iter, vol, f, forktype, fileId); + if( blockiter_skip(&iter, block)) + return NULL; + + while( count > 0) { + --count; + if( volume_readinbuf(vol, cbuf, blockiter_curr(&iter))) + return NULL; + cbuf += vol->blksize; + if( count > 0 && blockiter_next(&iter)) + return NULL; + } + return buf; +} + + +/* Read a raw hfsp_extent_rec from memory. + * + * return pointer right after the structure. + */ +void* +volume_readextent(void *p, hfsp_extent_rec er) +{ + int i; + hfsp_extent *e; + + for( i=0; i < 8; i++) { + e = &er[i]; + e->start_block = bswabU32_inc(p); + e->block_count = bswabU32_inc(p); + } + return p; +} + +/* Read a raw hfsp_fork from memory. + * + * return pointer right after the structure. + */ +void* +volume_readfork(void *p, hfsp_fork_raw* f) +{ + f->total_size = bswabU64_inc(p); + f->clump_size = bswabU32_inc(p); + f->total_blocks = bswabU32_inc(p); + + return volume_readextent(p, f->extents); +} + +/* Read the volume from the given buffer and swap the bytes. + * + * ToDo: add more consitency checks. + */ +static int +volume_readbuf(hfsp_vh* vh, char * p) +{ + if( (vh->signature = bswabU16_inc(p)) != HFSP_VOLHEAD_SIG) + HFSP_ERROR(-1, "This is not a HFS+ volume"); + + vh->version = bswabU16_inc(p); + vh->attributes = bswabU32_inc(p); + vh->last_mount_vers = bswabU32_inc(p); + vh->reserved = bswabU32_inc(p); + vh->create_date = bswabU32_inc(p); + vh->modify_date = bswabU32_inc(p); + vh->backup_date = bswabU32_inc(p); + vh->checked_date = bswabU32_inc(p); + vh->file_count = bswabU32_inc(p); + vh->folder_count = bswabU32_inc(p); + vh->blocksize = bswabU32_inc(p); + vh->total_blocks = bswabU32_inc(p); + vh->free_blocks = bswabU32_inc(p); + vh->next_alloc = bswabU32_inc(p); + vh->rsrc_clump_sz = bswabU32_inc(p); + vh->data_clump_sz = bswabU32_inc(p); + vh->next_cnid = bswabU32_inc(p); + vh->write_count = bswabU32_inc(p); + vh->encodings_bmp = bswabU64_inc(p); + memcpy(vh->finder_info, p, 32); + p += 32; // So finderinfo must be swapped later, *** + p = volume_readfork(p, &vh->alloc_file ); + p = volume_readfork(p, &vh->ext_file ); + p = volume_readfork(p, &vh->cat_file ); + p = volume_readfork(p, &vh->attr_file ); + volume_readfork(p, &vh->start_file ); + return 0; + fail: + return -1; +} + +/* Read the volume from the given block */ +static int +volume_read(volume * vol, hfsp_vh* vh, UInt32 block) +{ + char buf[vol->blksize]; + + if( volume_readinbuf(vol, buf, block)) + return -1; + return volume_readbuf(vh, buf); +} + +/* Find out wether the volume is wrapped and unwrap it eventually */ +static int +volume_read_wrapper(volume * vol, hfsp_vh* vh) +{ + UInt16 signature; + char buf[vol->blksize]; + char *p = buf; + + if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here + return -1; + + signature = bswabU16_inc(p); + if( signature == HFS_VOLHEAD_SIG) { /* Wrapper */ + UInt32 drAlBlkSiz; /* size (in bytes) of allocation blocks */ + UInt32 sect_per_block; /* how may block build an hfs sector */ + UInt16 drAlBlSt; /* first allocation block in volume */ + UInt16 embeds, embedl; /* Start/lenght of embedded area in blocks */ + + p += 0x12; /* skip unneded HFS vol fields */ + drAlBlkSiz = bswabU32_inc(p); /* offset 0x14 */ + p += 0x4; /* skip unneded HFS vol fields */ + drAlBlSt = bswabU16_inc(p); /* offset 0x1C */ + + p += 0x5E; /* skip unneded HFS vol fields */ + signature = bswabU16_inc(p); /* offset 0x7C, drEmbedSigWord */ + if( signature != HFSP_VOLHEAD_SIG) + HFSP_ERROR(-1, "This looks like a normal HFS volume"); + embeds = bswabU16_inc(p); + embedl = bswabU16_inc(p); + sect_per_block = (drAlBlkSiz / HFSP_BLOCKSZ); + // end is absolute (not relative to HFS+ start) + vol->maxblocks = embedl * sect_per_block; + vol->startblock = drAlBlSt + embeds * sect_per_block; + /* Now we can try to read the embedded HFS+ volume header */ + return volume_read(vol,vh,2); + } + else if( signature == HFSP_VOLHEAD_SIG) { /* Native HFS+ volume */ + p = buf; // Restore to begin of block + return volume_readbuf(vh, p); + } else + HFSP_ERROR(-1, "Neither Wrapper nor native HFS+ volume header found"); +fail: + return -1; +} + + +/* Open the device, read and verify the volume header + (and its backup) */ +int +volume_open( volume* vol, int os_fd ) +{ + hfsp_vh backup; /* backup volume found at second to last block */ + long sect_per_block; + int shift; + + vol->blksize_bits = HFSP_BLOCKSZ_BITS; + vol->blksize = HFSP_BLOCKSZ; + vol->startblock = 0; + vol->maxblocks = 3; + /* this should be enough until we find the volume descriptor */ + vol->extents = NULL; /* Thanks to Jeremias Sauceda */ + + btree_reset(&vol->catalog); + vol->os_fd = os_fd; + + // vol->maxblocks = os_seek(vol->os_fd, -1, HFSP_BLOCKSZ_BITS); + // This wont work for /dev/... but we do not really need it + + if( volume_read_wrapper(vol, &vol->vol)) + return -1; + if( volume_read(vol, &backup, vol->maxblocks - 2)) + return -1; + + /* Now switch blksize from HFSP_BLOCKSZ (512) to value given in header + and adjust depend values accordingly, after that a block always + means a HFS+ allocation size */ + + /* Usually 4096 / 512 == 8 */ + sect_per_block = vol->vol.blocksize / HFSP_BLOCKSZ; + shift = 0; + if( sect_per_block > 1) { + shift = 1; + while( sect_per_block > 2) { + sect_per_block >>=1; + shift++; + } /* shift = 3 */ + } + vol -> blksize_bits += shift; + vol -> blksize = 1 << vol->blksize_bits; + vol -> startblock >>= shift; + vol -> maxblocks = vol->vol.total_blocks; /* cant calculate via shift ? */ + + if( btree_init_cat(&vol->catalog, vol, &vol->vol.cat_file)) + return -1; + + return 0; +} + +/* Write back all data eventually cached and close the device */ +int +volume_close(volume* vol) +{ + btree_close(&vol->catalog); + if( vol->extents) { + btree_close(vol->extents); + FREE(vol->extents); + } + return 0; +} + +/* internal fucntion used to create the extents btree, + is called by inline function when needed */ +void +volume_create_extents_tree(volume* vol) +{ + btree* result = (btree*) ALLOC(btree*, sizeof(btree)); + if( !result) + HFSP_ERROR(ENOMEM, "No memory for extents btree"); + if( !btree_init_extent(result, vol, &vol->vol.ext_file)) { + vol->extents = result; + return; + } + fail: + vol->extents = NULL; +} + +/* Determine whether the volume is a HFS-plus volume */ +int +volume_probe(int fd, long long offset) +{ + UInt16 *vol; + int ret = 0; + + vol = (UInt16 *)malloc(2 * 1 << HFSP_BLOCKSZ_BITS); + os_seek_offset( fd, 2 * (1 << HFSP_BLOCKSZ_BITS) + offset ); + os_read(fd, vol, 2, HFSP_BLOCKSZ_BITS); + + if (__be16_to_cpu(vol[0]) == HFS_VOLHEAD_SIG && + __be16_to_cpu(vol[0x7c]) == HFSP_VOLHEAD_SIG) { + ret = -1; + } else if (__be16_to_cpu(vol[0]) == HFSP_VOLHEAD_SIG) { + ret = -1; + } + + free(vol); + return ret; +} + diff --git a/fs/hfsplus/record.c b/fs/hfsplus/record.c deleted file mode 100644 index d4e7af1..0000000 --- a/fs/hfsplus/record.c +++ /dev/null @@ -1,759 +0,0 @@ -/* - * libhfsp - library for reading and writing Macintosh HFS+ volumes. - * - * a record contains a key and a folder or file and is part - * of a btree. - * - * Copyright (C) 2000 Klaus Halfmann khalfmann@libra.de - * Original 1996-1998 Robert Leslie rob@mars.org - * Additional work by Brad Boyer (flar@pants.nu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * $Id: record.c,v 1.24 2000/10/17 05:58:46 hasi Exp $ - */ - -#include "config.h" -#include "libhfsp.h" -#include "hfstime.h" -#include "record.h" -#include "volume.h" -#include "btree.h" -#include "unicode.h" -#include "swab.h" - -/* read a hfsp_cat_key from memory */ -void* record_readkey(void* p, void* buf) -{ - hfsp_cat_key* key = (hfsp_cat_key*) buf; - const void* check; - UInt16 key_length, len,i; - UInt16* cp; - - key->key_length = key_length = bswabU16_inc(p); - check = p; - key->parent_cnid = bswabU32_inc(p); - key->name.strlen = len = bswabU16_inc(p); - cp = key->name.name; - for (i=0; i < len; i++, cp++) - *cp = bswabU16_inc(p); - /* check if keylenght was correct */ - if (key_length != ((char*) p) - ((char*) check)) - HFSP_ERROR(EINVAL, "Invalid key length in record_readkey"); - return p; - fail: - return NULL; -} - -/* read a hfsp_extent_key from memory */ -void* record_extent_readkey(void* p, void* buf) -{ - hfsp_extent_key* key = (hfsp_extent_key*) buf; - UInt16 key_length; - - key->key_length = key_length = bswabU16_inc(p); - key->fork_type = bswabU8_inc(p); - key->filler = bswabU8_inc(p); - if (key_length != 10) - HFSP_ERROR(-1, "Invalid key length in record_extent_readkey"); - key->file_id = bswabU32_inc(p); - key->start_block = bswabU32_inc(p); - return p; - fail: - return NULL; -} - - -/* read posix permission from memory */ -static inline void* record_readperm(void *p, hfsp_perm* perm) -{ - perm->owner= bswabU32_inc(p); - perm->group= bswabU32_inc(p); - perm->mode = bswabU32_inc(p); - perm->dev = bswabU32_inc(p); - return p; -} - -/* read directory info */ -static inline void* record_readDInfo(void *p, DInfo* info) -{ - info->frRect.top = bswabU16_inc(p); - info->frRect.left = bswabU16_inc(p); - info->frRect.bottom = bswabU16_inc(p); - info->frRect.right = bswabU16_inc(p); - info->frFlags = bswabU16_inc(p); - info->frLocation.v = bswabU16_inc(p); - info->frLocation.h = bswabU16_inc(p); - info->frView = bswabU16_inc(p); - return p; -} - -/* read extra Directory info */ -static inline void* record_readDXInfo(void *p, DXInfo* xinfo) -{ - xinfo->frScroll.v = bswabU16_inc(p); - xinfo->frScroll.h = bswabU16_inc(p); - xinfo->frOpenChain = bswabU32_inc(p); - xinfo->frUnused = bswabU16_inc(p); - xinfo->frComment = bswabU16_inc(p); - xinfo->frPutAway = bswabU32_inc(p); - return p; -} - -/* read a hfsp_cat_folder from memory */ -static void* record_readfolder(void *p, hfsp_cat_folder* folder) -{ - folder->flags = bswabU16_inc(p); - folder->valence = bswabU32_inc(p); - folder->id = bswabU32_inc(p); - folder->create_date = bswabU32_inc(p); - folder->content_mod_date = bswabU32_inc(p); - folder->attribute_mod_date = bswabU32_inc(p); - folder->access_date = bswabU32_inc(p); - folder->backup_date = bswabU32_inc(p); - p = record_readperm (p, &folder->permissions); - p = record_readDInfo (p, &folder->user_info); - p = record_readDXInfo (p, &folder->finder_info); - folder->text_encoding = bswabU32_inc(p); - folder->reserved = bswabU32_inc(p); - return p; -} - -/* read file info */ -static inline void* record_readFInfo(void *p, FInfo* info) -{ - info->fdType = bswabU32_inc(p); - info->fdCreator = bswabU32_inc(p); - info->fdFlags = bswabU16_inc(p); - info->fdLocation.v = bswabU16_inc(p); - info->fdLocation.h = bswabU16_inc(p); - info->fdFldr = bswabU16_inc(p); - return p; -} - -/* read extra File info */ -static inline void* record_readFXInfo(void *p, FXInfo* xinfo) -{ - SInt16 *q; - xinfo->fdIconID = bswabU16_inc(p); - q=(SInt16*) p; - q+=4; // skip unused - p=(void *)q; - xinfo->fdComment = bswabU16_inc(p); - xinfo->fdPutAway = bswabU32_inc(p); - return p; -} - -/* read a hfsp_cat_file from memory */ -static void* record_readfile(void *p, hfsp_cat_file* file) -{ - file->flags = bswabU16_inc(p); - file->reserved1 = bswabU32_inc(p); - file->id = bswabU32_inc(p); - file->create_date = bswabU32_inc(p); - file->content_mod_date = bswabU32_inc(p); - file->attribute_mod_date = bswabU32_inc(p); - file->access_date = bswabU32_inc(p); - file->backup_date = bswabU32_inc(p); - p = record_readperm (p, &file->permissions); - p = record_readFInfo (p, &file->user_info); - p = record_readFXInfo (p, &file->finder_info); - file->text_encoding = bswabU32_inc(p); - file->reserved2 = bswabU32_inc(p); - p = volume_readfork (p, &file->data_fork); - return volume_readfork (p, &file->res_fork); -} - -/* read a hfsp_cat_thread from memory */ -static void* record_readthread(void *p, hfsp_cat_thread* entry) -{ - int i; - UInt16 len; - UInt16* cp; - - entry-> reserved = bswabU16_inc(p); - entry-> parentID = bswabU32_inc(p); - entry->nodeName.strlen = len= bswabU16_inc(p); - cp = entry->nodeName.name; - if (len > 255) - HFSP_ERROR(-1, "Invalid key length in record thread"); - for (i=0; i < len; i++, cp++) - *cp = bswabU16_inc(p); - return p; - fail: - return NULL; -} - -/* read a hfsp_cat_entry from memory */ -static void* record_readentry(void *p, hfsp_cat_entry* entry) -{ - UInt16 type = bswabU16_inc(p); - entry->type = type; - switch (type) - { - case HFSP_FOLDER: - return record_readfolder(p, &entry->u.folder); - case HFSP_FILE: - return record_readfile (p, &entry->u.file); - case HFSP_FOLDER_THREAD: - case HFSP_FILE_THREAD: - return record_readthread(p, &entry->u.thread); - default: - HFSP_ERROR(-1, "Unexpected record type in record_readentry"); - } ; - fail: - return NULL; -} - - -/* Most of the functions here will not change the node in the btree, - But this must be changed in the future ... */ - - -/* intialize the record with the given index entry in the btree. */ -static int record_init(record* r, btree* bt, node_buf* buf, UInt16 index) -{ - void *p; - r-> tree = bt; - p = btree_key_by_index(bt,buf,index); - if (!p) - return -1; - p = record_readkey (p, &r->key); - if (!p) - return -1; - p = record_readentry(p, &r->record); - if (!p) - return -1; - r->node_index = buf->index; - r-> keyind = index; - - return 0; -} - -/* intialize the record with the given index entry in the btree. */ -static int record_init_extent(extent_record* r, btree* bt, node_buf* buf, UInt16 index) -{ - void *p; - r-> tree = bt; - p = btree_key_by_index(bt, buf,index); - if (!p) - return -1; - p = record_extent_readkey(p, &r->key); - if (!p) - return -1; - p = volume_readextent(p, r->extent); - if (!p) - return -1; - r->node_index = buf->index; - r-> keyind = index; - - return 0; -} - -/* intialize the record to the first record of the tree - * which is (per design) the root node. - */ -int record_init_root(record* r, btree* tree) -{ - // Position to first leaf node ... - UInt32 leaf_head = tree->head.leaf_head; - node_buf* buf = btree_node_by_index(tree, leaf_head); - if (!buf) - return -1; - return record_init(r, tree, buf, 0); -} - -/* Compare two cat_keys ... */ -int record_key_compare(void* k1, void* k2) -{ - hfsp_cat_key* key1 = (hfsp_cat_key*) k1; - hfsp_cat_key* key2 = (hfsp_cat_key*) k2; - int diff = key2->parent_cnid - key1->parent_cnid; - if (!diff) // same parent - diff = fast_unicode_compare(&key1->name, &key2->name); - return diff; -} - -/* Compare two extent_keys ... */ -int record_extent_key_compare(void* k1, void* k2) -{ - hfsp_extent_key* key1 = (hfsp_extent_key*) k1; - hfsp_extent_key* key2 = (hfsp_extent_key*) k2; - int diff = key2->fork_type - key1->fork_type; - if (!diff) // same type - { - diff = key2->file_id - key1->file_id; - if (!diff) // same file - diff = key2->start_block - key1->start_block; - } - return diff; -} - -/* Position node in btree so that key might be inside */ -static node_buf* record_find_node(btree* tree, void *key) -{ - int start, end, mid, comp; // components of a binary search - void *p = NULL; - char curr_key[tree->head.max_key_len]; - // The current key under examination - hfsp_key_read readkey = tree->kread; - hfsp_key_compare key_compare = tree->kcomp; - UInt32 index; - node_buf* node = btree_node_by_index(tree, tree->head.root); - if (!node) - HFSP_ERROR(-1, "record_find_node: Cant position to root node"); - while (node->desc.kind == HFSP_NODE_NDX) - { - mid = start = 0; - end = node->desc.num_rec; - comp = -1; - while (start < end) - { - mid = (start + end) >> 1; - p = btree_key_by_index(tree, node, mid); - if (!p) - HFSP_ERROR(-1, "record_find_node: unexpected error"); - p = readkey (p, curr_key); - if (!p) - HFSP_ERROR(-1, "record_find_node: unexpected error"); - comp = key_compare(curr_key, key); - if (comp > 0) - start = mid + 1; - else if (comp < 0) - end = mid; - else - break; - } - if (!p) // Empty tree, fascinating ... - HFSP_ERROR(-1, "record_find_node: unexpected empty node"); - if (comp < 0) // mmh interesting key is before this key ... - { - if (mid == 0) - return NULL; // nothing before this key .. - p = btree_key_by_index(tree, node, mid-1); - if (!p) - HFSP_ERROR(-1, "record_find_node: unexpected error"); - p = readkey (p, curr_key); - if (!p) - HFSP_ERROR(-1, "record_find_node: unexpected error"); - } - - index = bswabU32_inc(p); - node = btree_node_by_index(tree, index); - } - return node; // go on and use the found node - fail: - return NULL; -} - -/* search for the given key in the btree. - * - * returns pointer to memory just after key or NULL - * In any case *keyind recives the index where the - * key was found (or could be inserted.) - */ -static void * -record_find_key(btree* tree, void* key, int* keyind, UInt16* node_index) -{ - node_buf* buf = record_find_node(tree, key); - if (buf) - { - int comp = -1; - int start = 0; // components of a binary search - int end = buf->desc.num_rec; - int mid = -1; - void *p = NULL; - char curr_key[tree->head.max_key_len]; - hfsp_key_read readkey = tree->kread; - hfsp_key_compare key_compare = tree->kcomp; - while (start < end) - { - mid = (start + end) >> 1; - p = btree_key_by_index(tree, buf, mid); - if (!p) - HFSP_ERROR(-1, "record_init_key: unexpected error"); - p = readkey (p, curr_key); - if (!p) - HFSP_ERROR(-1, "record_init_cat_key: unexpected error"); - comp = key_compare(curr_key, key); - if (comp > 0) - start = mid + 1; - else if (comp < 0) - end = mid; - else - break; - } - if (!p) // Empty tree, fascinating ... - HFSP_ERROR(ENOENT, "record_init_key: unexpected empty node"); - *keyind = mid; - *node_index = buf->index; - if (!comp) // found something ... - return p; - } - HFSP_ERROR(ENOENT, NULL); - fail: - return NULL; -} - -/* intialize the record by searching for the given key in the btree. - * - * r is umodified on error. - */ -static int -record_init_key(record* r, btree* tree, hfsp_cat_key* key) -{ - int keyind; - UInt16 node_index; - void *p = record_find_key(tree, key, &keyind, &node_index); - - if (p) - { - r -> tree = tree; - r -> node_index= node_index; - r -> keyind = keyind; - r -> key = *key; // Better use a record_key_copy ... - p = record_readentry(p, &r->record); - if (!p) - HFSP_ERROR(-1, "record_init_key: unexpected error"); - return 0; - } - fail: - return -1; -} - -/* intialize the extent_record to the extent identified by the - * (first) blockindex. - * - * forktype: either HFSP_EXTEND_DATA or HFSP_EXTEND_RSRC - */ -int record_init_file(extent_record* r, btree* tree, - UInt8 forktype, UInt32 fileId, UInt32 blockindex) -{ - int keyind; - UInt16 node_index; - hfsp_extent_key key = { 10, forktype, 0, fileId, blockindex }; - void *p = record_find_key(tree, &key, &keyind, &node_index); - - if (p) - { - r -> tree = tree; - r -> node_index= node_index; - r -> keyind = keyind; - r -> key = key; // Better use a record_key_copy ... - p = volume_readextent(p, r->extent); - if (!p) - HFSP_ERROR(-1, "record_init_file: unexpected error"); - return 0; - } - fail: - return -1; -} - -/* intialize the record to the folder identified by cnid - */ -int record_init_cnid(record* r, btree* tree, UInt32 cnid) -{ - hfsp_cat_key thread_key; // the thread is the first record - - thread_key.key_length = 6; // null name (like '.' in unix ) - thread_key.parent_cnid = cnid; - thread_key.name.strlen = 0; - - return record_init_key(r, tree, &thread_key); -} - -/* intialize the record to the first record of the parent. - */ -int record_init_parent(record* r, record* parent) -{ - if (parent->record.type == HFSP_FOLDER) - return record_init_cnid(r, parent->tree, parent->record.u.folder.id); - else if(parent->record.type == HFSP_FOLDER_THREAD) - { - if (r != parent) - *r = *parent; // The folder thread is in fact the first entry, like '.' - return 0; - } - HFSP_ERROR(EINVAL, - "record_init_parent: parent is neither folder nor folder thread."); - - fail: - return EINVAL; -} - - -/* find correct node record for given node and *pindex. - * - * index of record in this (or next) node - * */ -static node_buf* prepare_next(btree* tree, UInt16 node_index, UInt16* pindex) -{ - node_buf* buf = btree_node_by_index(tree, node_index); - btree_node_desc* desc = &buf->desc; - UInt32 numrec = desc->num_rec; - if (*pindex >= numrec) // move on to next node - { - UInt16 next = desc->next; - *pindex = 0; - if (!next /* is there a next node ? */ - || !( buf = btree_node_by_index(tree, next))) - return NULL; - } - return buf; -} -/* move record foreward to next entry. - * - * In case of an error the value of *r is undefined ! - */ -int record_next(record* r) -{ - btree* tree = r->tree; - UInt16 index = r->keyind +1; - UInt32 parent; - node_buf* buf = prepare_next(tree, r->node_index, &index); - - if (!buf) - return ENOENT; // No (more) such file or directory - - parent = r->key.parent_cnid; - - if (record_init(r, tree, buf, index)) - return -1; - - if (r->key.parent_cnid != parent || // end of current directory - index != r->keyind) // internal error ? - return ENOENT; // No (more) such file or directory - - return 0; -} - -/* move record foreward to next extent record. - * - * In case of an error the value of *r is undefined ! - */ -int record_next_extent(extent_record* r) -{ - btree* tree = r->tree; - UInt16 index = r->keyind +1; - UInt32 file_id; - UInt8 fork_type; - node_buf* buf = prepare_next(tree, r->node_index, &index); - - if (!buf) - return ENOENT; // No (more) such file or directory - - file_id = r->key.file_id; - fork_type = r->key.fork_type; - - if (record_init_extent(r, tree, buf, index)) - return -1; - - if (r->key.file_id != file_id || // end of current file - r->key.fork_type != fork_type || // end of current fork - index != r->keyind) // internal error ? - return ENOENT; // No (more) such file or directory - - return 0; -} - -/* intialize the record by searching for the given string in the given folder. - * - * parent and r may be the same. - */ -int record_init_string_parent(record* r, record* parent, char* name) -{ - hfsp_cat_key key; - - if (parent->record.type == HFSP_FOLDER) - key.parent_cnid = parent->record.u.folder.id; - else if(parent->record.type == HFSP_FOLDER_THREAD) - key.parent_cnid = parent->key.parent_cnid; - else - HFSP_ERROR(-1, "record_init_string_parent: parent is not a folder."); - - key.key_length = 6 + unicode_asc2uni(&key.name,name); // 6 for minumum size - return record_init_key(r, parent->tree, &key); - - fail: - return -1; -} - -/* move record up in folder hierarchy (if possible) */ -int record_up(record* r) -{ - if (r->record.type == HFSP_FOLDER) - { - // locate folder thread - if (record_init_cnid(r, r->tree, r->record.u.folder.id)) - return -1; - } - else if(r->record.type == HFSP_FOLDER_THREAD) - { - // do nothing were are already where we want to be - } - else - HFSP_ERROR(-1, "record_up: record is neither folder nor folder thread."); - - if(r->record.type != HFSP_FOLDER_THREAD) - HFSP_ERROR(-1, "record_up: unable to locate parent"); - return record_init_cnid(r, r->tree, r->record.u.thread.parentID); - - fail: - return -1; -} - -#ifdef DEBUG - -/* print Quickdraw Point */ -static void record_print_Point(Point* p) -{ - printf("[ v=%d, h=%d ]", p->v, p->h); -} - -/* print Quickdraw Rect */ -static void record_print_Rect(Rect* r) -{ - printf("[ top=%d, left=%d, bottom=%d, right=%d ]", - r->top, r->left, r->bottom, r->right); -} - -/* print the key of a record */ -static void record_print_key(hfsp_cat_key* key) -{ - char buf[255]; // mh this _might_ overflow - unicode_uni2asc(buf, &key->name, 255); - printf("parent cnid : %ld\n", key->parent_cnid); - printf("name : %s\n", buf); -} - -/* print permissions */ -static void record_print_perm(hfsp_perm* perm) -{ - printf("owner :\t%ld\n", perm->owner); - printf("group :\t%ld\n", perm->group); - printf("perm :\t0x%lX\n",perm->mode); - printf("dev :\t%ld\n", perm->dev); -} - -/* print Directory info */ -static void record_print_DInfo(DInfo* dinfo) -{ - printf( "frRect :\t"); record_print_Rect(&dinfo->frRect); - printf("\nfrFlags :\t0X%X\n", dinfo->frFlags); - printf( "frLocation :\t"); record_print_Point(&dinfo->frLocation); - printf("\nfrView :\t0X%X\n", dinfo->frView); -} - -/* print extended Directory info */ -static void record_print_DXInfo(DXInfo* xinfo) -{ - printf( "frScroll :\t"); record_print_Point(&xinfo->frScroll); - printf("\nfrOpenChain :\t%ld\n", xinfo->frOpenChain); - printf( "frUnused :\t%d\n", xinfo->frUnused); - printf( "frComment :\t%d\n", xinfo->frComment); - printf( "frPutAway :\t%ld\n", xinfo->frPutAway); -} - -static void record_print_folder(hfsp_cat_folder* folder) -{ - printf("flags :\t0x%X\n", folder->flags); - printf("valence :\t0x%lX\n", folder->valence); - printf("id :\t%ld\n", folder->id); - record_print_perm (&folder->permissions); - record_print_DInfo (&folder->user_info); - record_print_DXInfo (&folder->finder_info); - printf("text_encoding :\t0x%lX\n", folder->text_encoding); - printf("reserved :\t0x%lX\n", folder->reserved); -} - -/* print File info */ -static void record_print_FInfo(FInfo* finfo) -{ - printf( "fdType :\t%4.4s\n", (char*) &finfo->fdType); - printf( "fdCreator :\t%4.4s\n", (char*) &finfo->fdCreator); - printf( "fdFlags :\t0X%X\n", finfo->fdFlags); - printf( "fdLocation :\t"); record_print_Point(&finfo->fdLocation); - printf("\nfdFldr :\t%d\n", finfo->fdFldr); -} - -/* print extended File info */ -static void record_print_FXInfo(FXInfo* xinfo) -{ - printf( "fdIconID :\t%d\n", xinfo->fdIconID); - // xinfo -> fdUnused; - printf( "fdComment :\t%d\n", xinfo->fdComment); - printf( "fdPutAway :\t%ld\n", xinfo->fdPutAway); -} - -/* print folder entry */ - -/* print file entry */ -static void record_print_file(hfsp_cat_file* file) -{ - printf("flags :\t0x%X\n", file->flags); - printf("reserved1 :\t0x%lX\n", file->reserved1); - printf("id :\t%ld\n", file->id); - record_print_perm (&file->permissions); - record_print_FInfo (&file->user_info); - record_print_FXInfo (&file->finder_info); - printf("text_encoding :\t0x%lX\n", file->text_encoding); - printf("reserved :\t0x%lX\n", file->reserved2); - printf("Datafork:\n"); - volume_print_fork (&file->data_fork); - printf("Rsrcfork:\n"); - volume_print_fork (&file->res_fork); -} - -/* print info for a file or folder thread */ -static void record_print_thread(hfsp_cat_thread* entry) -{ - char buf[255]; // mh this _might_ overflow - unicode_uni2asc(buf, &entry->nodeName, 255); - printf("parent cnid :\t%ld\n", entry->parentID); - printf("name :\t%s\n" , buf); -} - -/* print the information for a record */ -static void record_print_entry(hfsp_cat_entry* entry) -{ - switch (entry->type) - { - case HFSP_FOLDER: - printf("=== Folder ===\n"); - return record_print_folder(&entry->u.folder); - case HFSP_FILE: - printf("=== File ===\n"); - return record_print_file (&entry->u.file); - case HFSP_FOLDER_THREAD: - printf("=== Folder Thread ===\n"); - return record_print_thread(&entry->u.thread); - case HFSP_FILE_THREAD: - printf("=== File Thread ==\n"); - return record_print_thread(&entry->u.thread); - default: - printf("=== Unknown Record Type ===\n"); - } ; -} - - /* Dump all the record information to stdout */ -void record_print(record* r) -{ - printf ("keyind : %u\n", r->keyind); - record_print_key (&r->key); - record_print_entry(&r->record); -} - -#endif diff --git a/fs/hfsplus/volume.c b/fs/hfsplus/volume.c deleted file mode 100644 index 40b3eac..0000000 --- a/fs/hfsplus/volume.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * libhfs - library for reading and writing Macintosh HFS volumes - * - * Code to acces the basic volume information of a HFS+ volume. - * - * Copyright (C) 2000 Klaus Halfmann khalfmann@libra.de - * Original work by 1996-1998 Robert Leslie rob@mars.org - * other work 2000 from Brad Boyer (flar@pants.nu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - * MA 02110-1301, USA. - * - * $Id: volume.c,v 1.21 2000/10/25 05:43:04 hasi Exp $ - */ - -#include "config.h" -#include "libhfsp.h" -#include "volume.h" -#include "record.h" -#include "btree.h" -#include "blockiter.h" -#include "os.h" -#include "swab.h" -#include "hfstime.h" - - -/* Fill a given buffer with the given block in volume. - */ -int -volume_readinbuf(volume * vol,void* buf, long block) -{ - UInt16 blksize_bits; - ASSERT( block < vol->maxblocks); - - blksize_bits = vol->blksize_bits; - block += vol->startblock; - if( os_seek(vol->os_fd, block, blksize_bits) == block) - if( 1 == os_read(vol->os_fd, buf, 1, blksize_bits)) - return 0; - return -1; -} - -/* read multiple blocks into given memory. - * - * returns given pinter or NULL on failure. - */ -void* -volume_readfromfork(volume* vol, void* buf, - hfsp_fork_raw* f, UInt32 block, - UInt32 count, UInt8 forktype, UInt32 fileId) -{ - blockiter iter; - char *cbuf = buf; - - blockiter_init(&iter, vol, f, forktype, fileId); - if( blockiter_skip(&iter, block)) - return NULL; - - while( count > 0) { - --count; - if( volume_readinbuf(vol, cbuf, blockiter_curr(&iter))) - return NULL; - cbuf += vol->blksize; - if( count > 0 && blockiter_next(&iter)) - return NULL; - } - return buf; -} - - -/* Read a raw hfsp_extent_rec from memory. - * - * return pointer right after the structure. - */ -void* -volume_readextent(void *p, hfsp_extent_rec er) -{ - int i; - hfsp_extent *e; - - for( i=0; i < 8; i++) { - e = &er[i]; - e->start_block = bswabU32_inc(p); - e->block_count = bswabU32_inc(p); - } - return p; -} - -/* Read a raw hfsp_fork from memory. - * - * return pointer right after the structure. - */ -void* -volume_readfork(void *p, hfsp_fork_raw* f) -{ - f->total_size = bswabU64_inc(p); - f->clump_size = bswabU32_inc(p); - f->total_blocks = bswabU32_inc(p); - - return volume_readextent(p, f->extents); -} - -/* Read the volume from the given buffer and swap the bytes. - * - * ToDo: add more consitency checks. - */ -static int -volume_readbuf(hfsp_vh* vh, char * p) -{ - if( (vh->signature = bswabU16_inc(p)) != HFSP_VOLHEAD_SIG) - HFSP_ERROR(-1, "This is not a HFS+ volume"); - - vh->version = bswabU16_inc(p); - vh->attributes = bswabU32_inc(p); - vh->last_mount_vers = bswabU32_inc(p); - vh->reserved = bswabU32_inc(p); - vh->create_date = bswabU32_inc(p); - vh->modify_date = bswabU32_inc(p); - vh->backup_date = bswabU32_inc(p); - vh->checked_date = bswabU32_inc(p); - vh->file_count = bswabU32_inc(p); - vh->folder_count = bswabU32_inc(p); - vh->blocksize = bswabU32_inc(p); - vh->total_blocks = bswabU32_inc(p); - vh->free_blocks = bswabU32_inc(p); - vh->next_alloc = bswabU32_inc(p); - vh->rsrc_clump_sz = bswabU32_inc(p); - vh->data_clump_sz = bswabU32_inc(p); - vh->next_cnid = bswabU32_inc(p); - vh->write_count = bswabU32_inc(p); - vh->encodings_bmp = bswabU64_inc(p); - memcpy(vh->finder_info, p, 32); - p += 32; // So finderinfo must be swapped later, *** - p = volume_readfork(p, &vh->alloc_file ); - p = volume_readfork(p, &vh->ext_file ); - p = volume_readfork(p, &vh->cat_file ); - p = volume_readfork(p, &vh->attr_file ); - volume_readfork(p, &vh->start_file ); - return 0; - fail: - return -1; -} - -/* Read the volume from the given block */ -static int -volume_read(volume * vol, hfsp_vh* vh, UInt32 block) -{ - char buf[vol->blksize]; - - if( volume_readinbuf(vol, buf, block)) - return -1; - return volume_readbuf(vh, buf); -} - -/* Find out wether the volume is wrapped and unwrap it eventually */ -static int -volume_read_wrapper(volume * vol, hfsp_vh* vh) -{ - UInt16 signature; - char buf[vol->blksize]; - char *p = buf; - - if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here - return -1; - - signature = bswabU16_inc(p); - if( signature == HFS_VOLHEAD_SIG) { /* Wrapper */ - UInt32 drAlBlkSiz; /* size (in bytes) of allocation blocks */ - UInt32 sect_per_block; /* how may block build an hfs sector */ - UInt16 drAlBlSt; /* first allocation block in volume */ - UInt16 embeds, embedl; /* Start/lenght of embedded area in blocks */ - - p += 0x12; /* skip unneded HFS vol fields */ - drAlBlkSiz = bswabU32_inc(p); /* offset 0x14 */ - p += 0x4; /* skip unneded HFS vol fields */ - drAlBlSt = bswabU16_inc(p); /* offset 0x1C */ - - p += 0x5E; /* skip unneded HFS vol fields */ - signature = bswabU16_inc(p); /* offset 0x7C, drEmbedSigWord */ - if( signature != HFSP_VOLHEAD_SIG) - HFSP_ERROR(-1, "This looks like a normal HFS volume"); - embeds = bswabU16_inc(p); - embedl = bswabU16_inc(p); - sect_per_block = (drAlBlkSiz / HFSP_BLOCKSZ); - // end is absolute (not relative to HFS+ start) - vol->maxblocks = embedl * sect_per_block; - vol->startblock = drAlBlSt + embeds * sect_per_block; - /* Now we can try to read the embedded HFS+ volume header */ - return volume_read(vol,vh,2); - } - else if( signature == HFSP_VOLHEAD_SIG) { /* Native HFS+ volume */ - p = buf; // Restore to begin of block - return volume_readbuf(vh, p); - } else - HFSP_ERROR(-1, "Neither Wrapper nor native HFS+ volume header found"); -fail: - return -1; -} - - -/* Open the device, read and verify the volume header - (and its backup) */ -int -volume_open( volume* vol, int os_fd ) -{ - hfsp_vh backup; /* backup volume found at second to last block */ - long sect_per_block; - int shift; - - vol->blksize_bits = HFSP_BLOCKSZ_BITS; - vol->blksize = HFSP_BLOCKSZ; - vol->startblock = 0; - vol->maxblocks = 3; - /* this should be enough until we find the volume descriptor */ - vol->extents = NULL; /* Thanks to Jeremias Sauceda */ - - btree_reset(&vol->catalog); - vol->os_fd = os_fd; - - // vol->maxblocks = os_seek(vol->os_fd, -1, HFSP_BLOCKSZ_BITS); - // This wont work for /dev/... but we do not really need it - - if( volume_read_wrapper(vol, &vol->vol)) - return -1; - if( volume_read(vol, &backup, vol->maxblocks - 2)) - return -1; - - /* Now switch blksize from HFSP_BLOCKSZ (512) to value given in header - and adjust depend values accordingly, after that a block always - means a HFS+ allocation size */ - - /* Usually 4096 / 512 == 8 */ - sect_per_block = vol->vol.blocksize / HFSP_BLOCKSZ; - shift = 0; - if( sect_per_block > 1) { - shift = 1; - while( sect_per_block > 2) { - sect_per_block >>=1; - shift++; - } /* shift = 3 */ - } - vol -> blksize_bits += shift; - vol -> blksize = 1 << vol->blksize_bits; - vol -> startblock >>= shift; - vol -> maxblocks = vol->vol.total_blocks; /* cant calculate via shift ? */ - - if( btree_init_cat(&vol->catalog, vol, &vol->vol.cat_file)) - return -1; - - return 0; -} - -/* Write back all data eventually cached and close the device */ -int -volume_close(volume* vol) -{ - btree_close(&vol->catalog); - if( vol->extents) { - btree_close(vol->extents); - FREE(vol->extents); - } - return 0; -} - -/* internal fucntion used to create the extents btree, - is called by inline function when needed */ -void -volume_create_extents_tree(volume* vol) -{ - btree* result = (btree*) ALLOC(btree*, sizeof(btree)); - if( !result) - HFSP_ERROR(ENOMEM, "No memory for extents btree"); - if( !btree_init_extent(result, vol, &vol->vol.ext_file)) { - vol->extents = result; - return; - } - fail: - vol->extents = NULL; -} - -/* Determine whether the volume is a HFS-plus volume */ -int -volume_probe(int fd, long long offset) -{ - UInt16 *vol; - int ret = 0; - - vol = (UInt16 *)malloc(2 * 1 << HFSP_BLOCKSZ_BITS); - os_seek_offset( fd, 2 * (1 << HFSP_BLOCKSZ_BITS) + offset ); - os_read(fd, vol, 2, HFSP_BLOCKSZ_BITS); - - if (__be16_to_cpu(vol[0]) == HFS_VOLHEAD_SIG && - __be16_to_cpu(vol[0x7c]) == HFSP_VOLHEAD_SIG) { - ret = -1; - } else if (__be16_to_cpu(vol[0]) == HFSP_VOLHEAD_SIG) { - ret = -1; - } - - free(vol); - return ret; -} -