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