ppc64: Don't set Kp bit on SLB
[openbios.git] / fs / hfsplus / hfsp_volume.c
blob802d70043b7ba647d3b6b6338e75a5be34c901f4
1 /*
2 * libhfs - library for reading and writing Macintosh HFS volumes
4 * Code to acces the basic volume information of a HFS+ volume.
6 * Copyright (C) 2000 Klaus Halfmann <khalfmann@libra.de>
7 * Original work by 1996-1998 Robert Leslie <rob@mars.org>
8 * other work 2000 from Brad Boyer (flar@pants.nu)
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.
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.
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.
25 * $Id: volume.c,v 1.21 2000/10/25 05:43:04 hasi Exp $
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"
39 /* Fill a given buffer with the given block in volume.
41 int
42 volume_readinbuf(volume * vol,void* buf, long block)
44 UInt16 blksize_bits;
45 ASSERT( block < vol->maxblocks);
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;
55 /* read multiple blocks into given memory.
57 * returns given pinter or NULL on failure.
59 void*
60 volume_readfromfork(volume* vol, void* buf,
61 hfsp_fork_raw* f, UInt32 block,
62 UInt32 count, UInt8 forktype, UInt32 fileId)
64 blockiter iter;
65 char *cbuf = buf;
67 blockiter_init(&iter, vol, f, forktype, fileId);
68 if( blockiter_skip(&iter, block))
69 return NULL;
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;
79 return buf;
83 /* Read a raw hfsp_extent_rec from memory.
85 * return pointer right after the structure.
87 void*
88 volume_readextent(void *p, hfsp_extent_rec er)
90 int i;
91 hfsp_extent *e;
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);
98 return p;
101 /* Read a raw hfsp_fork from memory.
103 * return pointer right after the structure.
105 void*
106 volume_readfork(void *p, hfsp_fork_raw* f)
108 f->total_size = bswabU64_inc(p);
109 f->clump_size = bswabU32_inc(p);
110 f->total_blocks = bswabU32_inc(p);
112 return volume_readextent(p, f->extents);
115 /* Read the volume from the given buffer and swap the bytes.
117 * ToDo: add more consitency checks.
119 static int
120 volume_readbuf(hfsp_vh* vh, char * p)
122 if( (vh->signature = bswabU16_inc(p)) != HFSP_VOLHEAD_SIG)
123 HFSP_ERROR(-1, "This is not a HFS+ volume");
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;
156 /* Read the volume from the given block */
157 static int
158 volume_read(volume * vol, hfsp_vh* vh, UInt32 block)
160 char buf[vol->blksize];
162 if( volume_readinbuf(vol, buf, block))
163 return -1;
164 return volume_readbuf(vh, buf);
167 /* Find out wether the volume is wrapped and unwrap it eventually */
168 static int
169 volume_read_wrapper(volume * vol, hfsp_vh* vh)
171 UInt16 signature;
172 char buf[vol->blksize];
173 char *p = buf;
175 if( volume_readinbuf(vol, buf, 2) ) // Wrapper or volume header starts here
176 return -1;
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 */
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 */
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);
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;
213 /* Open the device, read and verify the volume header
214 (and its backup) */
216 volume_open( volume* vol, int os_fd )
218 hfsp_vh backup; /* backup volume found at second to last block */
219 long sect_per_block;
220 int shift;
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 */
229 btree_reset(&vol->catalog);
230 vol->os_fd = os_fd;
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
235 if( volume_read_wrapper(vol, &vol->vol))
236 return -1;
237 if( volume_read(vol, &backup, vol->maxblocks - 2))
238 return -1;
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 */
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 */
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 ? */
259 if( btree_init_cat(&vol->catalog, vol, &vol->vol.cat_file))
260 return -1;
262 return 0;
265 /* Write back all data eventually cached and close the device */
267 volume_close(volume* vol)
269 btree_close(&vol->catalog);
270 if( vol->extents) {
271 btree_close(vol->extents);
272 FREE(vol->extents);
274 return 0;
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)
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;
289 fail:
290 vol->extents = NULL;
293 /* Determine whether the volume is a HFS-plus volume */
295 volume_probe(int fd, long long offset)
297 UInt16 *vol;
298 int ret = 0;
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);
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;
311 free(vol);
312 return ret;