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; -} -
Files in fs/hfs and fs/hfsplus have same names, this causes problems during linkage.
That sounds like a bug in the build system. Can you fix that instead? That would actually fix it, your patch is just an ugly band-aid :-(
Segher
Am 18.11.2010 um 00:05 schrieb Segher Boessenkool:
Files in fs/hfs and fs/hfsplus have same names, this causes problems during linkage.
That sounds like a bug in the build system. Can you fix that instead? That would actually fix it, your patch is just an ugly band-aid :-(
As investigated previously, the problem occurs when the libfs.a library already exists and one of its source files changes. It seems like `ar' tries to do an incremental update of object files and gets confused about the identically named files within the archive, symptoms are missing (or duplicate?) symbols.
The reason I didn't rename the sources when I encountered the issue was that it seemed those files were imported from some external source; renaming them would make updating them harder. Someone suggested that configuring OpenBIOS in such a way that both are compiled in might be unnecessary.
Andreas
Files in fs/hfs and fs/hfsplus have same names, this causes problems during linkage.
That sounds like a bug in the build system. Can you fix that instead? That would actually fix it, your patch is just an ugly band-aid :-(
As investigated previously, the problem occurs when the libfs.a library already exists and one of its source files changes. It seems like `ar' tries to do an incremental update of object files and gets confused about the identically named files within the archive, symptoms are missing (or duplicate?) symbols.
Sounds to me like the real problem is with how ar is used, then? Can you show the ar commands that fail?
Segher
Sounds to me like the real problem is with how ar is used, then? Can you show the ar commands that fail?
Oh I see now. ar doesn't store pathname.
If you can require a new enough binutils (2.19 or newer), you could use "thin archives", which don't have this limitation, and have some more advantages. See the -T option to ar (ar rcsT bla.a ...)
Another option is to have an archive file per directory.
Segher
On Fri, Nov 19, 2010 at 2:15 AM, Segher Boessenkool segher@kernel.crashing.org wrote:
Sounds to me like the real problem is with how ar is used, then? Can you show the ar commands that fail?
Oh I see now. ar doesn't store pathname.
If you can require a new enough binutils (2.19 or newer), you could use "thin archives", which don't have this limitation, and have some more advantages. See the -T option to ar (ar rcsT bla.a ...)
Another option is to have an archive file per directory.
The object files could be renamed before archiving, or GCC -o target could be different from what simple %o: %.c substitution rule would generate.
But googling for the project finds very few references, most of them are OpenBIOS. This seems to be the source: http://ftp.penguinppc.org/users/hasi/ It's stale, but I found it here: http://www.koders.com/info.aspx?c=ProjectInfo&pid=XDR5GKGZPX43N13RGPC3DV... in the project hfsplusutils. Linux fs/hfsplus seems to be very different.
So I think renaming would be the easiest solution, in the unlikely event that hfsplusutils project revives we can still pretty easily refresh.
Am 21.11.2010 um 13:33 schrieb Blue Swirl:
On Fri, Nov 19, 2010 at 2:15 AM, Segher Boessenkool segher@kernel.crashing.org wrote:
Sounds to me like the real problem is with how ar is used, then? Can you show the ar commands that fail?
Oh I see now. ar doesn't store pathname.
If you can require a new enough binutils (2.19 or newer), you could use "thin archives", which don't have this limitation, and have some more advantages. See the -T option to ar (ar rcsT bla.a ...)
Another option is to have an archive file per directory.
The object files could be renamed before archiving, or GCC -o target could be different from what simple %o: %.c substitution rule would generate.
But googling for the project finds very few references, most of them are OpenBIOS. This seems to be the source: http://ftp.penguinppc.org/users/hasi/ It's stale, but I found it here: http://www.koders.com/info.aspx?c=ProjectInfo&pid=XDR5GKGZPX43N13RGPC3DV... in the project hfsplusutils. Linux fs/hfsplus seems to be very different.
So I think renaming would be the easiest solution, in the unlikely event that hfsplusutils project revives we can still pretty easily refresh.
Agreed.
The patch once again is line-wrapped [1] unfortunately. It would be nice if you could push such patches to your http://repo.or.cz/w/openbios.git repository (or wherever) for testing.
Andreas
[1] http://www.openfirmware.info/pipermail/openbios/2010-November/005823.html
On Sun, Nov 21, 2010 at 1:52 PM, Andreas Färber andreas.faerber@web.de wrote:
Am 21.11.2010 um 13:33 schrieb Blue Swirl:
On Fri, Nov 19, 2010 at 2:15 AM, Segher Boessenkool segher@kernel.crashing.org wrote:
Sounds to me like the real problem is with how ar is used, then? Can you show the ar commands that fail?
Oh I see now. ar doesn't store pathname.
If you can require a new enough binutils (2.19 or newer), you could use "thin archives", which don't have this limitation, and have some more advantages. See the -T option to ar (ar rcsT bla.a ...)
Another option is to have an archive file per directory.
The object files could be renamed before archiving, or GCC -o target could be different from what simple %o: %.c substitution rule would generate.
But googling for the project finds very few references, most of them are OpenBIOS. This seems to be the source: http://ftp.penguinppc.org/users/hasi/ It's stale, but I found it here:
http://www.koders.com/info.aspx?c=ProjectInfo&pid=XDR5GKGZPX43N13RGPC3DV... in the project hfsplusutils. Linux fs/hfsplus seems to be very different.
So I think renaming would be the easiest solution, in the unlikely event that hfsplusutils project revives we can still pretty easily refresh.
Agreed.
The patch once again is line-wrapped [1] unfortunately. It would be nice if you could push such patches to your http://repo.or.cz/w/openbios.git repository (or wherever) for testing.
Pushed, please test.
Am 28.11.2010 um 15:50 schrieb Blue Swirl:
On Sun, Nov 21, 2010 at 1:52 PM, Andreas Färber <andreas.faerber@web.de
wrote: Am 21.11.2010 um 13:33 schrieb Blue Swirl:
On Fri, Nov 19, 2010 at 2:15 AM, Segher Boessenkool segher@kernel.crashing.org wrote:
Sounds to me like the real problem is with how ar is used, then? Can you show the ar commands that fail?
Oh I see now. ar doesn't store pathname.
If you can require a new enough binutils (2.19 or newer), you could use "thin archives", which don't have this limitation, and have some more advantages. See the -T option to ar (ar rcsT bla.a ...)
Another option is to have an archive file per directory.
The object files could be renamed before archiving, or GCC -o target could be different from what simple %o: %.c substitution rule would generate.
But googling for the project finds very few references, most of them are OpenBIOS. This seems to be the source: http://ftp.penguinppc.org/users/hasi/ It's stale, but I found it here:
http://www.koders.com/info.aspx?c=ProjectInfo&pid=XDR5GKGZPX43N13RGPC3DV... in the project hfsplusutils. Linux fs/hfsplus seems to be very different.
So I think renaming would be the easiest solution, in the unlikely event that hfsplusutils project revives we can still pretty easily refresh.
Agreed.
The patch once again is line-wrapped [1] unfortunately. It would be nice if you could push such patches to your http://repo.or.cz/w/openbios.git repository (or wherever) for testing.
Pushed, please test.
Thanks, works for me. The slight dissimilarity with the original files stems from whitespace changes.
Acked-by: Andreas Färber andreas.faerber@web.de
I would suggest to rename unicode.c and blockiter.c, too, though. Might bite in the future.
Andreas
On Sun, Nov 28, 2010 at 5:16 PM, Andreas Färber andreas.faerber@web.de wrote:
Am 28.11.2010 um 15:50 schrieb Blue Swirl:
On Sun, Nov 21, 2010 at 1:52 PM, Andreas Färber andreas.faerber@web.de wrote:
Am 21.11.2010 um 13:33 schrieb Blue Swirl:
On Fri, Nov 19, 2010 at 2:15 AM, Segher Boessenkool segher@kernel.crashing.org wrote:
Sounds to me like the real problem is with how ar is used, then? Can you show the ar commands that fail?
Oh I see now. ar doesn't store pathname.
If you can require a new enough binutils (2.19 or newer), you could use "thin archives", which don't have this limitation, and have some more advantages. See the -T option to ar (ar rcsT bla.a ...)
Another option is to have an archive file per directory.
The object files could be renamed before archiving, or GCC -o target could be different from what simple %o: %.c substitution rule would generate.
But googling for the project finds very few references, most of them are OpenBIOS. This seems to be the source: http://ftp.penguinppc.org/users/hasi/ It's stale, but I found it here:
http://www.koders.com/info.aspx?c=ProjectInfo&pid=XDR5GKGZPX43N13RGPC3DV... in the project hfsplusutils. Linux fs/hfsplus seems to be very different.
So I think renaming would be the easiest solution, in the unlikely event that hfsplusutils project revives we can still pretty easily refresh.
Agreed.
The patch once again is line-wrapped [1] unfortunately. It would be nice if you could push such patches to your http://repo.or.cz/w/openbios.git repository (or wherever) for testing.
Pushed, please test.
Thanks, works for me. The slight dissimilarity with the original files stems from whitespace changes.
Probably because I have [apply] whitespace = fix in $HOME/.gitconfig
Acked-by: Andreas Färber andreas.faerber@web.de
Thanks.
I would suggest to rename unicode.c and blockiter.c, too, though. Might bite in the future.
True. I updated and pushed.