1 /* 2 * hfsutils - tools for reading and writing Macintosh HFS volumes 3 * Copyright (C) 1996, 1997 Robert Leslie 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20 # include <string.h> 21 # include <stdlib.h> 22 # include <errno.h> 23 # include <unistd.h> 24 # include <fcntl.h> 25 26 # include "internal.h" 27 # include "data.h" 28 # include "block.h" 29 # include "low.h" 30 # include "file.h" 31 32 /* 33 * NAME: low->lockvol() 34 * DESCRIPTION: prevent destructive simultaneous access 35 */ 36 int l_lockvol(hfsvol *vol) 37 { 38 # ifndef NODEVLOCKS 39 40 struct flock lock; 41 42 lock.l_type = (vol->flags & HFS_READONLY) ? F_RDLCK : F_WRLCK; 43 lock.l_start = 0; 44 lock.l_whence = SEEK_SET; 45 lock.l_len = 0; 46 47 if (fcntl(vol->fd, F_SETLK, &lock) < 0) 48 { 49 ERROR(errno, "unable to obtain lock for device"); 50 return -1; 51 } 52 53 # endif 54 55 return 0; 56 } 57 58 /* 59 * NAME: low->readblock0() 60 * DESCRIPTION: read the first sector and get bearings 61 */ 62 int l_readblock0(hfsvol *vol) 63 { 64 block b; 65 unsigned char *ptr = b; 66 Block0 rec; 67 68 if (b_readlb(vol, 0, &b) < 0) 69 return -1; 70 71 d_fetchw(&ptr, &rec.sbSig); 72 d_fetchw(&ptr, &rec.sbBlkSize); 73 d_fetchl(&ptr, &rec.sbBlkCount); 74 d_fetchw(&ptr, &rec.sbDevType); 75 d_fetchw(&ptr, &rec.sbDevId); 76 d_fetchl(&ptr, &rec.sbData); 77 d_fetchw(&ptr, &rec.sbDrvrCount); 78 d_fetchl(&ptr, &rec.ddBlock); 79 d_fetchw(&ptr, &rec.ddSize); 80 d_fetchw(&ptr, &rec.ddType); 81 82 switch (rec.sbSig) 83 { 84 case 0x4552: /* block device with a partition table */ 85 { 86 if (rec.sbBlkSize != HFS_BLOCKSZ) 87 { 88 ERROR(EINVAL, "unsupported block size"); 89 return -1; 90 } 91 92 vol->vlen = rec.sbBlkCount; 93 94 if (l_readpm(vol) < 0) 95 return -1; 96 } 97 break; 98 99 case 0x4c4b: /* bootable floppy */ 100 vol->pnum = 0; 101 break; 102 103 default: /* non-bootable floppy or something else */ 104 105 /* some miscreant media may also be partitioned; 106 we attempt to read a partition map, but ignore any failure */ 107 108 if (l_readpm(vol) < 0) 109 vol->pnum = 0; 110 } 111 112 return 0; 113 } 114 115 /* 116 * NAME: low->readpm() 117 * DESCRIPTION: read the partition map and locate an HFS volume 118 */ 119 int l_readpm(hfsvol *vol) 120 { 121 block b; 122 unsigned char *ptr; 123 Partition map; 124 unsigned long bnum; 125 int pnum; 126 127 bnum = 1; 128 pnum = vol->pnum; 129 130 while (1) 131 { 132 if (b_readlb(vol, bnum, &b) < 0) 133 return -1; 134 135 ptr = b; 136 137 d_fetchw(&ptr, &map.pmSig); 138 d_fetchw(&ptr, &map.pmSigPad); 139 d_fetchl(&ptr, &map.pmMapBlkCnt); 140 d_fetchl(&ptr, &map.pmPyPartStart); 141 d_fetchl(&ptr, &map.pmPartBlkCnt); 142 143 memcpy(map.pmPartName, ptr, 32); 144 map.pmPartName[32] = 0; 145 ptr += 32; 146 147 memcpy(map.pmParType, ptr, 32); 148 map.pmParType[32] = 0; 149 ptr += 32; 150 151 d_fetchl(&ptr, &map.pmLgDataStart); 152 d_fetchl(&ptr, &map.pmDataCnt); 153 d_fetchl(&ptr, &map.pmPartStatus); 154 d_fetchl(&ptr, &map.pmLgBootStart); 155 d_fetchl(&ptr, &map.pmBootSize); 156 d_fetchl(&ptr, &map.pmBootAddr); 157 d_fetchl(&ptr, &map.pmBootAddr2); 158 d_fetchl(&ptr, &map.pmBootEntry); 159 d_fetchl(&ptr, &map.pmBootEntry2); 160 d_fetchl(&ptr, &map.pmBootCksum); 161 162 memcpy(map.pmProcessor, ptr, 16); 163 map.pmProcessor[16] = 0; 164 ptr += 16; 165 166 if (map.pmSig == 0x5453) 167 { 168 /* old partition map sig */ 169 170 ERROR(EINVAL, "unsupported partition map signature"); 171 return -1; 172 } 173 174 if (map.pmSig != 0x504d) 175 { 176 ERROR(EINVAL, "bad partition map"); 177 return -1; 178 } 179 180 if (strcmp((char *) map.pmParType, "Apple_HFS") == 0 && --pnum == 0) 181 { 182 if (map.pmLgDataStart != 0) 183 { 184 ERROR(EINVAL, "unsupported start of partition logical data"); 185 return -1; 186 } 187 188 vol->vstart = map.pmPyPartStart; 189 vol->vlen = map.pmPartBlkCnt; 190 191 return 0; 192 } 193 194 if (bnum >= map.pmMapBlkCnt) 195 { 196 ERROR(EINVAL, "can't find HFS partition"); 197 return -1; 198 } 199 200 ++bnum; 201 } 202 } 203 204 /* 205 * NAME: low->readmdb() 206 * DESCRIPTION: read the master directory block into memory 207 */ 208 int l_readmdb(hfsvol *vol) 209 { 210 block b; 211 unsigned char *ptr = b; 212 MDB *mdb = &vol->mdb; 213 hfsfile *ext = &vol->ext.f; 214 hfsfile *cat = &vol->cat.f; 215 int i; 216 217 if (b_readlb(vol, 2, &b) < 0) 218 return -1; 219 220 d_fetchw(&ptr, &mdb->drSigWord); 221 d_fetchl(&ptr, &mdb->drCrDate); 222 d_fetchl(&ptr, &mdb->drLsMod); 223 d_fetchw(&ptr, &mdb->drAtrb); 224 d_fetchw(&ptr, (short *) &mdb->drNmFls); 225 d_fetchw(&ptr, (short *) &mdb->drVBMSt); 226 d_fetchw(&ptr, (short *) &mdb->drAllocPtr); 227 d_fetchw(&ptr, (short *) &mdb->drNmAlBlks); 228 d_fetchl(&ptr, (long *) &mdb->drAlBlkSiz); 229 d_fetchl(&ptr, (long *) &mdb->drClpSiz); 230 d_fetchw(&ptr, (short *) &mdb->drAlBlSt); 231 d_fetchl(&ptr, &mdb->drNxtCNID); 232 d_fetchw(&ptr, (short *) &mdb->drFreeBks); 233 234 d_fetchs(&ptr, mdb->drVN, sizeof(mdb->drVN)); 235 236 if (ptr - b != 64) 237 abort(); 238 239 d_fetchl(&ptr, &mdb->drVolBkUp); 240 d_fetchw(&ptr, &mdb->drVSeqNum); 241 d_fetchl(&ptr, (long *) &mdb->drWrCnt); 242 d_fetchl(&ptr, (long *) &mdb->drXTClpSiz); 243 d_fetchl(&ptr, (long *) &mdb->drCTClpSiz); 244 d_fetchw(&ptr, (short *) &mdb->drNmRtDirs); 245 d_fetchl(&ptr, (long *) &mdb->drFilCnt); 246 d_fetchl(&ptr, (long *) &mdb->drDirCnt); 247 248 for (i = 0; i < 8; ++i) 249 d_fetchl(&ptr, &mdb->drFndrInfo[i]); 250 251 if (ptr - b != 124) 252 abort(); 253 254 d_fetchw(&ptr, (short *) &mdb->drVCSize); 255 d_fetchw(&ptr, (short *) &mdb->drVBMCSize); 256 d_fetchw(&ptr, (short *) &mdb->drCtlCSize); 257 258 d_fetchl(&ptr, (long *) &mdb->drXTFlSize); 259 260 for (i = 0; i < 3; ++i) 261 { 262 d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrStABN); 263 d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrNumABlks); 264 } 265 266 if (ptr - b != 146) 267 abort(); 268 269 d_fetchl(&ptr, (long *) &mdb->drCTFlSize); 270 271 for (i = 0; i < 3; ++i) 272 { 273 d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrStABN); 274 d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrNumABlks); 275 } 276 277 if (ptr - b != 162) 278 abort(); 279 280 vol->lpa = mdb->drAlBlkSiz / HFS_BLOCKSZ; 281 282 /* extents pseudo-file structs */ 283 284 ext->vol = vol; 285 ext->parid = 0; 286 strcpy(ext->name, "extents overflow"); 287 288 ext->cat.cdrType = cdrFilRec; 289 /* ext->cat.cdrResrv2 */ 290 ext->cat.u.fil.filFlags = 0; 291 ext->cat.u.fil.filTyp = 0; 292 /* ext->cat.u.fil.filUsrWds */ 293 ext->cat.u.fil.filFlNum = HFS_CNID_EXT; 294 ext->cat.u.fil.filStBlk = mdb->drXTExtRec[0].xdrStABN; 295 ext->cat.u.fil.filLgLen = mdb->drXTFlSize; 296 ext->cat.u.fil.filPyLen = mdb->drXTFlSize; 297 ext->cat.u.fil.filRStBlk = 0; 298 ext->cat.u.fil.filRLgLen = 0; 299 ext->cat.u.fil.filRPyLen = 0; 300 ext->cat.u.fil.filCrDat = mdb->drCrDate; 301 ext->cat.u.fil.filMdDat = mdb->drLsMod; 302 ext->cat.u.fil.filBkDat = 0; 303 /* ext->cat.u.fil.filFndrInfo */ 304 ext->cat.u.fil.filClpSize = 0; 305 306 memcpy(ext->cat.u.fil.filExtRec, mdb->drXTExtRec, sizeof(ExtDataRec)); 307 for (i = 0; i < 3; ++i) 308 { 309 ext->cat.u.fil.filRExtRec[i].xdrStABN = 0; 310 ext->cat.u.fil.filRExtRec[i].xdrNumABlks = 0; 311 } 312 f_selectfork(ext, 0); 313 314 ext->clump = mdb->drXTClpSiz; 315 ext->flags = 0; 316 317 ext->prev = ext->next = 0; 318 319 /* catalog pseudo-file structs */ 320 321 cat->vol = vol; 322 cat->parid = 0; 323 strcpy(cat->name, "catalog"); 324 325 cat->cat.cdrType = cdrFilRec; 326 /* cat->cat.cdrResrv2 */ 327 cat->cat.u.fil.filFlags = 0; 328 cat->cat.u.fil.filTyp = 0; 329 /* cat->cat.u.fil.filUsrWds */ 330 cat->cat.u.fil.filFlNum = HFS_CNID_CAT; 331 cat->cat.u.fil.filStBlk = mdb->drCTExtRec[0].xdrStABN; 332 cat->cat.u.fil.filLgLen = mdb->drCTFlSize; 333 cat->cat.u.fil.filPyLen = mdb->drCTFlSize; 334 cat->cat.u.fil.filRStBlk = 0; 335 cat->cat.u.fil.filRLgLen = 0; 336 cat->cat.u.fil.filRPyLen = 0; 337 cat->cat.u.fil.filCrDat = mdb->drCrDate; 338 cat->cat.u.fil.filMdDat = mdb->drLsMod; 339 cat->cat.u.fil.filBkDat = 0; 340 /* cat->cat.u.fil.filFndrInfo */ 341 cat->cat.u.fil.filClpSize = 0; 342 343 memcpy(cat->cat.u.fil.filExtRec, mdb->drCTExtRec, sizeof(ExtDataRec)); 344 for (i = 0; i < 3; ++i) 345 { 346 cat->cat.u.fil.filRExtRec[i].xdrStABN = 0; 347 cat->cat.u.fil.filRExtRec[i].xdrNumABlks = 0; 348 } 349 f_selectfork(cat, 0); 350 351 cat->clump = mdb->drCTClpSiz; 352 cat->flags = 0; 353 354 cat->prev = cat->next = 0; 355 356 return 0; 357 } 358 359 /* 360 * NAME: low->writemdb() 361 * DESCRIPTION: write the master directory block to disk 362 */ 363 int l_writemdb(hfsvol *vol) 364 { 365 block b; 366 unsigned char *ptr = b; 367 MDB *mdb = &vol->mdb; 368 hfsfile *ext = &vol->ext.f; 369 hfsfile *cat = &vol->cat.f; 370 int i; 371 372 memset(&b, 0, sizeof(b)); 373 374 mdb->drXTFlSize = ext->cat.u.fil.filPyLen; 375 mdb->drXTClpSiz = ext->clump; 376 memcpy(mdb->drXTExtRec, ext->cat.u.fil.filExtRec, sizeof(ExtDataRec)); 377 378 mdb->drCTFlSize = cat->cat.u.fil.filPyLen; 379 mdb->drCTClpSiz = cat->clump; 380 memcpy(mdb->drCTExtRec, cat->cat.u.fil.filExtRec, sizeof(ExtDataRec)); 381 382 d_storew(&ptr, mdb->drSigWord); 383 d_storel(&ptr, mdb->drCrDate); 384 d_storel(&ptr, mdb->drLsMod); 385 d_storew(&ptr, mdb->drAtrb); 386 d_storew(&ptr, mdb->drNmFls); 387 d_storew(&ptr, mdb->drVBMSt); 388 d_storew(&ptr, mdb->drAllocPtr); 389 d_storew(&ptr, mdb->drNmAlBlks); 390 d_storel(&ptr, mdb->drAlBlkSiz); 391 d_storel(&ptr, mdb->drClpSiz); 392 d_storew(&ptr, mdb->drAlBlSt); 393 d_storel(&ptr, mdb->drNxtCNID); 394 d_storew(&ptr, mdb->drFreeBks); 395 d_stores(&ptr, mdb->drVN, sizeof(mdb->drVN)); 396 397 if (ptr - b != 64) 398 abort(); 399 400 d_storel(&ptr, mdb->drVolBkUp); 401 d_storew(&ptr, mdb->drVSeqNum); 402 d_storel(&ptr, mdb->drWrCnt); 403 d_storel(&ptr, mdb->drXTClpSiz); 404 d_storel(&ptr, mdb->drCTClpSiz); 405 d_storew(&ptr, mdb->drNmRtDirs); 406 d_storel(&ptr, mdb->drFilCnt); 407 d_storel(&ptr, mdb->drDirCnt); 408 409 for (i = 0; i < 8; ++i) 410 d_storel(&ptr, mdb->drFndrInfo[i]); 411 412 if (ptr - b != 124) 413 abort(); 414 415 d_storew(&ptr, mdb->drVCSize); 416 d_storew(&ptr, mdb->drVBMCSize); 417 d_storew(&ptr, mdb->drCtlCSize); 418 d_storel(&ptr, mdb->drXTFlSize); 419 420 for (i = 0; i < 3; ++i) 421 { 422 d_storew(&ptr, mdb->drXTExtRec[i].xdrStABN); 423 d_storew(&ptr, mdb->drXTExtRec[i].xdrNumABlks); 424 } 425 426 if (ptr - b != 146) 427 abort(); 428 429 d_storel(&ptr, mdb->drCTFlSize); 430 431 for (i = 0; i < 3; ++i) 432 { 433 d_storew(&ptr, mdb->drCTExtRec[i].xdrStABN); 434 d_storew(&ptr, mdb->drCTExtRec[i].xdrNumABlks); 435 } 436 437 if (ptr - b != 162) 438 abort(); 439 440 if (b_writelb(vol, 2, &b) < 0) 441 return -1; 442 if (vol->flags & HFS_UPDATE_ALTMDB) 443 { 444 #ifdef APPLE_HYB 445 /* "write" alternative MDB to memory copy */ 446 memcpy(vol->hce->hfs_alt_mdb, &b, sizeof(b)); 447 #else 448 if (b_writelb(vol, vol->vlen - 2, &b) < 0) 449 return -1; 450 #endif /* APPLE_HYB */ 451 } 452 vol->flags &= ~(HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB); 453 454 return 0; 455 } 456 457 /* 458 * NAME: low->readvbm() 459 * DESCRIPTION: read the volume bit map into memory 460 */ 461 int l_readvbm(hfsvol *vol) 462 { 463 int vbmst = vol->mdb.drVBMSt; 464 int vbmsz = (vol->mdb.drNmAlBlks + 4095) / 4096; 465 block *bp; 466 467 if (vol->mdb.drAlBlSt - vbmst < vbmsz) 468 { 469 ERROR(EIO, "volume bitmap collides with volume data"); 470 return -1; 471 } 472 473 bp = ALLOC(block, vbmsz); 474 if (bp == 0) 475 { 476 ERROR(ENOMEM, 0); 477 return -1; 478 } 479 480 vol->vbm = bp; 481 482 while (vbmsz--) 483 { 484 if (b_readlb(vol, vbmst++, bp++) < 0) 485 { 486 FREE(vol->vbm); 487 vol->vbm = 0; 488 489 return -1; 490 } 491 } 492 493 return 0; 494 } 495 496 /* 497 * NAME: low->writevbm() 498 * DESCRIPTION: write the volume bit map to disk 499 */ 500 int l_writevbm(hfsvol *vol) 501 { 502 int vbmst = vol->mdb.drVBMSt; 503 int vbmsz = (vol->mdb.drNmAlBlks + 4095) / 4096; 504 block *bp = vol->vbm; 505 506 while (vbmsz--) 507 { 508 if (b_writelb(vol, vbmst++, bp++) < 0) 509 return -1; 510 } 511 512 vol->flags &= ~HFS_UPDATE_VBM; 513 514 return 0; 515 } 516