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 /* @(#)hfs.c	1.9 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 /* APPLE_HYB James Pearson j.pearson@ps.ucl.ac.uk 16/7/97 */
34 
35 #include <mconfig.h>
36 #include <stdxlib.h>
37 #include <unixstd.h>
38 #include <fctldefs.h>
39 #include <errno.h>
40 #include <strdefs.h>
41 #include <ctype.h>
42 #include <statdefs.h>
43 
44 #include "internal.h"
45 #include "data.h"
46 #include "block.h"
47 #include "low.h"
48 #include "file.h"
49 #include "btree.h"
50 #include "node.h"
51 #include "record.h"
52 #include "volume.h"
53 #include "hfs.h"
54 
55 /* High-Level Volume Routines ============================================== */
56 
57 /*
58  * NAME:	hfs->mount()
59  * DESCRIPTION:	open an HFS volume; return volume descriptor or 0 (error)
60  */
61 #ifdef APPLE_HYB
hfs_mount(hce_mem * hce,int pnum,int flags)62 hfsvol *hfs_mount(hce_mem *hce, int pnum, int flags)
63 #else
64 hfsvol *hfs_mount(char *path, int pnum, int flags)
65 #endif /* APPLE_HYB */
66 {
67 #ifndef APPLE_HYB
68   struct stat dev;
69 #endif
70   hfsvol *vol = 0;
71 
72 #ifndef APPLE_HYB
73   /* see if the volume is already mounted */
74 
75   if (stat(path, &dev) >= 0)
76     {
77       struct stat mdev;
78       hfsvol *check;
79 
80       for (check = hfs_mounts; check; check = check->next)
81 	{
82 	  if (fstat(check->fd, &mdev) >= 0 &&
83 	      mdev.st_dev == dev.st_dev &&
84 	      mdev.st_ino == dev.st_ino &&
85 	      (check->pnum == 0 || check->pnum == pnum))
86 	    {
87 	      /* verify compatible read/write mode */
88 
89 	      if (((check->flags & HFS_READONLY) &&
90 		   ! (flags & O_WRONLY)) ||
91 		  (! (check->flags & HFS_READONLY) &&
92 		   (flags & (O_WRONLY | O_RDWR))))
93 		{
94 		  vol = check;
95 		  break;
96 		}
97 	    }
98 	}
99     }
100 #endif /* APPLE_HYB */
101   if (vol == 0)
102     {
103       vol = ALLOC(hfsvol, 1);
104       if (vol == 0)
105 	{
106 	  ERROR(ENOMEM, 0);
107 	  return 0;
108 	}
109 
110       vol->flags  = 0;
111       vol->pnum   = pnum;
112       vol->vstart = 0;
113       vol->vlen   = 0;
114       vol->lpa    = 0;
115       vol->vbm    = 0;
116       vol->cwd    = HFS_CNID_ROOTDIR;
117 
118       vol->refs   = 0;
119       vol->files  = 0;
120       vol->dirs   = 0;
121       vol->prev   = 0;
122       vol->next   = 0;
123 
124       vol->ext.map     = 0;
125       vol->ext.mapsz   = 0;
126       vol->ext.flags   = 0;
127       vol->ext.compare = r_compareextkeys;
128 
129       vol->cat.map     = 0;
130       vol->cat.mapsz   = 0;
131       vol->cat.flags   = 0;
132       vol->cat.compare = r_comparecatkeys;
133 
134       /* open and lock the device */
135 
136 #ifdef APPLE_HYB
137       vol->fd = 3;			/* any +ve number will do? */
138       vol->hce = hce;			/* store the extra with the vol info */
139 #else
140       if (flags & (O_WRONLY | O_RDWR))
141 	{
142 	  vol->fd = open(path, O_RDWR);
143 	  if (vol->fd >= 0 && l_lockvol(vol) < 0)
144 	    {
145 	      close(vol->fd);
146 	      vol->fd = -2;
147 	    }
148 	}
149 
150       if (! (flags & (O_WRONLY | O_RDWR)) ||
151 	  (vol->fd < 0 &&
152 	   (errno == EROFS || errno == EACCES || errno == EAGAIN) &&
153 	   (flags & O_RDWR)))
154 	{
155 	  vol->flags |= HFS_READONLY;
156 	  vol->fd = open(path, O_RDONLY);
157 	  if (vol->fd >= 0 && l_lockvol(vol) < 0)
158 	    {
159 	      close(vol->fd);
160 	      vol->fd = -2;
161 	    }
162 	}
163 
164       if (vol->fd < 0)
165 	{
166 	  if (vol->fd != -2)
167 	    ERROR(errno, "error opening device");
168 
169 	  v_destruct(vol);
170 
171 	  return 0;
172 	}
173 #endif /* APPLE_HYB */
174 
175       /* find out what kind of media this is and read the MDB */
176 
177       if (l_readblock0(vol) < 0 ||
178 	  l_readmdb(vol) < 0)
179 	{
180 #ifndef APPLE_HYB
181 	  close(vol->fd);
182 	  v_destruct(vol);
183 #endif /* APPLE_HYB */
184 	  return 0;
185 	}
186 
187       /* verify this is an HFS volume */
188 
189       if (vol->mdb.drSigWord != 0x4244)
190 	{
191 #ifndef APPLE_HYB
192 	  close(vol->fd);
193 #endif /* APPLE_HYB */
194 	  v_destruct(vol);
195 
196 	  ERROR(EINVAL, "not a Macintosh HFS volume");
197 	  return 0;
198 	}
199 
200       /* do minimal consistency checks */
201 
202       if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0)
203 	{
204 #ifndef APPLE_HYB
205 	  close(vol->fd);
206 #endif /* APPLE_HYB */
207 	  v_destruct(vol);
208 
209 	  ERROR(EINVAL, "bad volume allocation block size");
210 	  return 0;
211 	}
212 
213       if (vol->vlen == 0)
214 	vol->vlen = vol->mdb.drAlBlSt +
215 	  vol->mdb.drNmAlBlks * (vol->mdb.drAlBlkSiz / HFS_BLOCKSZ) + 2;
216 
217       /* read the volume bitmap and extents/catalog B*-tree headers */
218 
219       if (l_readvbm(vol) < 0 ||
220 	  bt_readhdr(&vol->ext) < 0 ||
221 	  bt_readhdr(&vol->cat) < 0)
222 	{
223 #ifndef APPLE_HYB
224 	  close(vol->fd);
225 #endif /* APPLE_HYB */
226 	  v_destruct(vol);
227 	  return 0;
228 	}
229 
230       if (! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED))
231 	{
232 	  /* volume was not cleanly unmounted; scavenge free-space */
233 
234 	  if (v_scavenge(vol) < 0)
235 	    {
236 #ifndef APPLE_HYB
237 	      close(vol->fd);
238 #endif /* APPLE_HYB */
239 	      v_destruct(vol);
240 	      return 0;
241 	    }
242 	}
243 
244       if (vol->flags & HFS_READONLY)
245 	vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
246       else
247 	vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED;
248 
249       vol->prev = 0;
250       vol->next = hfs_mounts;
251 
252       if (hfs_mounts)
253 	hfs_mounts->prev = vol;
254 
255       hfs_mounts = vol;
256     }
257 
258   ++vol->refs;
259 
260   return hfs_curvol = vol;
261 }
262 
263 /*
264  * NAME:	hfs->flush()
265  * DESCRIPTION:	flush all pending changes to an HFS volume
266  */
hfs_flush(hfsvol * vol)267 int hfs_flush(hfsvol *vol)
268 {
269   hfsfile *file;
270 
271   if (v_getvol(&vol) < 0)
272     return -1;
273 
274   for (file = vol->files; file; file = file->next)
275     {
276       if (f_flush(file) < 0)
277 	return -1;
278     }
279 
280   if (v_flush(vol, 0) < 0)
281     return -1;
282 
283   return 0;
284 }
285 
286 /*
287  * NAME:	hfs->flushall()
288  * DESCRIPTION:	flush all pending changes to all mounted HFS volumes
289  */
hfs_flushall()290 void hfs_flushall()
291 {
292   hfsvol *vol;
293 
294   for (vol = hfs_mounts; vol; vol = vol->next)
295     hfs_flush(vol);
296 }
297 
298 /*
299  * NAME:	hfs->umount()
300  * DESCRIPTION:	close an HFS volume
301  */
302 #ifdef APPLE_HYB
303 /* extra argument used to alter the position of the extents/catalog files */
hfs_umount(hfsvol * vol,long end,long locked)304 int hfs_umount(hfsvol *vol, long end, long locked)
305 #else
306 int hfs_umount(hfsvol *vol)
307 #endif /* APPLE_HYB */
308 {
309   int result = 0;
310 
311   if (v_getvol(&vol) < 0)
312     return -1;
313 
314   if (--vol->refs)
315     return v_flush(vol, 0);
316 
317   /* close all open files and directories */
318 
319   while (vol->files)
320 #ifdef APPLE_HYB
321     hfs_close(vol->files, 0, 0);
322 #else
323     hfs_close(vol->files);
324 #endif /* APPLE_HYB */
325 
326   while (vol->dirs)
327     hfs_closedir(vol->dirs);
328 
329 #ifdef APPLE_HYB
330   if (end)
331   {
332 	/*  move extents and catalog to end of volume ... */
333   	long vbmsz = (vol->vlen / vol->lpa + 4095) / 4096;
334 
335 	/* we are adding this "files" to the end of the ISO volume,
336 	   so calculate this address in HFS speak ... */
337 /*	end -= vol->mdb.drAlBlSt; */
338 	end -= (vol->mdb.drAlBlSt + vol->hce->hfs_map_size);
339 	end /= vol->lpa;
340 
341 	/* catalog file ... */
342 	vol->ext.f.cat.u.fil.filExtRec[0].xdrStABN = end;
343  	vol->mdb.drXTExtRec[0].xdrStABN = end;
344 
345 	/* move postition to start of extents file */
346 	end += vol->cat.f.cat.u.fil.filExtRec[0].xdrStABN;
347 
348 	/* extents file ... */
349 	vol->cat.f.cat.u.fil.filExtRec[0].xdrStABN = end;
350 	vol->mdb.drCTExtRec[0].xdrStABN = end;
351 
352 	/* the volume bitmap is wrong as we have "moved" files
353 	   about - simple just set the whole lot (it's a readonly volume
354 	   anyway!) */
355 	memset(vol->vbm, 0xff, vbmsz*HFS_BLOCKSZ);
356 
357 	/* set the free blocks to zero */
358 	vol->mdb.drFreeBks = 0;
359 
360 	/* flag changes for flushing later */
361 	vol->flags |= HFS_UPDATE_VBM;
362 	vol->flags |= HFS_UPDATE_MDB;
363 	vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
364 	if (locked) {
365 	    vol->mdb.drAtrb |= HFS_ATRB_SLOCKED;
366 	}
367 	vol->ext.flags |= HFS_UPDATE_BTHDR;
368 	vol->cat.flags |= HFS_UPDATE_BTHDR;
369   }
370 #endif /* APPLE_HYB */
371 
372   if (v_flush(vol, 1) < 0)
373     result = -1;
374 
375 #ifndef APPLE_HYB
376   if (close(vol->fd) < 0 && result == 0)
377     {
378       ERROR(errno, "error closing device");
379       result = -1;
380     }
381 #endif /* APPLE_HYB */
382 
383   if (vol->prev)
384     vol->prev->next = vol->next;
385   if (vol->next)
386     vol->next->prev = vol->prev;
387 
388   if (vol == hfs_mounts)
389     hfs_mounts = vol->next;
390   if (vol == hfs_curvol)
391     hfs_curvol = 0;
392 
393   v_destruct(vol);
394 
395   return result;
396 }
397 
398 /*
399  * NAME:	hfs->umountall()
400  * DESCRIPTION:	unmount all mounted volumes
401  */
hfs_umountall()402 void hfs_umountall()
403 {
404   while (hfs_mounts)
405 #ifdef APPLE_HYB
406     continue;
407 #else
408     hfs_umount(hfs_mounts);
409 #endif /* APPLE_HYB */
410 }
411 
412 /*
413  * NAME:	hfs->getvol()
414  * DESCRIPTION:	return a pointer to a mounted volume
415  */
hfs_getvol(char * name)416 hfsvol *hfs_getvol(char *name)
417 {
418   hfsvol *vol;
419 
420   if (name == 0)
421     return hfs_curvol;
422 
423   for (vol = hfs_mounts; vol; vol = vol->next)
424     {
425       if (d_relstring(name, vol->mdb.drVN) == 0)
426 	return vol;
427     }
428 
429   return 0;
430 }
431 
432 /*
433  * NAME:	hfs->setvol()
434  * DESCRIPTION:	change the current volume
435  */
hfs_setvol(hfsvol * vol)436 void hfs_setvol(hfsvol *vol)
437 {
438   hfs_curvol = vol;
439 }
440 
441 /*
442  * NAME:	hfs->vstat()
443  * DESCRIPTION:	return volume statistics
444  */
hfs_vstat(hfsvol * vol,hfsvolent * ent)445 int hfs_vstat(hfsvol *vol, hfsvolent *ent)
446 {
447   if (v_getvol(&vol) < 0)
448     return -1;
449 
450   strcpy(ent->name, vol->mdb.drVN);
451 
452   ent->flags     = (vol->flags & HFS_READONLY) ? HFS_ISLOCKED : 0;
453   ent->totbytes  = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;
454   ent->freebytes = vol->mdb.drFreeBks  * vol->mdb.drAlBlkSiz;
455   ent->crdate    = d_toutime(vol->mdb.drCrDate);
456   ent->mddate    = d_toutime(vol->mdb.drLsMod);
457 
458   return 0;
459 }
460 
461 /*
462  * NAME:	hfs->format()
463  * DESCRIPTION:	write a new filesystem
464  */
465 #ifdef APPLE_HYB
hfs_format(hce_mem * hce,int pnum,char * vname)466 int hfs_format(hce_mem *hce, int pnum, char *vname)
467 #else
468 int hfs_format(char *path, int pnum, char *vname)
469 #endif /* APPLE_HYB */
470 {
471   hfsvol vol;
472   btree *ext = &vol.ext;
473   btree *cat = &vol.cat;
474   unsigned int vbmsz;
475   int i, result = 0;
476   block vbm[16];
477   char *map;
478 
479   if (strchr(vname, ':'))
480     {
481       ERROR(EINVAL, "volume name may not contain colons");
482       return -1;
483     }
484 
485   i = strlen(vname);
486   if (i < 1 || i > HFS_MAX_VLEN)
487     {
488       ERROR(EINVAL, "volume name must be 1-27 chars");
489       return -1;
490     }
491 
492   vol.flags  = 0;
493   vol.pnum   = pnum;
494   vol.vstart = 0;
495   vol.vlen   = 0;
496   vol.lpa    = 0;
497   vol.vbm    = vbm;
498   vol.cwd    = HFS_CNID_ROOTDIR;
499 
500   vol.refs   = 0;
501   vol.files  = 0;
502   vol.dirs   = 0;
503   vol.prev   = 0;
504   vol.next   = 0;
505 
506 #ifndef APPLE_HYB
507   vol.fd = open(path, O_RDWR);
508   if (vol.fd < 0)
509     {
510       ERROR(errno, "error opening device for writing");
511       return -1;
512     }
513 
514   if (l_lockvol(&vol) < 0)
515     {
516       close(vol.fd);
517       return -1;
518     }
519 #endif /* APPLE_HYB */
520   if (pnum > 0)
521     {
522       if (l_readpm(&vol) < 0)
523 	{
524 	  close(vol.fd);
525 	  return -1;
526 	}
527     }
528   else  /* determine size of entire device */
529     {
530 #ifdef APPLE_HYB
531       vol.vlen = hce->hfs_vol_size;
532 #else
533       unsigned long low, high, mid;
534       block b;
535 
536       for (low = 0, high = 2879; b_readlb(&vol, high, &b) >= 0; high *= 2)
537 	low = high;
538 
539       while (low < high - 1)
540 	{
541 	  mid = (low + high) / 2;
542 
543 	  if (b_readlb(&vol, mid, &b) < 0)
544 	    high = mid;
545 	  else
546 	    low = mid;
547 	}
548 
549       vol.vlen = low + 1;
550 #endif /* APPLE_HYB */
551     }
552 
553   if (vol.vlen < 800 * 1024 / HFS_BLOCKSZ)
554     {
555 #ifndef APPLE_HYB
556       close(vol.fd);
557 #endif /* APPLE_HYB */
558 
559       ERROR(EINVAL, "volume size must be >= 800K");
560       return -1;
561     }
562 
563   /* initialize volume geometry */
564 
565 #ifdef APPLE_HYB
566   /* force lpa to be a multiple of 4 (i.e. 2048/512) - as calculated
567      earlier */
568   vol.lpa = hce->Csize/HFS_BLOCKSZ;
569 #else
570   vol.lpa = 1 + vol.vlen / 65536;
571 #endif /* APPLE_HYB */
572 
573   vbmsz = (vol.vlen / vol.lpa + 4095) / 4096;
574 
575   vol.mdb.drSigWord  = 0x4244;
576   vol.mdb.drCrDate   = d_tomtime(time(0));
577   vol.mdb.drLsMod    = vol.mdb.drCrDate;
578   vol.mdb.drAtrb     = 0;
579   vol.mdb.drNmFls    = 0;
580   vol.mdb.drVBMSt    = 3;
581   vol.mdb.drAllocPtr = 0;
582   vol.mdb.drNmAlBlks = (vol.vlen - 5 - vbmsz) / vol.lpa;
583   vol.mdb.drAlBlkSiz = vol.lpa * HFS_BLOCKSZ;
584   vol.mdb.drClpSiz   = vol.mdb.drAlBlkSiz * 4;
585   vol.mdb.drAlBlSt   = 3 + vbmsz;
586 #ifdef APPLE_HYB
587   /* round up start block to a muliple of lpa - important later */
588 /*vol.mdb.drAlBlSt   = ((vol.mdb.drAlBlSt + vol.lpa -  1) / vol.lpa) * vol.lpa;
589 */
590   /* take in accout alignment of files wrt HFS volume start i.e we want
591      drAlBlSt plus hfs_map_size to me a multiple of lpa */
592   vol.mdb.drAlBlSt   = ((vol.mdb.drAlBlSt + hce->hfs_map_size + vol.lpa -  1) / vol.lpa) * vol.lpa;
593   vol.mdb.drAlBlSt   -= hce->hfs_map_size;
594 #endif /* APPLE_HYB */
595   vol.mdb.drNxtCNID  = HFS_CNID_ROOTDIR;  /* modified later */
596   vol.mdb.drFreeBks  = vol.mdb.drNmAlBlks;
597 
598   strcpy(vol.mdb.drVN, vname);
599 
600   vol.mdb.drVolBkUp  = 0;
601   vol.mdb.drVSeqNum  = 0;
602   vol.mdb.drWrCnt    = 0;
603   vol.mdb.drXTClpSiz = vol.mdb.drNmAlBlks / 128 * vol.mdb.drAlBlkSiz;
604 #ifdef APPLE_HYB
605   /* adjust size of extents/catalog upwards as we may have rounded up
606      allocation size */
607   i = 1 + vol.vlen / 65536;
608 
609   vol.mdb.drXTClpSiz = (vol.mdb.drXTClpSiz * vol.lpa) / i;
610 
611   /* round up to lpa size */
612   vol.mdb.drXTClpSiz = ((vol.mdb.drXTClpSiz + vol.mdb.drAlBlkSiz - 1) /
613 				vol.mdb.drAlBlkSiz) * vol.mdb.drAlBlkSiz;
614 
615   /* ignore above, use what we have already calculated ... */
616   vol.mdb.drXTClpSiz = hce->XTCsize;
617 
618   /* make Catalog file CTC (default twice) as big - prevents further allocation
619      later which we don't want - this seems to work OK ... */
620 /*vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz * CTC; */
621   vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz * hce->ctc_size;
622 
623   /* we want to put things at the end of the volume later, so we'll
624      cheat here ... shouldn't matter, as we only need the volume read
625      only anyway (we won't be adding files later!) - leave some extra
626      space for the alternative MDB (in the last allocation block) */
627 
628   vol.mdb.drNmAlBlks = vol.mdb.drFreeBks = vol.vlen / vol.lpa - 1;
629 #else
630   vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz;
631 #endif /* APPLE_HYB */
632   vol.mdb.drNmRtDirs = 0;
633   vol.mdb.drFilCnt   = 0;
634   vol.mdb.drDirCnt   = -1;  /* incremented when root folder is created */
635 
636   for (i = 0; i < 8; ++i)
637     vol.mdb.drFndrInfo[i] = 0;
638 
639   vol.mdb.drVCSize   = 0;
640   vol.mdb.drVBMCSize = 0;
641   vol.mdb.drCtlCSize = 0;
642 
643   vol.mdb.drXTFlSize = 0;
644   vol.mdb.drCTFlSize = 0;
645 
646   for (i = 0; i < 3; ++i)
647     {
648       vol.mdb.drXTExtRec[i].xdrStABN    = 0;
649       vol.mdb.drXTExtRec[i].xdrNumABlks = 0;
650 
651       vol.mdb.drCTExtRec[i].xdrStABN    = 0;
652       vol.mdb.drCTExtRec[i].xdrNumABlks = 0;
653     }
654 
655   /* initialize volume bitmap */
656 
657   memset(vol.vbm, 0, sizeof(vbm));
658 
659 #ifdef APPLE_HYB
660   /* We don't want to write anything out at the moment, so we allocate
661      memory to hold the HFS "header" info and extents/catalog files.
662      Any reads/writes from/to these parts of the volume are trapped and
663      stored in memory. */
664 
665   /* blocks up to the first unallocated block == HFS "header" info
666      This will be placed in the first 32kb of the ISO volume later */
667   hce->hfs_hdr_size = vol.mdb.drAlBlSt;
668 
669   /* size of the extents and catalog files. This will be added
670      to the end of the ISO volume later */
671   hce->hfs_ce_size =  vol.mdb.drXTClpSiz + vol.mdb.drCTClpSiz;
672 
673   /* we also allocate space for the Desktop file and the alternative
674      MDB while we're here */
675   FREE(hce->hfs_ce);
676   hce->hfs_ce = ALLOC(unsigned char, (hce->hfs_ce_size + vol.mdb.drClpSiz
677 					+ vol.mdb.drAlBlkSiz));
678 
679   /* allocate memory for the map and hdr */
680   FREE(hce->hfs_map);
681   hce->hfs_map = ALLOC(unsigned char, ((hce->hfs_hdr_size + hce->hfs_map_size)
682 			*HFS_BLOCKSZ));
683 
684   if (hce->hfs_ce == 0 || hce->hfs_map == 0)
685     {
686       ERROR(ENOMEM, 0);
687       result = -1;
688     }
689 
690   /* hfs_hdr is immediately after the hfs_map */
691   hce->hfs_hdr = hce->hfs_map + hce->hfs_map_size*HFS_BLOCKSZ;
692 
693   /* size needed in HFS_BLOCKSZ blocks for later use */
694   hce->hfs_ce_size /= HFS_BLOCKSZ;
695 
696   /* note size of Desktop file */
697   hce->hfs_dt_size = vol.mdb.drClpSiz/HFS_BLOCKSZ;
698 
699   /* total size of catalog/extents and desktop */
700   hce->hfs_tot_size = hce->hfs_ce_size + hce->hfs_dt_size;
701 
702   /* alternative MDB in the last alocation block */
703   hce->hfs_alt_mdb = hce->hfs_ce + hce->hfs_tot_size*HFS_BLOCKSZ;
704 
705   /* add the MDB to the total size */
706   hce->hfs_tot_size += vol.lpa;
707 
708   /* store this info in the volume info */
709   vol.hce = hce;
710 
711 #endif /* APPLE_HYB */
712 
713   /* create extents overflow file */
714 
715   ext->f.vol   = &vol;
716   ext->f.parid = 0;
717   strcpy(ext->f.name, "extents overflow");
718 
719   ext->f.cat.cdrType          = cdrFilRec;
720   /* ext->f.cat.cdrResrv2 */
721   ext->f.cat.u.fil.filFlags   = 0;
722   ext->f.cat.u.fil.filTyp     = 0;
723   /* ext->f.cat.u.fil.filUsrWds */
724   ext->f.cat.u.fil.filFlNum   = HFS_CNID_EXT;
725   ext->f.cat.u.fil.filStBlk   = 0;
726   ext->f.cat.u.fil.filLgLen   = 0;
727   ext->f.cat.u.fil.filPyLen   = 0;
728   ext->f.cat.u.fil.filRStBlk  = 0;
729   ext->f.cat.u.fil.filRLgLen  = 0;
730   ext->f.cat.u.fil.filRPyLen  = 0;
731   ext->f.cat.u.fil.filCrDat   = vol.mdb.drCrDate;
732   ext->f.cat.u.fil.filMdDat   = vol.mdb.drLsMod;
733   ext->f.cat.u.fil.filBkDat   = 0;
734   /* ext->f.cat.u.fil.filFndrInfo */
735   ext->f.cat.u.fil.filClpSize = 0;
736 
737   for (i = 0; i < 3; ++i)
738     {
739       ext->f.cat.u.fil.filExtRec[i].xdrStABN     = 0;
740       ext->f.cat.u.fil.filExtRec[i].xdrNumABlks  = 0;
741 
742       ext->f.cat.u.fil.filRExtRec[i].xdrStABN    = 0;
743       ext->f.cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
744     }
745   /* ext->f.cat.u.fil.filResrv */
746   f_selectfork(&ext->f, 0);
747 
748   ext->f.clump = vol.mdb.drXTClpSiz;
749   ext->f.flags = 0;
750 
751   ext->f.prev = ext->f.next = 0;
752 
753   n_init(&ext->hdrnd, ext, ndHdrNode, 0);
754 
755   ext->hdrnd.nnum       = 0;
756   ext->hdrnd.nd.ndNRecs = 3;
757   ext->hdrnd.roff[1]    = 0x078;
758   ext->hdrnd.roff[2]    = 0x0f8;
759   ext->hdrnd.roff[3]    = 0x1f8;
760 
761   memset(HFS_NODEREC(ext->hdrnd, 1), 0, 128);
762 
763   ext->hdr.bthDepth    = 0;
764   ext->hdr.bthRoot     = 0;
765   ext->hdr.bthNRecs    = 0;
766   ext->hdr.bthFNode    = 0;
767   ext->hdr.bthLNode    = 0;
768   ext->hdr.bthNodeSize = HFS_BLOCKSZ;
769   ext->hdr.bthKeyLen   = 0x07;
770   ext->hdr.bthNNodes   = 0;
771   ext->hdr.bthFree     = 0;
772   for (i = 0; i < 76; ++i)
773     ext->hdr.bthResv[i] = 0;
774 
775   map = ALLOC(char, HFS_MAP1SZ);
776   if (map == 0)
777     {
778       if (result == 0)
779 	{
780 	  ERROR(ENOMEM, 0);
781 	  result = -1;
782 	}
783     }
784   else
785     {
786       memset(map, 0, HFS_MAP1SZ);
787       BMSET(map, 0);
788     }
789 
790   ext->map     = map;
791   ext->mapsz   = HFS_MAP1SZ;
792   ext->flags   = HFS_UPDATE_BTHDR;
793   ext->compare = r_compareextkeys;
794 
795   if (result == 0 && bt_space(ext, 1) < 0)
796     result = -1;
797 
798   --ext->hdr.bthFree;
799 
800   /* create catalog file */
801 
802   cat->f.vol   = &vol;
803   cat->f.parid = 0;
804   strcpy(cat->f.name, "catalog");
805 
806   cat->f.cat.cdrType          = cdrFilRec;
807   /* cat->f.cat.cdrResrv2 */
808   cat->f.cat.u.fil.filFlags   = 0;
809   cat->f.cat.u.fil.filTyp     = 0;
810   /* cat->f.cat.u.fil.filUsrWds */
811   cat->f.cat.u.fil.filFlNum   = HFS_CNID_CAT;
812   cat->f.cat.u.fil.filStBlk   = 0;
813   cat->f.cat.u.fil.filLgLen   = 0;
814   cat->f.cat.u.fil.filPyLen   = 0;
815   cat->f.cat.u.fil.filRStBlk  = 0;
816   cat->f.cat.u.fil.filRLgLen  = 0;
817   cat->f.cat.u.fil.filRPyLen  = 0;
818   cat->f.cat.u.fil.filCrDat   = vol.mdb.drCrDate;
819   cat->f.cat.u.fil.filMdDat   = vol.mdb.drLsMod;
820   cat->f.cat.u.fil.filBkDat   = 0;
821   /* cat->f.cat.u.fil.filFndrInfo */
822   cat->f.cat.u.fil.filClpSize = 0;
823 
824   for (i = 0; i < 3; ++i)
825     {
826       cat->f.cat.u.fil.filExtRec[i].xdrStABN     = 0;
827       cat->f.cat.u.fil.filExtRec[i].xdrNumABlks  = 0;
828 
829       cat->f.cat.u.fil.filRExtRec[i].xdrStABN    = 0;
830       cat->f.cat.u.fil.filRExtRec[i].xdrNumABlks = 0;
831     }
832   /* cat->f.cat.u.fil.filResrv */
833   f_selectfork(&cat->f, 0);
834 
835   cat->f.clump = vol.mdb.drCTClpSiz;
836   cat->f.flags = 0;
837 
838   cat->f.prev = cat->f.next = 0;
839 
840   n_init(&cat->hdrnd, cat, ndHdrNode, 0);
841 
842   cat->hdrnd.nnum       = 0;
843   cat->hdrnd.nd.ndNRecs = 3;
844   cat->hdrnd.roff[1]    = 0x078;
845   cat->hdrnd.roff[2]    = 0x0f8;
846   cat->hdrnd.roff[3]    = 0x1f8;
847 
848   memset(HFS_NODEREC(cat->hdrnd, 1), 0, 128);
849 
850   cat->hdr.bthDepth    = 0;
851   cat->hdr.bthRoot     = 0;
852   cat->hdr.bthNRecs    = 0;
853   cat->hdr.bthFNode    = 0;
854   cat->hdr.bthLNode    = 0;
855   cat->hdr.bthNodeSize = HFS_BLOCKSZ;
856   cat->hdr.bthKeyLen   = 0x25;
857   cat->hdr.bthNNodes   = 0;
858   cat->hdr.bthFree     = 0;
859   for (i = 0; i < 76; ++i)
860     cat->hdr.bthResv[i] = 0;
861 
862   map = ALLOC(char, HFS_MAP1SZ);
863   if (map == 0)
864     {
865       if (result == 0)
866 	{
867 	  ERROR(ENOMEM, 0);
868 	  result = -1;
869 	}
870     }
871   else
872     {
873       memset(map, 0, HFS_MAP1SZ);
874       BMSET(map, 0);
875     }
876 
877   cat->map     = map;
878   cat->mapsz   = HFS_MAP1SZ;
879   cat->flags   = HFS_UPDATE_BTHDR;
880   cat->compare = r_comparecatkeys;
881 
882   if (result == 0 && bt_space(cat, 1) < 0)
883     result = -1;
884 
885   --cat->hdr.bthFree;
886 
887   /* create root folder */
888 
889   if (result == 0 && v_newfolder(&vol, HFS_CNID_ROOTPAR, vname) < 0)
890     result = -1;
891 
892   vol.mdb.drNxtCNID = 16;
893 
894   /* finish up */
895 
896   if (result == 0)
897     {
898       block b;
899 
900       /* write boot blocks */
901 
902       memset(&b, 0, sizeof(b));
903       b_writelb(&vol, 0, &b);
904       b_writelb(&vol, 1, &b);
905 
906       /* flush other disk state */
907 
908       vol.flags |= HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB | HFS_UPDATE_VBM;
909 
910       if (v_flush(&vol, 1) < 0)
911 	result = -1;
912     }
913 #ifndef APPLE_HYB
914   if (close(vol.fd) < 0 && result == 0)
915     {
916       ERROR(errno, "error closing device");
917       result = -1;
918     }
919 #endif /* APPLE_HYB */
920   FREE(vol.ext.map);
921   FREE(vol.cat.map);
922 
923   return result;
924 }
925 
926 /* High-Level Directory Routines =========================================== */
927 
928 /*
929  * NAME:	hfs->chdir()
930  * DESCRIPTION:	change current HFS directory
931  */
hfs_chdir(hfsvol * vol,char * path)932 int hfs_chdir(hfsvol *vol, char *path)
933 {
934   CatDataRec data;
935 
936   if (v_getvol(&vol) < 0 ||
937       v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
938     return -1;
939 
940   if (data.cdrType != cdrDirRec)
941     {
942       ERROR(ENOTDIR, 0);
943       return -1;
944     }
945 
946   vol->cwd = data.u.dir.dirDirID;
947 
948   return 0;
949 }
950 
951 /*
952  * NAME:	hfs->getcwd()
953  * DESCRIPTION:	return the current working directory ID
954  */
hfs_getcwd(hfsvol * vol)955 long hfs_getcwd(hfsvol *vol)
956 {
957   if (v_getvol(&vol) < 0)
958     return 0;
959 
960   return vol->cwd;
961 }
962 
963 /*
964  * NAME:	hfs->setcwd()
965  * DESCRIPTION:	set the current working directory ID
966  */
hfs_setcwd(hfsvol * vol,long id)967 int hfs_setcwd(hfsvol *vol, long id)
968 {
969   if (v_getvol(&vol) < 0)
970     return -1;
971 
972   if (id == vol->cwd)
973     return 0;
974 
975   /* make sure the directory exists */
976 
977   if (v_getdthread(vol, id, 0, 0) <= 0)
978     return -1;
979 
980   vol->cwd = id;
981 
982   return 0;
983 }
984 
985 /*
986  * NAME:	hfs->dirinfo()
987  * DESCRIPTION:	given a directory ID, return its (name and) parent ID
988  */
hfs_dirinfo(hfsvol * vol,long * id,char * name)989 int hfs_dirinfo(hfsvol *vol, long *id, char *name)
990 {
991   CatDataRec thread;
992 
993   if (v_getvol(&vol) < 0 ||
994       v_getdthread(vol, *id, &thread, 0) <= 0)
995     return -1;
996 
997   *id = thread.u.dthd.thdParID;
998 
999   if (name)
1000     strcpy(name, thread.u.dthd.thdCName);
1001 
1002   return 0;
1003 }
1004 
1005 /*
1006  * NAME:	hfs->opendir()
1007  * DESCRIPTION:	prepare to read the contents of a directory
1008  */
hfs_opendir(hfsvol * vol,char * path)1009 hfsdir *hfs_opendir(hfsvol *vol, char *path)
1010 {
1011   hfsdir *dir;
1012   CatKeyRec key;
1013   CatDataRec data;
1014   unsigned char pkey[HFS_CATKEYLEN];
1015 
1016   if (v_getvol(&vol) < 0)
1017     return 0;
1018 
1019   dir = ALLOC(hfsdir, 1);
1020   if (dir == 0)
1021     {
1022       ERROR(ENOMEM, 0);
1023       return 0;
1024     }
1025 
1026   dir->vol = vol;
1027 
1028   if (*path == 0)
1029     {
1030       /* meta-directory containing root dirs from all mounted volumes */
1031 
1032       dir->dirid = 0;
1033       dir->vptr  = hfs_mounts;
1034     }
1035   else
1036     {
1037       if (v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
1038 	{
1039 	  FREE(dir);
1040 	  return 0;
1041 	}
1042 
1043       if (data.cdrType != cdrDirRec)
1044 	{
1045 	  FREE(dir);
1046 	  ERROR(ENOTDIR, 0);
1047 	  return 0;
1048 	}
1049 
1050       dir->dirid = data.u.dir.dirDirID;
1051       dir->vptr  = 0;
1052 
1053       r_makecatkey(&key, dir->dirid, "");
1054       r_packcatkey(&key, pkey, 0);
1055 
1056       if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
1057 	{
1058 	  FREE(dir);
1059 	  return 0;
1060 	}
1061     }
1062 
1063   dir->prev = 0;
1064   dir->next = vol->dirs;
1065 
1066   if (vol->dirs)
1067     vol->dirs->prev = dir;
1068 
1069   vol->dirs = dir;
1070 
1071   return dir;
1072 }
1073 
1074 /*
1075  * NAME:	hfs->readdir()
1076  * DESCRIPTION:	return the next entry in the directory
1077  */
hfs_readdir(hfsdir * dir,hfsdirent * ent)1078 int hfs_readdir(hfsdir *dir, hfsdirent *ent)
1079 {
1080   CatKeyRec key;
1081   CatDataRec data;
1082   unsigned char *ptr;
1083 
1084   if (dir->dirid == 0)
1085     {
1086       hfsvol *vol;
1087       char cname[HFS_MAX_FLEN + 1];
1088 
1089       for (vol = hfs_mounts; vol; vol = vol->next)
1090 	{
1091 	  if (vol == dir->vptr)
1092 	    break;
1093 	}
1094 
1095       if (vol == 0)
1096 	{
1097 	  ERROR(ENOENT, "no more entries");
1098 	  return -1;
1099 	}
1100 
1101       if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, 0) <= 0 ||
1102 	  v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
1103 		      &data, cname, 0) < 0)
1104 	return -1;
1105 
1106       r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);
1107 
1108       dir->vptr = vol->next;
1109 
1110       return 0;
1111     }
1112 
1113   if (dir->n.rnum == -1)
1114     {
1115       ERROR(ENOENT, "no more entries");
1116       return -1;
1117     }
1118 
1119   for (;;)
1120     {
1121       ++dir->n.rnum;
1122 
1123       while (dir->n.rnum >= (int)dir->n.nd.ndNRecs)
1124 	{
1125 	  dir->n.nnum = dir->n.nd.ndFLink;
1126 	  if (dir->n.nnum == 0)
1127 	    {
1128 	      dir->n.rnum = -1;
1129 	      ERROR(ENOENT, "no more entries");
1130 	      return -1;
1131 	    }
1132 
1133 	  if (bt_getnode(&dir->n) < 0)
1134 	    {
1135 	      dir->n.rnum = -1;
1136 	      return -1;
1137 	    }
1138 
1139 	  dir->n.rnum = 0;
1140 	}
1141 
1142       ptr = HFS_NODEREC(dir->n, dir->n.rnum);
1143 
1144       r_unpackcatkey(ptr, &key);
1145 
1146       if (key.ckrParID != dir->dirid)
1147 	{
1148 	  dir->n.rnum = -1;
1149 	  ERROR(ENOENT, "no more entries");
1150 	  return -1;
1151 	}
1152 
1153       r_unpackcatdata(HFS_RECDATA(ptr), &data);
1154 
1155       switch (data.cdrType)
1156 	{
1157 	case cdrDirRec:
1158 	case cdrFilRec:
1159 	  r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
1160 	  return 0;
1161 
1162 	case cdrThdRec:
1163 	case cdrFThdRec:
1164 	  break;
1165 
1166 	default:
1167 	  dir->n.rnum = -1;
1168 
1169 	  ERROR(EIO, "unexpected directory entry found");
1170 	  return -1;
1171 	}
1172     }
1173 }
1174 
1175 /*
1176  * NAME:	hfs->closedir()
1177  * DESCRIPTION:	stop reading a directory
1178  */
hfs_closedir(hfsdir * dir)1179 int hfs_closedir(hfsdir *dir)
1180 {
1181   hfsvol *vol = dir->vol;
1182 
1183   if (dir->prev)
1184     dir->prev->next = dir->next;
1185   if (dir->next)
1186     dir->next->prev = dir->prev;
1187   if (dir == vol->dirs)
1188     vol->dirs = dir->next;
1189 
1190   FREE(dir);
1191 
1192   return 0;
1193 }
1194 
1195 /* High-Level File Routines ================================================ */
1196 
1197 /*
1198  * NAME:	hfs->open()
1199  * DESCRIPTION:	prepare a file for I/O
1200  */
hfs_open(hfsvol * vol,char * path)1201 hfsfile *hfs_open(hfsvol *vol, char *path)
1202 {
1203   hfsfile *file;
1204 
1205   if (v_getvol(&vol) < 0)
1206     return 0;
1207 
1208   file = ALLOC(hfsfile, 1);
1209   if (file == 0)
1210     {
1211       ERROR(ENOMEM, 0);
1212       return 0;
1213     }
1214 
1215   if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, 0) <= 0)
1216     {
1217       FREE(file);
1218       return 0;
1219     }
1220 
1221   if (file->cat.cdrType != cdrFilRec)
1222     {
1223       FREE(file);
1224       ERROR(EISDIR, 0);
1225       return 0;
1226     }
1227 
1228   file->vol   = vol;
1229   file->clump = file->cat.u.fil.filClpSize;
1230   file->flags = 0;
1231 
1232   f_selectfork(file, 0);
1233 
1234   file->prev = 0;
1235   file->next = vol->files;
1236 
1237   if (vol->files)
1238     vol->files->prev = file;
1239 
1240   vol->files = file;
1241 
1242   return file;
1243 }
1244 
1245 /*
1246  * NAME:	hfs->setfork()
1247  * DESCRIPTION:	select file fork for I/O operations
1248  */
hfs_setfork(hfsfile * file,int ffork)1249 int hfs_setfork(hfsfile *file, int ffork)
1250 {
1251   int result = 0;
1252 
1253   if (! (file->vol->flags & HFS_READONLY) &&
1254       f_trunc(file) < 0)
1255     result = -1;
1256 
1257   f_selectfork(file, ffork);
1258 
1259   return result;
1260 }
1261 
1262 /*
1263  * NAME:	hfs->getfork()
1264  * DESCRIPTION:	return the current fork for I/O operations
1265  */
hfs_getfork(hfsfile * file)1266 int hfs_getfork(hfsfile *file)
1267 {
1268   return file->fork != fkData;
1269 }
1270 
1271 /*
1272  * NAME:	hfs->read()
1273  * DESCRIPTION:	read from an open file
1274  */
hfs_read(hfsfile * file,void * buf,unsigned long len)1275 long hfs_read(hfsfile *file, void *buf, unsigned long len)
1276 {
1277   unsigned long *lglen, count;
1278   unsigned char *ptr = buf;
1279 
1280   f_getptrs(file, &lglen, 0, 0);
1281 
1282   if (file->pos + len > *lglen)
1283     len = *lglen - file->pos;
1284 
1285   count = len;
1286   while (count)
1287     {
1288       block b;
1289       unsigned long bnum, offs, chunk;
1290 
1291       bnum  = file->pos / HFS_BLOCKSZ;
1292       offs  = file->pos % HFS_BLOCKSZ;
1293 
1294       chunk = HFS_BLOCKSZ - offs;
1295       if (chunk > count)
1296 	chunk = count;
1297 
1298       if (f_getblock(file, bnum, &b) < 0)
1299 	return -1;
1300 
1301       memcpy(ptr, b + offs, chunk);
1302       ptr += chunk;
1303 
1304       file->pos += chunk;
1305       count     -= chunk;
1306     }
1307 
1308   return len;
1309 }
1310 
1311 /*
1312  * NAME:	hfs->write()
1313  * DESCRIPTION:	write to an open file
1314  */
hfs_write(hfsfile * file,void * buf,unsigned long len)1315 long hfs_write(hfsfile *file, void *buf, unsigned long len)
1316 {
1317   unsigned long *lglen, *pylen, count;
1318   unsigned char *ptr = buf;
1319 
1320   if (file->vol->flags & HFS_READONLY)
1321     {
1322       ERROR(EROFS, 0);
1323       return -1;
1324     }
1325 
1326   f_getptrs(file, &lglen, &pylen, 0);
1327 
1328   count = len;
1329 
1330   /* set flag to update (at least) the modification time */
1331 
1332   if (count)
1333     {
1334       file->cat.u.fil.filMdDat = d_tomtime(time(0));
1335       file->flags |= HFS_UPDATE_CATREC;
1336     }
1337 
1338   while (count)
1339     {
1340       block b;
1341       unsigned long bnum, offs, chunk;
1342 
1343       bnum  = file->pos / HFS_BLOCKSZ;
1344       offs  = file->pos % HFS_BLOCKSZ;
1345 
1346       chunk = HFS_BLOCKSZ - offs;
1347       if (chunk > count)
1348 	chunk = count;
1349 
1350       if (file->pos + chunk > *pylen)
1351 	{
1352 	  if (bt_space(&file->vol->ext, 1) < 0 ||
1353 	      f_alloc(file) < 0)
1354 	    return -1;
1355 	}
1356 #ifndef APPLE_HYB
1357       /* Ignore this part as we are always writing new files to an empty disk
1358 	 i.e. offs will always be 0 */
1359 
1360       if (offs > 0 || chunk < HFS_BLOCKSZ)
1361 	{
1362 	  if (f_getblock(file, bnum, &b) < 0)
1363 	    return -1;
1364 	}
1365 #endif /* APPLE_HYB */
1366       memcpy(b + offs, ptr, chunk);
1367       ptr += chunk;
1368 
1369       if (f_putblock(file, bnum, &b) < 0)
1370 	return -1;
1371 
1372       file->pos += chunk;
1373       count     -= chunk;
1374 
1375       if (file->pos > *lglen)
1376 	*lglen = file->pos;
1377     }
1378 
1379   return len;
1380 }
1381 
1382 /*
1383  * NAME:	hfs->truncate()
1384  * DESCRIPTION:	truncate an open file
1385  */
hfs_truncate(hfsfile * file,unsigned long len)1386 int hfs_truncate(hfsfile *file, unsigned long len)
1387 {
1388   unsigned long *lglen;
1389 
1390   f_getptrs(file, &lglen, 0, 0);
1391 
1392   if (*lglen > len)
1393     {
1394       if (file->vol->flags & HFS_READONLY)
1395 	{
1396 	  ERROR(EROFS, 0);
1397 	  return -1;
1398 	}
1399 
1400       *lglen = len;
1401 
1402       file->cat.u.fil.filMdDat = d_tomtime(time(0));
1403       file->flags |= HFS_UPDATE_CATREC;
1404 
1405       if (file->pos > len)
1406 	file->pos = len;
1407     }
1408 
1409   return 0;
1410 }
1411 
1412 /*
1413  * NAME:	hfs->lseek()
1414  * DESCRIPTION:	change file seek pointer
1415  */
hfs_lseek(hfsfile * file,long offset,int from)1416 long hfs_lseek(hfsfile *file, long offset, int from)
1417 {
1418   unsigned long *lglen;
1419   long newpos;
1420 
1421   f_getptrs(file, &lglen, 0, 0);
1422 
1423   switch (from)
1424     {
1425     case SEEK_SET:
1426       newpos = offset;
1427       break;
1428 
1429     case SEEK_CUR:
1430       newpos = file->pos + offset;
1431       break;
1432 
1433     case SEEK_END:
1434       newpos = *lglen + offset;
1435       break;
1436 
1437     default:
1438       ERROR(EINVAL, 0);
1439       return -1;
1440     }
1441 
1442   if (newpos < 0)
1443     newpos = 0;
1444   else if (newpos > *lglen)
1445     newpos = *lglen;
1446 
1447   file->pos = newpos;
1448 
1449   return newpos;
1450 }
1451 
1452 /*
1453  * NAME:	hfs->close()
1454  * DESCRIPTION:	close a file
1455  */
1456 #ifdef APPLE_HYB
1457 /* extra args are used to set the start of the forks in the ISO volume */
hfs_close(hfsfile * file,long dext,long rext)1458 int hfs_close(hfsfile *file, long dext, long rext)
1459 {
1460   int offset;
1461 #else
1462 int hfs_close(hfsfile *file)
1463 {
1464 #endif /* APPLE_HYB */
1465   hfsvol *vol = file->vol;
1466   int result = 0;
1467 
1468   if (f_trunc(file) < 0 ||
1469       f_flush(file) < 0)
1470     result = -1;
1471 
1472 #ifdef APPLE_HYB
1473   /* "start" of file is relative to the first available block */
1474   offset = vol->hce->hfs_hdr_size + vol->hce->hfs_map_size;
1475   /* update the "real" starting extent and re-flush the file */
1476   if (dext)
1477     file->cat.u.fil.filExtRec[0].xdrStABN = (dext - offset)/vol->lpa;
1478 
1479   if (rext)
1480     file->cat.u.fil.filRExtRec[0].xdrStABN = (rext - offset)/vol->lpa;
1481 
1482   if (dext || rext)
1483     file->flags |= HFS_UPDATE_CATREC;
1484 
1485   if (f_flush(file) < 0)
1486     result = -1;
1487 #endif /*APPLE_HYB */
1488 
1489   if (file->prev)
1490     file->prev->next = file->next;
1491   if (file->next)
1492     file->next->prev = file->prev;
1493   if (file == vol->files)
1494     vol->files = file->next;
1495 
1496   FREE(file);
1497 
1498   return result;
1499 }
1500 
1501 /* High-Level Catalog Routines ============================================= */
1502 
1503 /*
1504  * NAME:	hfs->stat()
1505  * DESCRIPTION:	return catalog information for an arbitrary path
1506  */
1507 int hfs_stat(hfsvol *vol, char *path, hfsdirent *ent)
1508 {
1509   CatDataRec data;
1510   long parid;
1511   char name[HFS_MAX_FLEN + 1];
1512 
1513   if (v_getvol(&vol) < 0 ||
1514       v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
1515     return -1;
1516 
1517   r_unpackdirent(parid, name, &data, ent);
1518 
1519   return 0;
1520 }
1521 
1522 /*
1523  * NAME:	hfs->fstat()
1524  * DESCRIPTION:	return catalog information for an open file
1525  */
1526 int hfs_fstat(hfsfile *file, hfsdirent *ent)
1527 {
1528   r_unpackdirent(file->parid, file->name, &file->cat, ent);
1529 
1530   return 0;
1531 }
1532 
1533 /*
1534  * NAME:	hfs->setattr()
1535  * DESCRIPTION:	change a file's attributes
1536  */
1537 int hfs_setattr(hfsvol *vol, char *path, hfsdirent *ent)
1538 {
1539   CatDataRec data;
1540   node n;
1541 
1542   if (v_getvol(&vol) < 0 ||
1543       v_resolve(&vol, path, &data, 0, 0, &n) <= 0)
1544     return -1;
1545 
1546   if (vol->flags & HFS_READONLY)
1547     {
1548       ERROR(EROFS, 0);
1549       return -1;
1550     }
1551 
1552   r_packdirent(&data, ent);
1553 
1554   if (v_putcatrec(&data, &n) < 0)
1555     return -1;
1556 
1557   return 0;
1558 }
1559 
1560 /*
1561  * NAME:	hfs->fsetattr()
1562  * DESCRIPTION:	change an open file's attributes
1563  */
1564 int hfs_fsetattr(hfsfile *file, hfsdirent *ent)
1565 {
1566   if (file->vol->flags & HFS_READONLY)
1567     {
1568       ERROR(EROFS, 0);
1569       return -1;
1570     }
1571 
1572   r_packdirent(&file->cat, ent);
1573 
1574   file->flags |= HFS_UPDATE_CATREC;
1575 
1576   return 0;
1577 }
1578 
1579 /*
1580  * NAME:	hfs->mkdir()
1581  * DESCRIPTION:	create a new directory
1582  */
1583 int hfs_mkdir(hfsvol *vol, char *path)
1584 {
1585   CatDataRec data;
1586   long parid;
1587   char name[HFS_MAX_FLEN + 1];
1588   int found;
1589 
1590   if (v_getvol(&vol) < 0)
1591     return -1;
1592 
1593   found = v_resolve(&vol, path, &data, &parid, name, 0);
1594   if (found < 0 || parid == 0)
1595     return -1;
1596   else if (found)
1597     {
1598       ERROR(EEXIST, 0);
1599       return -1;
1600     }
1601 
1602   if (parid == HFS_CNID_ROOTPAR)
1603     {
1604       ERROR(EINVAL, 0);
1605       return -1;
1606     }
1607 
1608   if (vol->flags & HFS_READONLY)
1609     {
1610       ERROR(EROFS, 0);
1611       return -1;
1612     }
1613 
1614   if (v_newfolder(vol, parid, name) < 0)
1615     return -1;
1616 
1617   return 0;
1618 }
1619 
1620 /*
1621  * NAME:	hfs->rmdir()
1622  * DESCRIPTION:	delete an empty directory
1623  */
1624 int hfs_rmdir(hfsvol *vol, char *path)
1625 {
1626   CatKeyRec key;
1627   CatDataRec data;
1628   long parid;
1629   char name[HFS_MAX_FLEN + 1];
1630   unsigned char pkey[HFS_CATKEYLEN];
1631 
1632   if (v_getvol(&vol) < 0 ||
1633       v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
1634     return -1;
1635 
1636   if (data.cdrType != cdrDirRec)
1637     {
1638       ERROR(ENOTDIR, 0);
1639       return -1;
1640     }
1641 
1642   if (data.u.dir.dirVal != 0)
1643     {
1644       ERROR(ENOTEMPTY, 0);
1645       return -1;
1646     }
1647 
1648   if (parid == HFS_CNID_ROOTPAR)
1649     {
1650       ERROR(EINVAL, 0);
1651       return -1;
1652     }
1653 
1654   if (vol->flags & HFS_READONLY)
1655     {
1656       ERROR(EROFS, 0);
1657       return -1;
1658     }
1659 
1660   /* delete directory record */
1661 
1662   r_makecatkey(&key, parid, name);
1663   r_packcatkey(&key, pkey, 0);
1664 
1665   if (bt_delete(&vol->cat, pkey) < 0)
1666     return -1;
1667 
1668   /* delete thread record */
1669 
1670   r_makecatkey(&key, data.u.dir.dirDirID, "");
1671   r_packcatkey(&key, pkey, 0);
1672 
1673   if (bt_delete(&vol->cat, pkey) < 0 ||
1674       v_adjvalence(vol, parid, 1, -1) < 0)
1675     return -1;
1676 
1677   return 0;
1678 }
1679 
1680 /*
1681  * NAME:	hfs->create()
1682  * DESCRIPTION:	create a new file
1683  */
1684 int hfs_create(hfsvol *vol, char *path, char *type, char *creator)
1685 {
1686   CatKeyRec key;
1687   CatDataRec data;
1688   long id, parid;
1689   char name[HFS_MAX_FLEN + 1];
1690   unsigned char record[HFS_CATRECMAXLEN];
1691   int found, i, reclen;
1692 
1693   if (v_getvol(&vol) < 0)
1694     return -1;
1695 
1696   found = v_resolve(&vol, path, &data, &parid, name, 0);
1697   if (found < 0 || parid == 0)
1698     return -1;
1699   else if (found)
1700     {
1701       ERROR(EEXIST, 0);
1702       return -1;
1703     }
1704 
1705   if (parid == HFS_CNID_ROOTPAR)
1706     {
1707       ERROR(EINVAL, 0);
1708       return -1;
1709     }
1710 
1711   if (vol->flags & HFS_READONLY)
1712     {
1713       ERROR(EROFS, 0);
1714       return -1;
1715     }
1716 
1717   /* create file `name' in parent `parid' */
1718 
1719   if (bt_space(&vol->cat, 1) < 0)
1720     return -1;
1721 
1722   id = vol->mdb.drNxtCNID++;
1723   vol->flags |= HFS_UPDATE_MDB;
1724 
1725   /* create file record */
1726 
1727   data.cdrType   = cdrFilRec;
1728   data.cdrResrv2 = 0;
1729 
1730   data.u.fil.filFlags = 0;
1731   data.u.fil.filTyp   = 0;
1732 
1733   memset(&data.u.fil.filUsrWds, 0, sizeof(data.u.fil.filUsrWds));
1734 
1735   data.u.fil.filUsrWds.fdType    = d_getl((unsigned char *) type);
1736   data.u.fil.filUsrWds.fdCreator = d_getl((unsigned char *) creator);
1737 
1738   data.u.fil.filFlNum  = id;
1739   data.u.fil.filStBlk  = 0;
1740   data.u.fil.filLgLen  = 0;
1741   data.u.fil.filPyLen  = 0;
1742   data.u.fil.filRStBlk = 0;
1743   data.u.fil.filRLgLen = 0;
1744   data.u.fil.filRPyLen = 0;
1745   data.u.fil.filCrDat  = d_tomtime(time(0));
1746   data.u.fil.filMdDat  = data.u.fil.filCrDat;
1747   data.u.fil.filBkDat  = 0;
1748 
1749   memset(&data.u.fil.filFndrInfo, 0, sizeof(data.u.fil.filFndrInfo));
1750 
1751   data.u.fil.filClpSize = 0;
1752 
1753   for (i = 0; i < 3; ++i)
1754     {
1755       data.u.fil.filExtRec[i].xdrStABN     = 0;
1756       data.u.fil.filExtRec[i].xdrNumABlks  = 0;
1757 
1758       data.u.fil.filRExtRec[i].xdrStABN    = 0;
1759       data.u.fil.filRExtRec[i].xdrNumABlks = 0;
1760     }
1761 
1762   data.u.fil.filResrv = 0;
1763 
1764   r_makecatkey(&key, parid, name);
1765   r_packcatkey(&key, record, &reclen);
1766   r_packcatdata(&data, HFS_RECDATA(record), &reclen);
1767 
1768   if (bt_insert(&vol->cat, record, reclen) < 0 ||
1769       v_adjvalence(vol, parid, 0, 1) < 0)
1770     return -1;
1771 
1772   return 0;
1773 }
1774 
1775 /*
1776  * NAME:	hfs->delete()
1777  * DESCRIPTION:	remove both forks of a file
1778  */
1779 int hfs_delete(hfsvol *vol, char *path)
1780 {
1781   hfsfile file;
1782   CatKeyRec key;
1783   unsigned char pkey[HFS_CATKEYLEN];
1784   int found;
1785 
1786   if (v_getvol(&vol) < 0 ||
1787       v_resolve(&vol, path, &file.cat, &file.parid, file.name, 0) <= 0)
1788     return -1;
1789 
1790   if (file.cat.cdrType != cdrFilRec)
1791     {
1792       ERROR(EISDIR, 0);
1793       return -1;
1794     }
1795 
1796   if (file.parid == HFS_CNID_ROOTPAR)
1797     {
1798       ERROR(EINVAL, 0);
1799       return -1;
1800     }
1801 
1802   if (vol->flags & HFS_READONLY)
1803     {
1804       ERROR(EROFS, 0);
1805       return -1;
1806     }
1807 
1808   /* free disk blocks */
1809 
1810   file.vol   = vol;
1811   file.flags = 0;
1812 
1813   file.cat.u.fil.filLgLen  = 0;
1814   file.cat.u.fil.filRLgLen = 0;
1815 
1816   f_selectfork(&file, 0);
1817   if (f_trunc(&file) < 0)
1818     return -1;
1819 
1820   f_selectfork(&file, 1);
1821   if (f_trunc(&file) < 0)
1822     return -1;
1823 
1824   /* delete file record */
1825 
1826   r_makecatkey(&key, file.parid, file.name);
1827   r_packcatkey(&key, pkey, 0);
1828 
1829   if (bt_delete(&vol->cat, pkey) < 0 ||
1830       v_adjvalence(vol, file.parid, 0, -1) < 0)
1831     return -1;
1832 
1833   /* delete file thread, if any */
1834 
1835   found = v_getfthread(vol, file.cat.u.fil.filFlNum, 0, 0);
1836   if (found < 0)
1837     return -1;
1838 
1839   if (found)
1840     {
1841       r_makecatkey(&key, file.cat.u.fil.filFlNum, "");
1842       r_packcatkey(&key, pkey, 0);
1843 
1844       if (bt_delete(&vol->cat, pkey) < 0)
1845 	return -1;
1846     }
1847 
1848   return 0;
1849 }
1850 
1851 /*
1852  * NAME:	hfs->rename()
1853  * DESCRIPTION:	change the name of and/or move a file or directory
1854  */
1855 int hfs_rename(hfsvol *vol, char *srcpath, char *dstpath)
1856 {
1857   hfsvol *srcvol;
1858   CatDataRec src, dst;
1859   long srcid, dstid;
1860   CatKeyRec key;
1861   char srcname[HFS_MAX_FLEN + 1], dstname[HFS_MAX_FLEN + 1];
1862   unsigned char record[HFS_CATRECMAXLEN];
1863   int found, isdir, moving, reclen;
1864   node n;
1865 
1866   if (v_getvol(&vol) < 0 ||
1867       v_resolve(&vol, srcpath, &src, &srcid, srcname, 0) <= 0)
1868     return -1;
1869 
1870   isdir  = (src.cdrType == cdrDirRec);
1871   srcvol = vol;
1872 
1873   found = v_resolve(&vol, dstpath, &dst, &dstid, dstname, 0);
1874   if (found < 0)
1875     return -1;
1876 
1877   if (vol != srcvol)
1878     {
1879       ERROR(EINVAL, "can't move across volumes");
1880       return -1;
1881     }
1882 
1883   if (dstid == 0)
1884     {
1885       ERROR(ENOENT, "bad destination path");
1886       return -1;
1887     }
1888 
1889   if (found &&
1890       dst.cdrType == cdrDirRec &&
1891       dst.u.dir.dirDirID != src.u.dir.dirDirID)
1892     {
1893       dstid = dst.u.dir.dirDirID;
1894       strcpy(dstname, srcname);
1895 
1896       found = v_catsearch(vol, dstid, dstname, 0, 0, 0);
1897       if (found < 0)
1898 	return -1;
1899     }
1900 
1901   moving = (srcid != dstid);
1902 
1903   if (found)
1904     {
1905       char *ptr;
1906 
1907       ptr = strrchr(dstpath, ':');
1908       if (ptr == 0)
1909 	ptr = dstpath;
1910       else
1911 	++ptr;
1912 
1913       if (*ptr)
1914 	strcpy(dstname, ptr);
1915 
1916       if (! moving && strcmp(srcname, dstname) == 0)
1917 	return 0;  /* source and destination are the same */
1918 
1919       if (moving || d_relstring(srcname, dstname))
1920 	{
1921 	  ERROR(EEXIST, "can't use destination name");
1922 	  return -1;
1923 	}
1924     }
1925 
1926   /* can't move anything into the root directory's parent */
1927 
1928   if (moving && dstid == HFS_CNID_ROOTPAR)
1929     {
1930       ERROR(EINVAL, "can't move above root directory");
1931       return -1;
1932     }
1933 
1934   if (moving && isdir)
1935     {
1936       long id;
1937 
1938       /* can't move root directory anywhere */
1939 
1940       if (src.u.dir.dirDirID == HFS_CNID_ROOTDIR)
1941 	{
1942 	  ERROR(EINVAL, "can't move root directory");
1943 	  return -1;
1944 	}
1945 
1946       /* make sure we aren't trying to move a directory inside itself */
1947 
1948       for (id = dstid; id != HFS_CNID_ROOTDIR; id = dst.u.dthd.thdParID)
1949 	{
1950 	  if (id == src.u.dir.dirDirID)
1951 	    {
1952 	      ERROR(EINVAL, "can't move directory inside itself");
1953 	      return -1;
1954 	    }
1955 
1956 	  if (v_getdthread(vol, id, &dst, 0) <= 0)
1957 	    return -1;
1958 	}
1959     }
1960 
1961   if (vol->flags & HFS_READONLY)
1962     {
1963       ERROR(EROFS, 0);
1964       return -1;
1965     }
1966 
1967   /* change volume name */
1968 
1969   if (dstid == HFS_CNID_ROOTPAR)
1970     {
1971       if (strlen(dstname) > HFS_MAX_VLEN)
1972 	{
1973 	  ERROR(ENAMETOOLONG, 0);
1974 	  return -1;
1975 	}
1976 
1977       strcpy(vol->mdb.drVN, dstname);
1978       vol->flags |= HFS_UPDATE_MDB;
1979     }
1980 
1981   /* remove source record */
1982 
1983   r_makecatkey(&key, srcid, srcname);
1984   r_packcatkey(&key, record, 0);
1985 
1986   if (bt_delete(&vol->cat, record) < 0)
1987     return -1;
1988 
1989   /* insert destination record */
1990 
1991   r_makecatkey(&key, dstid, dstname);
1992   r_packcatkey(&key, record, &reclen);
1993   r_packcatdata(&src, HFS_RECDATA(record), &reclen);
1994 
1995   if (bt_insert(&vol->cat, record, reclen) < 0)
1996     return -1;
1997 
1998   /* update thread record */
1999 
2000   if (isdir)
2001     {
2002       if (v_getdthread(vol, src.u.dir.dirDirID, &dst, &n) <= 0)
2003 	return -1;
2004 
2005       dst.u.dthd.thdParID = dstid;
2006       strcpy(dst.u.dthd.thdCName, dstname);
2007 
2008       if (v_putcatrec(&dst, &n) < 0)
2009 	return -1;
2010     }
2011   else
2012     {
2013       found = v_getfthread(vol, src.u.fil.filFlNum, &dst, &n);
2014       if (found < 0)
2015 	return -1;
2016 
2017       if (found)
2018 	{
2019 	  dst.u.fthd.fthdParID = dstid;
2020 	  strcpy(dst.u.fthd.fthdCName, dstname);
2021 
2022 	  if (v_putcatrec(&dst, &n) < 0)
2023 	    return -1;
2024 	}
2025     }
2026 
2027   /* update directory valences */
2028 
2029   if (moving)
2030     {
2031       if (v_adjvalence(vol, srcid, isdir, -1) < 0 ||
2032 	  v_adjvalence(vol, dstid, isdir,  1) < 0)
2033 	return -1;
2034     }
2035 
2036   return 0;
2037 }
2038 #ifdef APPLE_HYB
2039 /*
2040  * NAME:        hfs->hfs_get_drAllocPtr()
2041  * DESCRIPTION: get the current start of next allocation search
2042  */
2043 unsigned short
2044 hfs_get_drAllocPtr(hfsfile *file)
2045 {
2046   return(file->vol->mdb.drAllocPtr);
2047 }
2048 
2049 /*
2050  * NAME:        hfs->hfs_set_drAllocPtr()
2051  * DESCRIPTION: set the current start of next allocation search
2052  */
2053 #ifdef	PROTOTYPES
2054 int
2055 hfs_set_drAllocPtr(hfsfile *file, unsigned short drAllocPtr, int size)
2056 #else
2057 int
2058 hfs_set_drAllocPtr(hfsfile *file, unsigned short drAllocPtr, int size)
2059 #endif
2060 {
2061   hfsvol *vol = file->vol;
2062   int result = 0;
2063 
2064   /* truncate the current fork */
2065   if (f_trunc(file) < 0 ||
2066       f_flush(file) < 0)
2067     result = -1;
2068 
2069   /* convert the fork size into allocation blocks */
2070   size = (size + vol->mdb.drAlBlkSiz - 1)/vol->mdb.drAlBlkSiz;
2071 
2072   /* set the start of next allocation search to be after this fork */
2073   vol->mdb.drAllocPtr = drAllocPtr + size;
2074 
2075   vol->flags |= HFS_UPDATE_MDB;
2076 
2077   return result;
2078 }
2079 
2080 /*
2081  * NAME:        hfs->vsetbless()
2082  * DESCRIPTION: set blessed folder
2083  *
2084  * adapted from vsetattr() from v3.2.6
2085  */
2086 #ifdef  PROTOTYPES
2087 void
2088 hfs_vsetbless(hfsvol *vol, unsigned long cnid)
2089 #else
2090 void
2091 hfs_vsetbless(hfsvol *vol, unsigned long cnid)
2092 #endif
2093 {
2094   vol->mdb.drFndrInfo[0] = cnid;
2095 
2096   vol->flags |= HFS_UPDATE_MDB;
2097 }
2098 #endif /* APPLE_HYB */
2099