Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libhfs_iso / low.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
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).
6  *
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.
10  *
11  */
12
13 /* @(#)low.c    1.4 04/06/17 joerg */
14 /*
15  * hfsutils - tools for reading and writing Macintosh HFS volumes
16  * Copyright (C) 1996, 1997 Robert Leslie
17  *
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.
22  *
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.
27  *
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.
31  */
32
33 #include <mconfig.h>
34 #include <strdefs.h>
35 #include <stdxlib.h>
36 #include <errno.h>
37 #include <unixstd.h>
38 #include <fctldefs.h>
39
40 #include "internal.h"
41 #include "data.h"
42 #include "block.h"
43 #include "low.h"
44 #include "file.h"
45
46 /*
47  * NAME:        low->lockvol()
48  * DESCRIPTION: prevent destructive simultaneous access
49  */
50 int l_lockvol(hfsvol *vol)
51 {
52 # ifndef NODEVLOCKS
53
54   struct flock lock;
55
56   lock.l_type   = (vol->flags & HFS_READONLY) ? F_RDLCK : F_WRLCK;
57   lock.l_start  = 0;
58   lock.l_whence = SEEK_SET;
59   lock.l_len    = 0;
60
61   if (fcntl(vol->fd, F_SETLK, &lock) < 0)
62     {
63       ERROR(errno, "unable to obtain lock for device");
64       return -1;
65     }
66
67 # endif
68
69   return 0;
70 }
71
72 /*
73  * NAME:        low->readblock0()
74  * DESCRIPTION: read the first sector and get bearings
75  */
76 int l_readblock0(hfsvol *vol)
77 {
78   block b;
79   unsigned char *ptr = b;
80   Block0 rec;
81
82   if (b_readlb(vol, 0, &b) < 0)
83     return -1;
84
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);
95
96   switch (rec.sbSig)
97     {
98     case 0x4552:  /* block device with a partition table */
99       {
100         if (rec.sbBlkSize != HFS_BLOCKSZ)
101           {
102             ERROR(EINVAL, "unsupported block size");
103             return -1;
104           }
105
106         vol->vlen = rec.sbBlkCount;
107
108         if (l_readpm(vol) < 0)
109           return -1;
110       }
111       break;
112
113     case 0x4c4b:  /* bootable floppy */
114       vol->pnum = 0;
115       break;
116
117     default:  /* non-bootable floppy or something else */
118
119       /* some miscreant media may also be partitioned;
120          we attempt to read a partition map, but ignore any failure */
121
122       if (l_readpm(vol) < 0)
123         vol->pnum = 0;
124     }
125
126   return 0;
127 }
128
129 /*
130  * NAME:        low->readpm()
131  * DESCRIPTION: read the partition map and locate an HFS volume
132  */
133 int l_readpm(hfsvol *vol)
134 {
135   block b;
136   unsigned char *ptr;
137   Partition map;
138   unsigned long bnum;
139   int pnum;
140
141   bnum = 1;
142   pnum = vol->pnum;
143
144   for (;;)
145     {
146       if (b_readlb(vol, bnum, &b) < 0)
147         return -1;
148
149       ptr = b;
150
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);
156
157       memcpy(map.pmPartName, ptr, 32);
158       map.pmPartName[32] = 0;
159       ptr += 32;
160
161       memcpy(map.pmParType, ptr, 32);
162       map.pmParType[32] = 0;
163       ptr += 32;
164
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);
175
176       memcpy(map.pmProcessor, ptr, 16);
177       map.pmProcessor[16] = 0;
178       ptr += 16;
179
180       if (map.pmSig == 0x5453)
181         {
182           /* old partition map sig */
183
184           ERROR(EINVAL, "unsupported partition map signature");
185           return -1;
186         }
187
188       if (map.pmSig != 0x504d)
189         {
190           ERROR(EINVAL, "bad partition map");
191           return -1;
192         }
193
194       if (strcmp((char *) map.pmParType, "Apple_HFS") == 0 && --pnum == 0)
195         {
196           if (map.pmLgDataStart != 0)
197             {
198               ERROR(EINVAL, "unsupported start of partition logical data");
199               return -1;
200             }
201
202           vol->vstart = map.pmPyPartStart;
203           vol->vlen   = map.pmPartBlkCnt;
204
205           return 0;
206         }
207
208       if (bnum >= map.pmMapBlkCnt)
209         {
210           ERROR(EINVAL, "can't find HFS partition");
211           return -1;
212         }
213
214       ++bnum;
215     }
216 }
217
218 /*
219  * NAME:        low->readmdb()
220  * DESCRIPTION: read the master directory block into memory
221  */
222 int l_readmdb(hfsvol *vol)
223 {
224   block b;
225   unsigned char *ptr = b;
226   MDB *mdb = &vol->mdb;
227   hfsfile *ext = &vol->ext.f;
228   hfsfile *cat = &vol->cat.f;
229   int i;
230
231   if (b_readlb(vol, 2, &b) < 0)
232     return -1;
233
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);
247
248   d_fetchs(&ptr, mdb->drVN, sizeof(mdb->drVN));
249
250   if (ptr - b != 64)
251     abort();
252
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);
261
262   for (i = 0; i < 8; ++i)
263     d_fetchl(&ptr, &mdb->drFndrInfo[i]);
264
265   if (ptr - b != 124)
266     abort();
267
268   d_fetchw(&ptr, (short *) &mdb->drVCSize);
269   d_fetchw(&ptr, (short *) &mdb->drVBMCSize);
270   d_fetchw(&ptr, (short *) &mdb->drCtlCSize);
271
272   d_fetchl(&ptr, (long *) &mdb->drXTFlSize);
273
274   for (i = 0; i < 3; ++i)
275     {
276       d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrStABN);
277       d_fetchw(&ptr, (short *) &mdb->drXTExtRec[i].xdrNumABlks);
278     }
279
280   if (ptr - b != 146)
281     abort();
282
283   d_fetchl(&ptr, (long *) &mdb->drCTFlSize);
284
285   for (i = 0; i < 3; ++i)
286     {
287       d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrStABN);
288       d_fetchw(&ptr, (short *) &mdb->drCTExtRec[i].xdrNumABlks);
289     }
290
291   if (ptr - b != 162)
292     abort();
293
294   vol->lpa = mdb->drAlBlkSiz / HFS_BLOCKSZ;
295
296   /* extents pseudo-file structs */
297
298   ext->vol   = vol;
299   ext->parid = 0;
300   strcpy(ext->name, "extents overflow");
301
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;
319
320   memcpy(ext->cat.u.fil.filExtRec, mdb->drXTExtRec, sizeof(ExtDataRec));
321   for (i = 0; i < 3; ++i)
322     {
323       ext->cat.u.fil.filRExtRec[i].xdrStABN    = 0;
324       ext->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
325     }
326   f_selectfork(ext, 0);
327
328   ext->clump = mdb->drXTClpSiz;
329   ext->flags = 0;
330
331   ext->prev = ext->next = 0;
332
333   /* catalog pseudo-file structs */
334
335   cat->vol   = vol;
336   cat->parid = 0;
337   strcpy(cat->name, "catalog");
338
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;
356
357   memcpy(cat->cat.u.fil.filExtRec, mdb->drCTExtRec, sizeof(ExtDataRec));
358   for (i = 0; i < 3; ++i)
359     {
360       cat->cat.u.fil.filRExtRec[i].xdrStABN    = 0;
361       cat->cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
362     }
363   f_selectfork(cat, 0);
364
365   cat->clump = mdb->drCTClpSiz;
366   cat->flags = 0;
367
368   cat->prev = cat->next = 0;
369
370   return 0;
371 }
372
373 /*
374  * NAME:        low->writemdb()
375  * DESCRIPTION: write the master directory block to disk
376  */
377 int l_writemdb(hfsvol *vol)
378 {
379   block b;
380   unsigned char *ptr = b;
381   MDB *mdb = &vol->mdb;
382   hfsfile *ext = &vol->ext.f;
383   hfsfile *cat = &vol->cat.f;
384   int i;
385
386   memset(&b, 0, sizeof(b));
387
388   mdb->drXTFlSize = ext->cat.u.fil.filPyLen;
389   mdb->drXTClpSiz = ext->clump;
390   memcpy(mdb->drXTExtRec, ext->cat.u.fil.filExtRec, sizeof(ExtDataRec));
391
392   mdb->drCTFlSize = cat->cat.u.fil.filPyLen;
393   mdb->drCTClpSiz = cat->clump;
394   memcpy(mdb->drCTExtRec, cat->cat.u.fil.filExtRec, sizeof(ExtDataRec));
395
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));
410
411   if (ptr - b != 64)
412     abort();
413
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);
422
423   for (i = 0; i < 8; ++i)
424     d_storel(&ptr, mdb->drFndrInfo[i]);
425
426   if (ptr - b != 124)
427     abort();
428
429   d_storew(&ptr, mdb->drVCSize);
430   d_storew(&ptr, mdb->drVBMCSize);
431   d_storew(&ptr, mdb->drCtlCSize);
432   d_storel(&ptr, mdb->drXTFlSize);
433
434   for (i = 0; i < 3; ++i)
435     {
436       d_storew(&ptr, mdb->drXTExtRec[i].xdrStABN);
437       d_storew(&ptr, mdb->drXTExtRec[i].xdrNumABlks);
438     }
439
440   if (ptr - b != 146)
441     abort();
442
443   d_storel(&ptr, mdb->drCTFlSize);
444
445   for (i = 0; i < 3; ++i)
446     {
447       d_storew(&ptr, mdb->drCTExtRec[i].xdrStABN);
448       d_storew(&ptr, mdb->drCTExtRec[i].xdrNumABlks);
449     }
450
451   if (ptr - b != 162)
452     abort();
453
454   if (b_writelb(vol, 2, &b) < 0)
455     return -1;
456   if (vol->flags & HFS_UPDATE_ALTMDB)
457     {
458 #ifdef APPLE_HYB
459       /* "write" alternative MDB to memory copy */
460       memcpy(vol->hce->hfs_alt_mdb, &b, sizeof(b));
461 #else
462       if (b_writelb(vol, vol->vlen - 2, &b) < 0)
463         return -1;
464 #endif /* APPLE_HYB */
465     }
466   vol->flags &= ~(HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB);
467
468   return 0;
469 }
470
471 /*
472  * NAME:        low->readvbm()
473  * DESCRIPTION: read the volume bit map into memory
474  */
475 int l_readvbm(hfsvol *vol)
476 {
477   int vbmst = vol->mdb.drVBMSt;
478   int vbmsz = (vol->mdb.drNmAlBlks + 4095) / (unsigned)4096;
479   block *bp;
480
481   if ((int)(vol->mdb.drAlBlSt - vbmst) < vbmsz)
482     {
483       ERROR(EIO, "volume bitmap collides with volume data");
484       return -1;
485     }
486
487   bp = ALLOC(block, vbmsz);
488   if (bp == 0)
489     {
490       ERROR(ENOMEM, 0);
491       return -1;
492     }
493
494   vol->vbm = bp;
495
496   while (vbmsz--)
497     {
498       if (b_readlb(vol, vbmst++, bp++) < 0)
499         {
500           FREE(vol->vbm);
501           vol->vbm = 0;
502
503           return -1;
504         }
505     }
506
507   return 0;
508 }
509
510 /*
511  * NAME:        low->writevbm()
512  * DESCRIPTION: write the volume bit map to disk
513  */
514 int l_writevbm(hfsvol *vol)
515 {
516   int vbmst = vol->mdb.drVBMSt;
517   int vbmsz = (vol->mdb.drNmAlBlks + 4095) / (unsigned)4096;
518   block *bp = vol->vbm;
519
520   while (vbmsz--)
521     {
522       if (b_writelb(vol, vbmst++, bp++) < 0)
523         return -1;
524     }
525
526   vol->flags &= ~HFS_UPDATE_VBM;
527
528   return 0;
529 }