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