|
|
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.