2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)low.c 1.4 04/06/17 joerg */
15 * hfsutils - tools for reading and writing Macintosh HFS volumes
16 * Copyright (C) 1996, 1997 Robert Leslie
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
47 * NAME: low->lockvol()
48 * DESCRIPTION: prevent destructive simultaneous access
50 int l_lockvol(hfsvol *vol)
56 lock.l_type = (vol->flags & HFS_READONLY) ? F_RDLCK : F_WRLCK;
58 lock.l_whence = SEEK_SET;
61 if (fcntl(vol->fd, F_SETLK, &lock) < 0)
63 ERROR(errno, "unable to obtain lock for device");
73 * NAME: low->readblock0()
74 * DESCRIPTION: read the first sector and get bearings
76 int l_readblock0(hfsvol *vol)
79 unsigned char *ptr = b;
82 if (b_readlb(vol, 0, &b) < 0)
85 d_fetchw(&ptr, &rec.sbSig);
86 d_fetchw(&ptr, &rec.sbBlkSize);
87 d_fetchl(&ptr, &rec.sbBlkCount);
88 d_fetchw(&ptr, &rec.sbDevType);
89 d_fetchw(&ptr, &rec.sbDevId);
90 d_fetchl(&ptr, &rec.sbData);
91 d_fetchw(&ptr, &rec.sbDrvrCount);
92 d_fetchl(&ptr, &rec.ddBlock);
93 d_fetchw(&ptr, &rec.ddSize);
94 d_fetchw(&ptr, &rec.ddType);
98 case 0x4552: /* block device with a partition table */
100 if (rec.sbBlkSize != HFS_BLOCKSZ)
102 ERROR(EINVAL, "unsupported block size");
106 vol->vlen = rec.sbBlkCount;
108 if (l_readpm(vol) < 0)
113 case 0x4c4b: /* bootable floppy */
117 default: /* non-bootable floppy or something else */
119 /* some miscreant media may also be partitioned;
120 we attempt to read a partition map, but ignore any failure */
122 if (l_readpm(vol) < 0)
130 * NAME: low->readpm()
131 * DESCRIPTION: read the partition map and locate an HFS volume
133 int l_readpm(hfsvol *vol)
146 if (b_readlb(vol, bnum, &b) < 0)
151 d_fetchw(&ptr, &map.pmSig);
152 d_fetchw(&ptr, &map.pmSigPad);
153 d_fetchl(&ptr, &map.pmMapBlkCnt);
154 d_fetchl(&ptr, &map.pmPyPartStart);
155 d_fetchl(&ptr, &map.pmPartBlkCnt);
157 memcpy(map.pmPartName, ptr, 32);
158 map.pmPartName[32] = 0;
161 memcpy(map.pmParType, ptr, 32);
162 map.pmParType[32] = 0;
165 d_fetchl(&ptr, &map.pmLgDataStart);
166 d_fetchl(&ptr, &map.pmDataCnt);
167 d_fetchl(&ptr, &map.pmPartStatus);
168 d_fetchl(&ptr, &map.pmLgBootStart);
169 d_fetchl(&ptr, &map.pmBootSize);
170 d_fetchl(&ptr, &map.pmBootAddr);
171 d_fetchl(&ptr, &map.pmBootAddr2);
172 d_fetchl(&ptr, &map.pmBootEntry);
173 d_fetchl(&ptr, &map.pmBootEntry2);
174 d_fetchl(&ptr, &map.pmBootCksum);
176 memcpy(map.pmProcessor, ptr, 16);
177 map.pmProcessor[16] = 0;
180 if (map.pmSig == 0x5453)
182 /* old partition map sig */
184 ERROR(EINVAL, "unsupported partition map signature");
188 if (map.pmSig != 0x504d)
190 ERROR(EINVAL, "bad partition map");
194 if (strcmp((char *) map.pmParType, "Apple_HFS") == 0 && --pnum == 0)
196 if (map.pmLgDataStart != 0)
198 ERROR(EINVAL, "unsupported start of partition logical data");
202 vol->vstart = map.pmPyPartStart;
203 vol->vlen = map.pmPartBlkCnt;
208 if (bnum >= map.pmMapBlkCnt)
210 ERROR(EINVAL, "can't find HFS partition");
219 * NAME: low->readmdb()
220 * DESCRIPTION: read the master directory block into memory
222 int l_readmdb(hfsvol *vol)
225 unsigned char *ptr = b;
226 MDB *mdb = &vol->mdb;
227 hfsfile *ext = &vol->ext.f;
228 hfsfile *cat = &vol->cat.f;
231 if (b_readlb(vol, 2, &b) < 0)
234 d_fetchw(&ptr, &mdb->drSigWord);
235 d_fetchl(&ptr, &mdb->drCrDate);
236 d_fetchl(&ptr, &mdb->drLsMod);
237 d_fetchw(&ptr, &mdb->drAtrb);
238 d_fetchw(&ptr, (short *) &mdb->drNmFls);
239 d_fetchw(&ptr, (short *) &mdb->drVBMSt);
240 d_fetchw(&ptr, (short *) &mdb->drAllocPtr);
241 d_fetchw(&ptr, (short *) &mdb->drNmAlBlks);
242 d_fetchl(&ptr, (long *) &mdb->drAlBlkSiz);
243 d_fetchl(&ptr, (long *) &mdb->drClpSiz);
244 d_fetchw(&ptr, (short *) &mdb->drAlBlSt);
245 d_fetchl(&ptr, &mdb->drNxtCNID);
246 d_fetchw(&ptr, (short *) &mdb->drFreeBks);
248 d_fetchs(&ptr, mdb->drVN, sizeof(mdb->drVN));
253 d_fetchl(&ptr, &mdb->drVolBkUp);
254 d_fetchw(&ptr, &mdb->drVSeqNum);
255 d_fetchl(&ptr, (long *) &mdb->drWrCnt);
256 d_fetchl(&ptr, (long *) &mdb->drXTClpSiz);
257 d_fetchl(&ptr, (long *) &mdb->drCTClpSiz);
258 d_fetchw(&ptr, (short *) &mdb->drNmRtDirs);
259 d_fetchl(&ptr, (long *) &mdb->drFilCnt);
260 d_fetchl(&ptr, (long *) &mdb->drDirCnt);
262 for (i = 0; i < 8; ++i)
263 d_fetchl(&ptr, &mdb->drFndrInfo[i]);
268 d_fetchw(&ptr, (short *) &mdb->drVCSize);
269 d_fetchw(&ptr, (short *) &mdb->drVBMCSize);
270 d_fetchw(&ptr, (short *) &mdb->drCtlCSize);
272 d_fetchl(&ptr, (long *) &mdb->drXTFlSize);
274 for (i = 0; i < 3; ++i)
276 d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrStABN);
277 d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrNumABlks);
283 d_fetchl(&ptr, (long *) &mdb->drCTFlSize);
285 for (i = 0; i < 3; ++i)
287 d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrStABN);
288 d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrNumABlks);
294 vol->lpa = mdb->drAlBlkSiz / HFS_BLOCKSZ;
296 /* extents pseudo-file structs */
300 strcpy(ext->name, "extents overflow");
302 ext->cat.cdrType = cdrFilRec;
303 /* ext->cat.cdrResrv2 */
304 ext->cat.u.fil.filFlags = 0;
305 ext->cat.u.fil.filTyp = 0;
306 /* ext->cat.u.fil.filUsrWds */
307 ext->cat.u.fil.filFlNum = HFS_CNID_EXT;
308 ext->cat.u.fil.filStBlk = mdb->drXTExtRec[0].xdrStABN;
309 ext->cat.u.fil.filLgLen = mdb->drXTFlSize;
310 ext->cat.u.fil.filPyLen = mdb->drXTFlSize;
311 ext->cat.u.fil.filRStBlk = 0;
312 ext->cat.u.fil.filRLgLen = 0;
313 ext->cat.u.fil.filRPyLen = 0;
314 ext->cat.u.fil.filCrDat = mdb->drCrDate;
315 ext->cat.u.fil.filMdDat = mdb->drLsMod;
316 ext->cat.u.fil.filBkDat = 0;
317 /* ext->cat.u.fil.filFndrInfo */
318 ext->cat.u.fil.filClpSize = 0;
320 memcpy(ext->cat.u.fil.filExtRec, mdb->drXTExtRec, sizeof(ExtDataRec));
321 for (i = 0; i < 3; ++i)
323 ext->cat.u.fil.filRExtRec[i].xdrStABN = 0;
324 ext->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
326 f_selectfork(ext, 0);
328 ext->clump = mdb->drXTClpSiz;
331 ext->prev = ext->next = 0;
333 /* catalog pseudo-file structs */
337 strcpy(cat->name, "catalog");
339 cat->cat.cdrType = cdrFilRec;
340 /* cat->cat.cdrResrv2 */
341 cat->cat.u.fil.filFlags = 0;
342 cat->cat.u.fil.filTyp = 0;
343 /* cat->cat.u.fil.filUsrWds */
344 cat->cat.u.fil.filFlNum = HFS_CNID_CAT;
345 cat->cat.u.fil.filStBlk = mdb->drCTExtRec[0].xdrStABN;
346 cat->cat.u.fil.filLgLen = mdb->drCTFlSize;
347 cat->cat.u.fil.filPyLen = mdb->drCTFlSize;
348 cat->cat.u.fil.filRStBlk = 0;
349 cat->cat.u.fil.filRLgLen = 0;
350 cat->cat.u.fil.filRPyLen = 0;
351 cat->cat.u.fil.filCrDat = mdb->drCrDate;
352 cat->cat.u.fil.filMdDat = mdb->drLsMod;
353 cat->cat.u.fil.filBkDat = 0;
354 /* cat->cat.u.fil.filFndrInfo */
355 cat->cat.u.fil.filClpSize = 0;
357 memcpy(cat->cat.u.fil.filExtRec, mdb->drCTExtRec, sizeof(ExtDataRec));
358 for (i = 0; i < 3; ++i)
360 cat->cat.u.fil.filRExtRec[i].xdrStABN = 0;
361 cat->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
363 f_selectfork(cat, 0);
365 cat->clump = mdb->drCTClpSiz;
368 cat->prev = cat->next = 0;
374 * NAME: low->writemdb()
375 * DESCRIPTION: write the master directory block to disk
377 int l_writemdb(hfsvol *vol)
380 unsigned char *ptr = b;
381 MDB *mdb = &vol->mdb;
382 hfsfile *ext = &vol->ext.f;
383 hfsfile *cat = &vol->cat.f;
386 memset(&b, 0, sizeof(b));
388 mdb->drXTFlSize = ext->cat.u.fil.filPyLen;
389 mdb->drXTClpSiz = ext->clump;
390 memcpy(mdb->drXTExtRec, ext->cat.u.fil.filExtRec, sizeof(ExtDataRec));
392 mdb->drCTFlSize = cat->cat.u.fil.filPyLen;
393 mdb->drCTClpSiz = cat->clump;
394 memcpy(mdb->drCTExtRec, cat->cat.u.fil.filExtRec, sizeof(ExtDataRec));
396 d_storew(&ptr, mdb->drSigWord);
397 d_storel(&ptr, mdb->drCrDate);
398 d_storel(&ptr, mdb->drLsMod);
399 d_storew(&ptr, mdb->drAtrb);
400 d_storew(&ptr, mdb->drNmFls);
401 d_storew(&ptr, mdb->drVBMSt);
402 d_storew(&ptr, mdb->drAllocPtr);
403 d_storew(&ptr, mdb->drNmAlBlks);
404 d_storel(&ptr, mdb->drAlBlkSiz);
405 d_storel(&ptr, mdb->drClpSiz);
406 d_storew(&ptr, mdb->drAlBlSt);
407 d_storel(&ptr, mdb->drNxtCNID);
408 d_storew(&ptr, mdb->drFreeBks);
409 d_stores(&ptr, mdb->drVN, sizeof(mdb->drVN));
414 d_storel(&ptr, mdb->drVolBkUp);
415 d_storew(&ptr, mdb->drVSeqNum);
416 d_storel(&ptr, mdb->drWrCnt);
417 d_storel(&ptr, mdb->drXTClpSiz);
418 d_storel(&ptr, mdb->drCTClpSiz);
419 d_storew(&ptr, mdb->drNmRtDirs);
420 d_storel(&ptr, mdb->drFilCnt);
421 d_storel(&ptr, mdb->drDirCnt);
423 for (i = 0; i < 8; ++i)
424 d_storel(&ptr, mdb->drFndrInfo[i]);
429 d_storew(&ptr, mdb->drVCSize);
430 d_storew(&ptr, mdb->drVBMCSize);
431 d_storew(&ptr, mdb->drCtlCSize);
432 d_storel(&ptr, mdb->drXTFlSize);
434 for (i = 0; i < 3; ++i)
436 d_storew(&ptr, mdb->drXTExtRec[i].xdrStABN);
437 d_storew(&ptr, mdb->drXTExtRec[i].xdrNumABlks);
443 d_storel(&ptr, mdb->drCTFlSize);
445 for (i = 0; i < 3; ++i)
447 d_storew(&ptr, mdb->drCTExtRec[i].xdrStABN);
448 d_storew(&ptr, mdb->drCTExtRec[i].xdrNumABlks);
454 if (b_writelb(vol, 2, &b) < 0)
456 if (vol->flags & HFS_UPDATE_ALTMDB)
459 /* "write" alternative MDB to memory copy */
460 memcpy(vol->hce->hfs_alt_mdb, &b, sizeof(b));
462 if (b_writelb(vol, vol->vlen - 2, &b) < 0)
464 #endif /* APPLE_HYB */
466 vol->flags &= ~(HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB);
472 * NAME: low->readvbm()
473 * DESCRIPTION: read the volume bit map into memory
475 int l_readvbm(hfsvol *vol)
477 int vbmst = vol->mdb.drVBMSt;
478 int vbmsz = (vol->mdb.drNmAlBlks + 4095) / (unsigned)4096;
481 if ((int)(vol->mdb.drAlBlSt - vbmst) < vbmsz)
483 ERROR(EIO, "volume bitmap collides with volume data");
487 bp = ALLOC(block, vbmsz);
498 if (b_readlb(vol, vbmst++, bp++) < 0)
511 * NAME: low->writevbm()
512 * DESCRIPTION: write the volume bit map to disk
514 int l_writevbm(hfsvol *vol)
516 int vbmst = vol->mdb.drVBMSt;
517 int vbmsz = (vol->mdb.drNmAlBlks + 4095) / (unsigned)4096;
518 block *bp = vol->vbm;
522 if (b_writelb(vol, vbmst++, bp++) < 0)
526 vol->flags &= ~HFS_UPDATE_VBM;