|
|
1.1 ! root 1: /* ! 2: * libhfs - library for reading and writing Macintosh HFS volumes ! 3: * ! 4: * Code to acces the basic volume information of a HFS+ volume. ! 5: * ! 6: * Copyright (C) 2000 Klaus Halfmann <[email protected]> ! 7: * Original work by 1996-1998 Robert Leslie <[email protected]> ! 8: * other work 2000 from Brad Boyer ([email protected]) ! 9: * ! 10: * This program is free software; you can redistribute it and/or modify ! 11: * it under the terms of the GNU General Public License as published by ! 12: * the Free Software Foundation; either version 2 of the License, or ! 13: * (at your option) any later version. ! 14: * ! 15: * This program is distributed in the hope that it will be useful, ! 16: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 17: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 18: * GNU General Public License for more details. ! 19: * ! 20: * You should have received a copy of the GNU General Public License ! 21: * along with this program; if not, write to the Free Software ! 22: * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, ! 23: * MA 02110-1301, USA. ! 24: * ! 25: * $Id: volume.c,v 1.21 2000/10/25 05:43:04 hasi Exp $ ! 26: */ ! 27: ! 28: #include "config.h" ! 29: #include "libhfsp.h" ! 30: #include "volume.h" ! 31: #include "record.h" ! 32: #include "btree.h" ! 33: #include "blockiter.h" ! 34: #include "os.h" ! 35: #include "swab.h" ! 36: #include "hfstime.h" ! 37: ! 38: ! 39: /* Fill a given buffer with the given block in volume. ! 40: */ ! 41: int ! 42: volume_readinbuf(volume * vol,void* buf, long block) ! 43: { ! 44: UInt16 blksize_bits; ! 45: ASSERT( block < vol->maxblocks); ! 46: ! 47: blksize_bits = vol->blksize_bits; ! 48: block += vol->startblock; ! 49: if( os_seek(vol->os_fd, block, blksize_bits) == block) ! 50: if( 1 == os_read(vol->os_fd, buf, 1, blksize_bits)) ! 51: return 0; ! 52: return -1; ! 53: } ! 54: ! 55: /* read multiple blocks into given memory. ! 56: * ! 57: * returns given pinter or NULL on failure. ! 58: */ ! 59: void* ! 60: volume_readfromfork(volume* vol, void* buf, ! 61: hfsp_fork_raw* f, UInt32 block, ! 62: UInt32 count, UInt8 forktype, UInt32 fileId) ! 63: { ! 64: blockiter iter; ! 65: char *cbuf = buf; ! 66: ! 67: blockiter_init(&iter, vol, f, forktype, fileId); ! 68: if( blockiter_skip(&iter, block)) ! 69: return NULL; ! 70: ! 71: while( count > 0) { ! 72: --count; ! 73: if( volume_readinbuf(vol, cbuf, blockiter_curr(&iter))) ! 74: return NULL; ! 75: cbuf += vol->blksize; ! 76: if( count > 0 && blockiter_next(&iter)) ! 77: return NULL; ! 78: } ! 79: return buf; ! 80: } ! 81: ! 82: ! 83: /* Read a raw hfsp_extent_rec from memory. ! 84: * ! 85: * return pointer right after the structure. ! 86: */ ! 87: void* ! 88: volume_readextent(void *p, hfsp_extent_rec er) ! 89: { ! 90: int i; ! 91: hfsp_extent *e; ! 92: ! 93: for( i=0; i < 8; i++) { ! 94: e = &er[i]; ! 95: e->start_block = bswabU32_inc(p); ! 96: e->block_count = bswabU32_inc(p); ! 97: } ! 98: return p; ! 99: } ! 100: ! 101: /* Read a raw hfsp_fork from memory. ! 102: * ! 103: * return pointer right after the structure. ! 104: */ ! 105: void* ! 106: volume_readfork(void *p, hfsp_fork_raw* f) ! 107: { ! 108: f->total_size = bswabU64_inc(p); ! 109: f->clump_size = bswabU32_inc(p); ! 110: f->total_blocks = bswabU32_inc(p); ! 111: ! 112: return volume_readextent(p, f->extents); ! 113: } ! 114: ! 115: /* Read the volume from the given buffer and swap the bytes. ! 116: * ! 117: * ToDo: add more consitency checks. ! 118: */ ! 119: static int ! 120: volume_readbuf(hfsp_vh* vh, char * p) ! 121: { ! 122: if( (vh->signature = bswabU16_inc(p)) != HFSP_VOLHEAD_SIG) ! 123: HFSP_ERROR(-1, "This is not a HFS+ volume"); ! 124: ! 125: vh->version = bswabU16_inc(p); ! 126: vh->attributes = bswabU32_inc(p); ! 127: vh->last_mount_vers = bswabU32_inc(p); ! 128: vh->reserved = bswabU32_inc(p); ! 129: vh->create_date = bswabU32_inc(p); ! 130: vh->modify_date = bswabU32_inc(p); ! 131: vh->backup_date = bswabU32_inc(p); ! 132: vh->checked_date = bswabU32_inc(p); ! 133: vh->file_count = bswabU32_inc(p); ! 134: vh->folder_count = bswabU32_inc(p); ! 135: vh->blocksize = bswabU32_inc(p); ! 136: vh->total_blocks = bswabU32_inc(p); ! 137: vh->free_blocks = bswabU32_inc(p); ! 138: vh->next_alloc = bswabU32_inc(p); ! 139: vh->rsrc_clump_sz = bswabU32_inc(p); ! 140: vh->data_clump_sz = bswabU32_inc(p); ! 141: vh->next_cnid = bswabU32_inc(p); ! 142: vh->write_count = bswabU32_inc(p); ! 143: vh->encodings_bmp = bswabU64_inc(p); ! 144: memcpy(vh->finder_info, p, 32); ! 145: p += 32; // So finderinfo must be swapped later, *** ! 146: p = volume_readfork(p, &vh->alloc_file ); ! 147: p = volume_readfork(p, &vh->ext_file ); ! 148: p = volume_readfork(p, &vh->cat_file ); ! 149: p = volume_readfork(p, &vh->attr_file ); ! 150: volume_readfork(p, &vh->start_file ); ! 151: return 0; ! 152: fail: ! 153: return -1; ! 154: } ! 155: ! 156: /* Read the volume from the given block */ ! 157: static int ! 158: volume_read(volume * vol, hfsp_vh* vh, UInt32 block) ! 159: { ! 160: char buf[vol->blksize]; ! 161: ! 162: if( volume_readinbuf(vol, buf, block)) ! 163: return -1; ! 164: return volume_readbuf(vh, buf); ! 165: } ! 166: ! 167: /* Find out wether the volume is wrapped and unwrap it eventually */ ! 168: static int ! 169: volume_read_wrapper(volume * vol, hfsp_vh* vh) ! 170: { ! 171: UInt16 signature; ! 172: char buf[vol->blksize]; ! 173: char *p = buf; ! 174: ! 175: if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here ! 176: return -1; ! 177: ! 178: signature = bswabU16_inc(p); ! 179: if( signature == HFS_VOLHEAD_SIG) { /* Wrapper */ ! 180: UInt32 drAlBlkSiz; /* size (in bytes) of allocation blocks */ ! 181: UInt32 sect_per_block; /* how may block build an hfs sector */ ! 182: UInt16 drAlBlSt; /* first allocation block in volume */ ! 183: UInt16 embeds, embedl; /* Start/lenght of embedded area in blocks */ ! 184: ! 185: p += 0x12; /* skip unneded HFS vol fields */ ! 186: drAlBlkSiz = bswabU32_inc(p); /* offset 0x14 */ ! 187: p += 0x4; /* skip unneded HFS vol fields */ ! 188: drAlBlSt = bswabU16_inc(p); /* offset 0x1C */ ! 189: ! 190: p += 0x5E; /* skip unneded HFS vol fields */ ! 191: signature = bswabU16_inc(p); /* offset 0x7C, drEmbedSigWord */ ! 192: if( signature != HFSP_VOLHEAD_SIG) ! 193: HFSP_ERROR(-1, "This looks like a normal HFS volume"); ! 194: embeds = bswabU16_inc(p); ! 195: embedl = bswabU16_inc(p); ! 196: sect_per_block = (drAlBlkSiz / HFSP_BLOCKSZ); ! 197: // end is absolute (not relative to HFS+ start) ! 198: vol->maxblocks = embedl * sect_per_block; ! 199: vol->startblock = drAlBlSt + embeds * sect_per_block; ! 200: /* Now we can try to read the embedded HFS+ volume header */ ! 201: return volume_read(vol,vh,2); ! 202: } ! 203: else if( signature == HFSP_VOLHEAD_SIG) { /* Native HFS+ volume */ ! 204: p = buf; // Restore to begin of block ! 205: return volume_readbuf(vh, p); ! 206: } else ! 207: HFSP_ERROR(-1, "Neither Wrapper nor native HFS+ volume header found"); ! 208: fail: ! 209: return -1; ! 210: } ! 211: ! 212: ! 213: /* Open the device, read and verify the volume header ! 214: (and its backup) */ ! 215: int ! 216: volume_open( volume* vol, int os_fd ) ! 217: { ! 218: hfsp_vh backup; /* backup volume found at second to last block */ ! 219: long sect_per_block; ! 220: int shift; ! 221: ! 222: vol->blksize_bits = HFSP_BLOCKSZ_BITS; ! 223: vol->blksize = HFSP_BLOCKSZ; ! 224: vol->startblock = 0; ! 225: vol->maxblocks = 3; ! 226: /* this should be enough until we find the volume descriptor */ ! 227: vol->extents = NULL; /* Thanks to Jeremias Sauceda */ ! 228: ! 229: btree_reset(&vol->catalog); ! 230: vol->os_fd = os_fd; ! 231: ! 232: // vol->maxblocks = os_seek(vol->os_fd, -1, HFSP_BLOCKSZ_BITS); ! 233: // This wont work for /dev/... but we do not really need it ! 234: ! 235: if( volume_read_wrapper(vol, &vol->vol)) ! 236: return -1; ! 237: if( volume_read(vol, &backup, vol->maxblocks - 2)) ! 238: return -1; ! 239: ! 240: /* Now switch blksize from HFSP_BLOCKSZ (512) to value given in header ! 241: and adjust depend values accordingly, after that a block always ! 242: means a HFS+ allocation size */ ! 243: ! 244: /* Usually 4096 / 512 == 8 */ ! 245: sect_per_block = vol->vol.blocksize / HFSP_BLOCKSZ; ! 246: shift = 0; ! 247: if( sect_per_block > 1) { ! 248: shift = 1; ! 249: while( sect_per_block > 2) { ! 250: sect_per_block >>=1; ! 251: shift++; ! 252: } /* shift = 3 */ ! 253: } ! 254: vol -> blksize_bits += shift; ! 255: vol -> blksize = 1 << vol->blksize_bits; ! 256: vol -> startblock >>= shift; ! 257: vol -> maxblocks = vol->vol.total_blocks; /* cant calculate via shift ? */ ! 258: ! 259: if( btree_init_cat(&vol->catalog, vol, &vol->vol.cat_file)) ! 260: return -1; ! 261: ! 262: return 0; ! 263: } ! 264: ! 265: /* Write back all data eventually cached and close the device */ ! 266: int ! 267: volume_close(volume* vol) ! 268: { ! 269: btree_close(&vol->catalog); ! 270: if( vol->extents) { ! 271: btree_close(vol->extents); ! 272: FREE(vol->extents); ! 273: } ! 274: return 0; ! 275: } ! 276: ! 277: /* internal fucntion used to create the extents btree, ! 278: is called by inline function when needed */ ! 279: void ! 280: volume_create_extents_tree(volume* vol) ! 281: { ! 282: btree* result = (btree*) ALLOC(btree*, sizeof(btree)); ! 283: if( !result) ! 284: HFSP_ERROR(ENOMEM, "No memory for extents btree"); ! 285: if( !btree_init_extent(result, vol, &vol->vol.ext_file)) { ! 286: vol->extents = result; ! 287: return; ! 288: } ! 289: fail: ! 290: vol->extents = NULL; ! 291: } ! 292: ! 293: /* Determine whether the volume is a HFS-plus volume */ ! 294: int ! 295: volume_probe(int fd, long long offset) ! 296: { ! 297: UInt16 *vol; ! 298: int ret = 0; ! 299: ! 300: vol = (UInt16 *)malloc(2 * 1 << HFSP_BLOCKSZ_BITS); ! 301: os_seek_offset( fd, 2 * (1 << HFSP_BLOCKSZ_BITS) + offset ); ! 302: os_read(fd, vol, 2, HFSP_BLOCKSZ_BITS); ! 303: ! 304: if (__be16_to_cpu(vol[0]) == HFS_VOLHEAD_SIG && ! 305: __be16_to_cpu(vol[0x7c]) == HFSP_VOLHEAD_SIG) { ! 306: ret = -1; ! 307: } else if (__be16_to_cpu(vol[0]) == HFSP_VOLHEAD_SIG) { ! 308: ret = -1; ! 309: } ! 310: ! 311: free(vol); ! 312: return ret; ! 313: } ! 314:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.