/[pearpc]/src/io/prom/fs/hfs/volume.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/io/prom/fs/hfs/volume.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 23744 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * libhfs - library for reading and writing Macintosh HFS volumes
3     * Copyright (C) 1996-1998 Robert Leslie
4     * Modified for use with PearPC (c) 2004 Stefan Weyergraf <stefan@weyergraf.de>
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     *
20     */
21    
22     # ifdef HAVE_CONFIG_H
23     # include "config.h"
24     # endif
25    
26     # include <stdlib.h>
27     # include <string.h>
28     # include <time.h>
29     # include <errno.h>
30    
31     # include "libhfs.h"
32     # include "volume.h"
33     # include "data.h"
34     # include "block.h"
35     # include "low.h"
36     # include "medium.h"
37     # include "file.h"
38     # include "btree.h"
39     # include "record.h"
40     # include "os.h"
41    
42     /*
43     * NAME: vol->init()
44     * DESCRIPTION: initialize volume structure
45     */
46     void v_init(hfsvol *vol, int flags)
47     {
48     btree *ext = &vol->ext;
49     btree *cat = &vol->cat;
50    
51     vol->priv = 0;
52     vol->flags = flags & HFS_VOL_OPT_MASK;
53    
54     vol->pnum = -1;
55     vol->vstart = 0;
56     vol->vlen = 0;
57     vol->lpa = 0;
58    
59     vol->cache = 0;
60    
61     vol->vbm = 0;
62     vol->vbmsz = 0;
63    
64     f_init(&ext->f, vol, HFS_CNID_EXT, "extents overflow");
65    
66     ext->map = 0;
67     ext->mapsz = 0;
68     ext->flags = 0;
69    
70     ext->keyunpack = (keyunpackfunc) r_unpackextkey;
71     ext->keycompare = (keycomparefunc) r_compareextkeys;
72    
73     f_init(&cat->f, vol, HFS_CNID_CAT, "catalog");
74    
75     cat->map = 0;
76     cat->mapsz = 0;
77     cat->flags = 0;
78    
79     cat->keyunpack = (keyunpackfunc) r_unpackcatkey;
80     cat->keycompare = (keycomparefunc) r_comparecatkeys;
81    
82     vol->cwd = HFS_CNID_ROOTDIR;
83    
84     vol->refs = 0;
85     vol->files = 0;
86     vol->dirs = 0;
87    
88     vol->prev = 0;
89     vol->next = 0;
90     }
91    
92     /*
93     * NAME: vol->open()
94     * DESCRIPTION: open volume source and lock against concurrent updates
95     */
96     int v_open(hfsvol *vol, const void *devicehandle, int mode)
97     {
98     if (vol->flags & HFS_VOL_OPEN)
99     ERROR(EINVAL, "volume already open");
100    
101     if (hfs_os_open(&vol->priv, devicehandle, mode) == -1)
102     goto fail;
103    
104     vol->flags |= HFS_VOL_OPEN;
105    
106     /* initialize volume block cache (OK to fail) */
107    
108     if (! (vol->flags & HFS_OPT_NOCACHE) &&
109     b_init(vol) != -1)
110     vol->flags |= HFS_VOL_USINGCACHE;
111    
112     return 0;
113    
114     fail:
115     return -1;
116     }
117    
118     /*
119     * NAME: flushvol()
120     * DESCRIPTION: flush all pending changes (B*-tree, MDB, VBM) to volume
121     */
122     static
123     int flushvol(hfsvol *vol, int umount)
124     {
125     if (vol->flags & HFS_VOL_READONLY)
126     goto done;
127    
128     if ((vol->ext.flags & HFS_BT_UPDATE_HDR) &&
129     bt_writehdr(&vol->ext) == -1)
130     goto fail;
131    
132     if ((vol->cat.flags & HFS_BT_UPDATE_HDR) &&
133     bt_writehdr(&vol->cat) == -1)
134     goto fail;
135    
136     if ((vol->flags & HFS_VOL_UPDATE_VBM) &&
137     v_writevbm(vol) == -1)
138     goto fail;
139    
140     if (umount && ! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED))
141     {
142     vol->mdb.drAtrb |= HFS_ATRB_UMOUNTED;
143     vol->flags |= HFS_VOL_UPDATE_MDB;
144     }
145    
146     if ((vol->flags & (HFS_VOL_UPDATE_MDB | HFS_VOL_UPDATE_ALTMDB)) &&
147     v_writemdb(vol) == -1)
148     goto fail;
149    
150     done:
151     return 0;
152    
153     fail:
154     return -1;
155     }
156    
157     /*
158     * NAME: vol->flush()
159     * DESCRIPTION: commit all pending changes to volume device
160     */
161     int v_flush(hfsvol *vol)
162     {
163     if (flushvol(vol, 0) == -1)
164     goto fail;
165    
166     if ((vol->flags & HFS_VOL_USINGCACHE) &&
167     b_flush(vol) == -1)
168     goto fail;
169    
170     return 0;
171    
172     fail:
173     return -1;
174     }
175    
176     /*
177     * NAME: vol->close()
178     * DESCRIPTION: close access path to volume source
179     */
180     int v_close(hfsvol *vol)
181     {
182     int result = 0;
183    
184     if (! (vol->flags & HFS_VOL_OPEN))
185     goto done;
186    
187     if ((vol->flags & HFS_VOL_MOUNTED) &&
188     flushvol(vol, 1) == -1)
189     result = -1;
190    
191     if ((vol->flags & HFS_VOL_USINGCACHE) &&
192     b_finish(vol) == -1)
193     result = -1;
194    
195     if (hfs_os_close(&vol->priv) == -1)
196     result = -1;
197    
198     vol->flags &= ~(HFS_VOL_OPEN | HFS_VOL_MOUNTED | HFS_VOL_USINGCACHE);
199    
200     /* free dynamically allocated structures */
201    
202     FREE(vol->vbm);
203    
204     vol->vbm = 0;
205     vol->vbmsz = 0;
206    
207     FREE(vol->ext.map);
208     FREE(vol->cat.map);
209    
210     vol->ext.map = 0;
211     vol->cat.map = 0;
212    
213     done:
214     return result;
215     }
216    
217     /*
218     * NAME: vol->same()
219     * DESCRIPTION: return 1 iff path is same as open volume
220     */
221     int v_same(hfsvol *vol, const char *path)
222     {
223     return hfs_os_same(&vol->priv, path);
224     }
225    
226     /*
227     * NAME: vol->geometry()
228     * DESCRIPTION: determine volume location and size (possibly in a partition)
229     */
230     int v_geometry(hfsvol *vol, int pnum)
231     {
232     ApplePartition map;
233     unsigned long bnum = 0;
234     int found;
235    
236     vol->pnum = pnum;
237    
238     if (pnum == 0)
239     {
240     vol->vstart = 0;
241     vol->vlen = b_size(vol);
242    
243     if (vol->vlen == 0)
244     goto fail;
245     }
246     else
247     {
248     /* while (pnum--)
249     {
250     found = m_findpmentry(vol, "Apple_HFS", &map, &bnum);
251     if ((found == -1) || !found) found = m_findpmentry(vol, "Apple_Bootstrap", &map, &bnum);
252     if ((found == -1 || !found) && !pnum)
253     goto fail;
254     }*/
255     bnum = pnum;
256     found = m_findpmentry(vol, "Apple_HFS", &map, &bnum);
257     bnum = pnum;
258     if ((found == -1) || !found) found = m_findpmentry(vol, "Apple_Bootstrap", &map, &bnum);
259     if (found == -1 || !found) goto fail;
260    
261     vol->vstart = map.pmPyPartStart;
262     vol->vlen = map.pmPartBlkCnt;
263    
264     if (map.pmDataCnt)
265     {
266     if ((unsigned long) map.pmLgDataStart +
267     (unsigned long) map.pmDataCnt > vol->vlen)
268     ERROR(EINVAL, "partition data overflows partition");
269    
270     vol->vstart += (unsigned long) map.pmLgDataStart;
271     vol->vlen = map.pmDataCnt;
272     }
273    
274     if (vol->vlen == 0)
275     ERROR(EINVAL, "volume partition is empty");
276     }
277    
278     if (vol->vlen < 800 * (1024 >> HFS_BLOCKSZ_BITS))
279     ERROR(EINVAL, "volume is smaller than 800K");
280    
281     return 0;
282    
283     fail:
284     return -1;
285     }
286    
287     /*
288     * NAME: vol->readmdb()
289     * DESCRIPTION: load Master Directory Block into memory
290     */
291     int v_readmdb(hfsvol *vol)
292     {
293     if (l_getmdb(vol, &vol->mdb, 0) == -1)
294     goto fail;
295    
296     if (vol->mdb.drSigWord != HFS_SIGWORD)
297     {
298     if (vol->mdb.drSigWord == HFS_SIGWORD_MFS)
299     ERROR(EINVAL, "MFS volume format not supported");
300     else
301     ERROR(EINVAL, "not a Macintosh HFS volume");
302     }
303    
304     if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0)
305     ERROR(EINVAL, "bad volume allocation block size");
306    
307     vol->lpa = vol->mdb.drAlBlkSiz >> HFS_BLOCKSZ_BITS;
308    
309     /* extents pseudo-file structs */
310    
311     vol->ext.f.cat.u.fil.filStBlk = vol->mdb.drXTExtRec[0].xdrStABN;
312     vol->ext.f.cat.u.fil.filLgLen = vol->mdb.drXTFlSize;
313     vol->ext.f.cat.u.fil.filPyLen = vol->mdb.drXTFlSize;
314    
315     vol->ext.f.cat.u.fil.filCrDat = vol->mdb.drCrDate;
316     vol->ext.f.cat.u.fil.filMdDat = vol->mdb.drLsMod;
317    
318     memcpy(&vol->ext.f.cat.u.fil.filExtRec,
319     &vol->mdb.drXTExtRec, sizeof(ExtDataRec));
320    
321     f_selectfork(&vol->ext.f, fkData);
322    
323     /* catalog pseudo-file structs */
324    
325     vol->cat.f.cat.u.fil.filStBlk = vol->mdb.drCTExtRec[0].xdrStABN;
326     vol->cat.f.cat.u.fil.filLgLen = vol->mdb.drCTFlSize;
327     vol->cat.f.cat.u.fil.filPyLen = vol->mdb.drCTFlSize;
328    
329     vol->cat.f.cat.u.fil.filCrDat = vol->mdb.drCrDate;
330     vol->cat.f.cat.u.fil.filMdDat = vol->mdb.drLsMod;
331    
332     memcpy(&vol->cat.f.cat.u.fil.filExtRec,
333     &vol->mdb.drCTExtRec, sizeof(ExtDataRec));
334    
335     f_selectfork(&vol->cat.f, fkData);
336    
337     return 0;
338    
339     fail:
340     return -1;
341     }
342    
343     /*
344     * NAME: vol->writemdb()
345     * DESCRIPTION: flush Master Directory Block to medium
346     */
347     int v_writemdb(hfsvol *vol)
348     {
349     vol->mdb.drLsMod = d_mtime(time(0));
350    
351     vol->mdb.drXTFlSize = vol->ext.f.cat.u.fil.filPyLen;
352     memcpy(&vol->mdb.drXTExtRec,
353     &vol->ext.f.cat.u.fil.filExtRec, sizeof(ExtDataRec));
354    
355     vol->mdb.drCTFlSize = vol->cat.f.cat.u.fil.filPyLen;
356     memcpy(&vol->mdb.drCTExtRec,
357     &vol->cat.f.cat.u.fil.filExtRec, sizeof(ExtDataRec));
358    
359     if (l_putmdb(vol, &vol->mdb, vol->flags & HFS_VOL_UPDATE_ALTMDB) == -1)
360     goto fail;
361    
362     vol->flags &= ~(HFS_VOL_UPDATE_MDB | HFS_VOL_UPDATE_ALTMDB);
363    
364     return 0;
365    
366     fail:
367     return -1;
368     }
369    
370     /*
371     * NAME: vol->readvbm()
372     * DESCRIPTION: read volume bitmap into memory
373     */
374     int v_readvbm(hfsvol *vol)
375     {
376     unsigned int vbmst = vol->mdb.drVBMSt;
377     unsigned int vbmsz = (vol->mdb.drNmAlBlks + 0x0fff) >> 12;
378     block *bp;
379    
380     ASSERT(vol->vbm == 0);
381    
382     if (vol->mdb.drAlBlSt - vbmst < vbmsz)
383     ERROR(EIO, "volume bitmap collides with volume data");
384    
385     vol->vbm = ALLOC(block, vbmsz);
386     if (vol->vbm == 0)
387     ERROR(ENOMEM, 0);
388    
389     vol->vbmsz = vbmsz;
390    
391     for (bp = vol->vbm; vbmsz--; ++bp)
392     {
393     if (b_readlb(vol, vbmst++, bp) == -1)
394     goto fail;
395     }
396    
397     return 0;
398    
399     fail:
400     FREE(vol->vbm);
401    
402     vol->vbm = 0;
403     vol->vbmsz = 0;
404    
405     return -1;
406     }
407    
408     /*
409     * NAME: vol->writevbm()
410     * DESCRIPTION: flush volume bitmap to medium
411     */
412     int v_writevbm(hfsvol *vol)
413     {
414     unsigned int vbmst = vol->mdb.drVBMSt;
415     unsigned int vbmsz = vol->vbmsz;
416     // const
417     block *bp;
418    
419     for (bp = vol->vbm; vbmsz--; ++bp)
420     {
421     if (b_writelb(vol, vbmst++, bp) == -1)
422     goto fail;
423     }
424    
425     vol->flags &= ~HFS_VOL_UPDATE_VBM;
426    
427     return 0;
428    
429     fail:
430     return -1;
431     }
432    
433     /*
434     * NAME: vol->mount()
435     * DESCRIPTION: load volume information into memory
436     */
437     int v_mount(hfsvol *vol)
438     {
439     /* read the MDB, volume bitmap, and extents/catalog B*-tree headers */
440    
441     if (v_readmdb(vol) == -1 ||
442     v_readvbm(vol) == -1 ||
443     bt_readhdr(&vol->ext) == -1 ||
444     bt_readhdr(&vol->cat) == -1)
445     goto fail;
446    
447     if (! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED) &&
448     v_scavenge(vol) == -1)
449     goto fail;
450    
451     if (vol->mdb.drAtrb & HFS_ATRB_SLOCKED)
452     vol->flags |= HFS_VOL_READONLY;
453     else if (vol->flags & HFS_VOL_READONLY)
454     vol->mdb.drAtrb |= HFS_ATRB_HLOCKED;
455     else
456     vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED;
457    
458     vol->flags |= HFS_VOL_MOUNTED;
459    
460     return 0;
461    
462     fail:
463     return -1;
464     }
465    
466     /*
467     * NAME: vol->dirty()
468     * DESCRIPTION: ensure the volume is marked "in use" before we make changes
469     */
470     int v_dirty(hfsvol *vol)
471     {
472     if (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED)
473     {
474     vol->mdb.drAtrb &= ~HFS_ATRB_UMOUNTED;
475     ++vol->mdb.drWrCnt;
476    
477     if (v_writemdb(vol) == -1)
478     goto fail;
479    
480     if ((vol->flags & HFS_VOL_USINGCACHE) &&
481     b_flush(vol) == -1)
482     goto fail;
483     }
484    
485     return 0;
486    
487     fail:
488     return -1;
489     }
490    
491     /*
492     * NAME: vol->catsearch()
493     * DESCRIPTION: search catalog tree
494     */
495     int v_catsearch(hfsvol *vol, unsigned long parid, const char *name,
496     CatDataRec *data, char *cname, node *np)
497     {
498     CatKeyRec key;
499     byte pkey[HFS_CATKEYLEN];
500     const byte *ptr;
501     node n;
502     int found;
503    
504     if (np == 0)
505     np = &n;
506    
507     r_makecatkey(&key, parid, name);
508     r_packcatkey(&key, pkey, 0);
509    
510     found = bt_search(&vol->cat, pkey, np);
511     if (found <= 0)
512     return found;
513    
514     ptr = HFS_NODEREC(*np, np->rnum);
515    
516     if (cname)
517     {
518     r_unpackcatkey(ptr, &key);
519     strcpy(cname, key.ckrCName);
520     }
521    
522     if (data)
523     r_unpackcatdata(HFS_RECDATA(ptr), data);
524    
525     return 1;
526     }
527    
528     /*
529     * NAME: vol->extsearch()
530     * DESCRIPTION: search extents tree
531     */
532     int v_extsearch(hfsfile *file, unsigned int fabn,
533     ExtDataRec *data, node *np)
534     {
535     ExtKeyRec key;
536     ExtDataRec extsave;
537     unsigned int fabnsave;
538     byte pkey[HFS_EXTKEYLEN];
539     const byte *ptr;
540     node n;
541     int found;
542    
543     if (np == 0)
544     np = &n;
545    
546     r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn);
547     r_packextkey(&key, pkey, 0);
548    
549     /* in case bt_search() clobbers these */
550    
551     memcpy(&extsave, &file->ext, sizeof(ExtDataRec));
552     fabnsave = file->fabn;
553    
554     found = bt_search(&file->vol->ext, pkey, np);
555    
556     memcpy(&file->ext, &extsave, sizeof(ExtDataRec));
557     file->fabn = fabnsave;
558    
559     if (found <= 0)
560     return found;
561    
562     if (data)
563     {
564     ptr = HFS_NODEREC(*np, np->rnum);
565     r_unpackextdata(HFS_RECDATA(ptr), data);
566     }
567    
568     return 1;
569     }
570    
571     /*
572     * NAME: vol->getthread()
573     * DESCRIPTION: retrieve catalog thread information for a file or directory
574     */
575     int v_getthread(hfsvol *vol, unsigned long id,
576     CatDataRec *thread, node *np, int type)
577     {
578     CatDataRec rec;
579     int found;
580    
581     if (thread == 0)
582     thread = &rec;
583    
584     found = v_catsearch(vol, id, "", thread, 0, np);
585     if (found == 1 && thread->cdrType != type)
586     ERROR(EIO, "bad thread record");
587    
588     return found;
589    
590     fail:
591     return -1;
592     }
593    
594     /*
595     * NAME: vol->putcatrec()
596     * DESCRIPTION: store catalog information
597     */
598     int v_putcatrec(const CatDataRec *data, node *np)
599     {
600     byte pdata[HFS_CATDATALEN], *ptr;
601     unsigned int len = 0;
602    
603     r_packcatdata(data, pdata, &len);
604    
605     ptr = HFS_NODEREC(*np, np->rnum);
606     memcpy(HFS_RECDATA(ptr), pdata, len);
607    
608     return bt_putnode(np);
609     }
610    
611     /*
612     * NAME: vol->putextrec()
613     * DESCRIPTION: store extent information
614     */
615     int v_putextrec(const ExtDataRec *data, node *np)
616     {
617     byte pdata[HFS_EXTDATALEN], *ptr;
618     unsigned int len = 0;
619    
620     r_packextdata(data, pdata, &len);
621    
622     ptr = HFS_NODEREC(*np, np->rnum);
623     memcpy(HFS_RECDATA(ptr), pdata, len);
624    
625     return bt_putnode(np);
626     }
627    
628     /*
629     * NAME: vol->allocblocks()
630     * DESCRIPTION: allocate a contiguous range of blocks
631     */
632     int v_allocblocks(hfsvol *vol, ExtDescriptor *blocks)
633     {
634     unsigned int request, found, foundat, start, end;
635     register unsigned int pt;
636     block *vbm;
637     int wrap = 0;
638    
639     if (vol->mdb.drFreeBks == 0)
640     ERROR(ENOSPC, "volume full");
641    
642     request = blocks->xdrNumABlks;
643     found = 0;
644     foundat = 0;
645     start = vol->mdb.drAllocPtr;
646     end = vol->mdb.drNmAlBlks;
647     vbm = vol->vbm;
648    
649     ASSERT(request > 0);
650    
651     /* backtrack the start pointer to recover unused space */
652    
653     if (! BMTST(vbm, start))
654     {
655     while (start > 0 && ! BMTST(vbm, start - 1))
656     --start;
657     }
658    
659     /* find largest unused block which satisfies request */
660    
661     pt = start;
662    
663     while (1)
664     {
665     unsigned int mark;
666    
667     /* skip blocks in use */
668    
669     while (pt < end && BMTST(vbm, pt))
670     ++pt;
671    
672     if (wrap && pt >= start)
673     break;
674    
675     /* count blocks not in use */
676    
677     mark = pt;
678     while (pt < end && pt - mark < request && ! BMTST(vbm, pt))
679     ++pt;
680    
681     if (pt - mark > found)
682     {
683     found = pt - mark;
684     foundat = mark;
685     }
686    
687     if (wrap && pt >= start)
688     break;
689    
690     if (pt == end)
691     pt = 0, wrap = 1;
692    
693     if (found == request)
694     break;
695     }
696    
697     if (found == 0 || found > vol->mdb.drFreeBks)
698     ERROR(EIO, "bad volume bitmap or free block count");
699    
700     blocks->xdrStABN = foundat;
701     blocks->xdrNumABlks = found;
702    
703     if (v_dirty(vol) == -1)
704     goto fail;
705    
706     vol->mdb.drAllocPtr = pt;
707     vol->mdb.drFreeBks -= found;
708    
709     for (pt = foundat; pt < foundat + found; ++pt)
710     BMSET(vbm, pt);
711    
712     vol->flags |= HFS_VOL_UPDATE_MDB | HFS_VOL_UPDATE_VBM;
713    
714     if (vol->flags & HFS_OPT_ZERO)
715     {
716     block b;
717     unsigned int i;
718    
719     memset(&b, 0, sizeof(b));
720    
721     for (pt = foundat; pt < foundat + found; ++pt)
722     {
723     for (i = 0; i < vol->lpa; ++i)
724     b_writeab(vol, pt, i, &b);
725     }
726     }
727    
728     return 0;
729    
730     fail:
731     return -1;
732     }
733    
734     /*
735     * NAME: vol->freeblocks()
736     * DESCRIPTION: deallocate a contiguous range of blocks
737     */
738     int v_freeblocks(hfsvol *vol, const ExtDescriptor *blocks)
739     {
740     unsigned int start, len, pt;
741     block *vbm;
742    
743     start = blocks->xdrStABN;
744     len = blocks->xdrNumABlks;
745     vbm = vol->vbm;
746    
747     if (v_dirty(vol) == -1)
748     goto fail;
749    
750     vol->mdb.drFreeBks += len;
751    
752     for (pt = start; pt < start + len; ++pt)
753     BMCLR(vbm, pt);
754    
755     vol->flags |= HFS_VOL_UPDATE_MDB | HFS_VOL_UPDATE_VBM;
756    
757     return 0;
758    
759     fail:
760     return -1;
761     }
762    
763     /*
764     * NAME: vol->resolve()
765     * DESCRIPTION: translate a pathname; return catalog information
766     */
767     int v_resolve(hfsvol **vol, const char *path,
768     CatDataRec *data, unsigned long *parid, char *fname, node *np)
769     {
770     unsigned long dirid;
771     char name[HFS_MAX_FLEN + 1], *nptr;
772     int found = 0;
773    
774     if (*path == 0)
775     ERROR(ENOENT, "empty path");
776    
777     if (parid)
778     *parid = 0;
779    
780     nptr = strchr(path, '/');
781    
782     if (*path == '/' || nptr == 0)
783     {
784     dirid = (*vol)->cwd; /* relative path */
785    
786     if (*path == '/')
787     ++path;
788    
789     if (*path == 0)
790     {
791     found = v_getdthread(*vol, dirid, data, 0);
792     if (found == -1)
793     goto fail;
794    
795     if (found)
796     {
797     if (parid)
798     *parid = data->u.dthd.thdParID;
799    
800     found = v_catsearch(*vol, data->u.dthd.thdParID,
801     data->u.dthd.thdCName, data, fname, np);
802     if (found == -1)
803     goto fail;
804     }
805    
806     goto done;
807     }
808     }
809     else
810     {
811     hfsvol *check;
812    
813     dirid = HFS_CNID_ROOTPAR; /* absolute path */
814    
815     if (nptr - path > HFS_MAX_VLEN)
816     ERROR(ENAMETOOLONG, 0);
817    
818     strncpy(name, path, nptr - path);
819     name[nptr - path] = 0;
820    
821     for (check = hfs_mounts; check; check = check->next)
822     {
823     if (d_relstring(check->mdb.drVN, name) == 0)
824     {
825     *vol = check;
826     break;
827     }
828     }
829     }
830    
831     while (1)
832     {
833     while (*path == '/')
834     {
835     ++path;
836    
837     found = v_getdthread(*vol, dirid, data, 0);
838     if (found == -1)
839     goto fail;
840     else if (! found)
841     goto done;
842    
843     dirid = data->u.dthd.thdParID;
844     }
845    
846     if (*path == 0)
847     {
848     found = v_getdthread(*vol, dirid, data, 0);
849     if (found == -1)
850     goto fail;
851    
852     if (found)
853     {
854     if (parid)
855     *parid = data->u.dthd.thdParID;
856    
857     found = v_catsearch(*vol, data->u.dthd.thdParID,
858     data->u.dthd.thdCName, data, fname, np);
859     if (found == -1)
860     goto fail;
861     }
862    
863     goto done;
864     }
865    
866     nptr = name;
867     while (nptr < name + sizeof(name) - 1 && *path && *path != '/')
868     *nptr++ = *path++;
869    
870     if (*path && *path != '/')
871     ERROR(ENAMETOOLONG, 0);
872    
873     *nptr = 0;
874     if (*path == '/')
875     ++path;
876    
877     if (parid)
878     *parid = dirid;
879    
880     found = v_catsearch(*vol, dirid, name, data, fname, np);
881     if (found == -1)
882     goto fail;
883    
884     if (! found)
885     {
886     if (*path && parid)
887     *parid = 0;
888    
889     if (*path == 0 && fname)
890     strcpy(fname, name);
891    
892     goto done;
893     }
894    
895     switch (data->cdrType)
896     {
897     case cdrDirRec:
898     if (*path == 0)
899     goto done;
900    
901     dirid = data->u.dir.dirDirID;
902     break;
903    
904     case cdrFilRec:
905     if (*path == 0)
906     goto done;
907    
908     ERROR(ENOTDIR, "invalid pathname");
909    
910     default:
911     ERROR(EIO, "unexpected catalog record");
912     }
913     }
914    
915     done:
916     return found;
917    
918     fail:
919     return -1;
920     }
921    
922     /*
923     * NAME: vol->adjvalence()
924     * DESCRIPTION: update a volume's valence counts
925     */
926     int v_adjvalence(hfsvol *vol, unsigned long parid, int isdir, int adj)
927     {
928     node n;
929     CatDataRec data;
930     int result = 0;
931    
932     if (isdir)
933     vol->mdb.drDirCnt += adj;
934     else
935     vol->mdb.drFilCnt += adj;
936    
937     vol->flags |= HFS_VOL_UPDATE_MDB;
938    
939     if (parid == HFS_CNID_ROOTDIR)
940     {
941     if (isdir)
942     vol->mdb.drNmRtDirs += adj;
943     else
944     vol->mdb.drNmFls += adj;
945     }
946     else if (parid == HFS_CNID_ROOTPAR)
947     goto done;
948    
949     if (v_getdthread(vol, parid, &data, 0) <= 0 ||
950     v_catsearch(vol, data.u.dthd.thdParID, data.u.dthd.thdCName,
951     &data, 0, &n) <= 0 ||
952     data.cdrType != cdrDirRec)
953     ERROR(EIO, "can't find parent directory");
954    
955     data.u.dir.dirVal += adj;
956     data.u.dir.dirMdDat = d_mtime(time(0));
957    
958     result = v_putcatrec(&data, &n);
959    
960     done:
961     return result;
962    
963     fail:
964     return -1;
965     }
966    
967     /*
968     * NAME: vol->mkdir()
969     * DESCRIPTION: create a new HFS directory
970     */
971     int v_mkdir(hfsvol *vol, unsigned long parid, const char *name)
972     {
973     CatKeyRec key;
974     CatDataRec data;
975     unsigned long id;
976     byte record[HFS_MAX_CATRECLEN];
977     unsigned int reclen;
978     int i;
979    
980     if (bt_space(&vol->cat, 2) == -1)
981     goto fail;
982    
983     id = vol->mdb.drNxtCNID++;
984     vol->flags |= HFS_VOL_UPDATE_MDB;
985    
986     /* create directory record */
987    
988     data.cdrType = cdrDirRec;
989     data.cdrResrv2 = 0;
990    
991     data.u.dir.dirFlags = 0;
992     data.u.dir.dirVal = 0;
993     data.u.dir.dirDirID = id;
994     data.u.dir.dirCrDat = d_mtime(time(0));
995     data.u.dir.dirMdDat = data.u.dir.dirCrDat;
996     data.u.dir.dirBkDat = 0;
997    
998     memset(&data.u.dir.dirUsrInfo, 0, sizeof(data.u.dir.dirUsrInfo));
999     memset(&data.u.dir.dirFndrInfo, 0, sizeof(data.u.dir.dirFndrInfo));
1000     for (i = 0; i < 4; ++i)
1001     data.u.dir.dirResrv[i] = 0;
1002    
1003     r_makecatkey(&key, parid, name);
1004     r_packcatrec(&key, &data, record, &reclen);
1005    
1006     if (bt_insert(&vol->cat, record, reclen) == -1)
1007     goto fail;
1008    
1009     /* create thread record */
1010    
1011     data.cdrType = cdrThdRec;
1012     data.cdrResrv2 = 0;
1013    
1014     data.u.dthd.thdResrv[0] = 0;
1015     data.u.dthd.thdResrv[1] = 0;
1016     data.u.dthd.thdParID = parid;
1017     strcpy(data.u.dthd.thdCName, name);
1018    
1019     r_makecatkey(&key, id, "");
1020     r_packcatrec(&key, &data, record, &reclen);
1021    
1022     if (bt_insert(&vol->cat, record, reclen) == -1 ||
1023     v_adjvalence(vol, parid, 1, 1) == -1)
1024     goto fail;
1025    
1026     return 0;
1027    
1028     fail:
1029     return -1;
1030     }
1031    
1032     /*
1033     * NAME: markexts()
1034     * DESCRIPTION: set bits from an extent record in the volume bitmap
1035     */
1036     static
1037     void markexts(block *vbm, const ExtDataRec *exts)
1038     {
1039     int i;
1040     unsigned int pt, len;
1041    
1042     for (i = 0; i < 3; ++i)
1043     {
1044     for ( pt = (*exts)[i].xdrStABN,
1045     len = (*exts)[i].xdrNumABlks; len--; ++pt)
1046     BMSET(vbm, pt);
1047     }
1048     }
1049    
1050     /*
1051     * NAME: vol->scavenge()
1052     * DESCRIPTION: safeguard blocks in the volume bitmap
1053     */
1054     int v_scavenge(hfsvol *vol)
1055     {
1056     block *vbm = vol->vbm;
1057     node n;
1058     unsigned int pt, blks;
1059     unsigned long lastcnid = 15;
1060    
1061     # ifdef DEBUG
1062     fprintf(stderr, "VOL: \"%s\" not cleanly unmounted\n",
1063     vol->mdb.drVN);
1064     # endif
1065    
1066     if (vol->flags & HFS_VOL_READONLY)
1067     goto done;
1068    
1069     # ifdef DEBUG
1070     fprintf(stderr, "VOL: scavenging...\n");
1071     # endif
1072    
1073     /* reset MDB by marking it dirty again */
1074    
1075     vol->mdb.drAtrb |= HFS_ATRB_UMOUNTED;
1076     if (v_dirty(vol) == -1)
1077     goto fail;
1078    
1079     /* begin by marking extents in MDB */
1080    
1081     markexts(vbm, &vol->mdb.drXTExtRec);
1082     markexts(vbm, &vol->mdb.drCTExtRec);
1083    
1084     vol->flags |= HFS_VOL_UPDATE_VBM;
1085    
1086     /* scavenge the extents overflow file */
1087    
1088     if (vol->ext.hdr.bthFNode > 0)
1089     {
1090     if (bt_getnode(&n, &vol->ext, vol->ext.hdr.bthFNode) == -1)
1091     goto fail;
1092    
1093     n.rnum = 0;
1094    
1095     while (1)
1096     {
1097     ExtDataRec data;
1098     const byte *ptr;
1099    
1100     while (n.rnum >= n.nd.ndNRecs && n.nd.ndFLink > 0)
1101     {
1102     if (bt_getnode(&n, &vol->ext, n.nd.ndFLink) == -1)
1103     goto fail;
1104    
1105     n.rnum = 0;
1106     }
1107    
1108     if (n.rnum >= n.nd.ndNRecs && n.nd.ndFLink == 0)
1109     break;
1110    
1111     ptr = HFS_NODEREC(n, n.rnum);
1112     r_unpackextdata(HFS_RECDATA(ptr), &data);
1113    
1114     markexts(vbm, &data);
1115    
1116     ++n.rnum;
1117     }
1118     }
1119    
1120     /* scavenge the catalog file */
1121    
1122     if (vol->cat.hdr.bthFNode > 0)
1123     {
1124     if (bt_getnode(&n, &vol->cat, vol->cat.hdr.bthFNode) == -1)
1125     goto fail;
1126    
1127     n.rnum = 0;
1128    
1129     while (1)
1130     {
1131     CatDataRec data;
1132     const byte *ptr;
1133    
1134     while (n.rnum >= n.nd.ndNRecs && n.nd.ndFLink > 0)
1135     {
1136     if (bt_getnode(&n, &vol->cat, n.nd.ndFLink) == -1)
1137     goto fail;
1138    
1139     n.rnum = 0;
1140     }
1141    
1142     if (n.rnum >= n.nd.ndNRecs && n.nd.ndFLink == 0)
1143     break;
1144    
1145     ptr = HFS_NODEREC(n, n.rnum);
1146     r_unpackcatdata(HFS_RECDATA(ptr), &data);
1147    
1148     switch (data.cdrType)
1149     {
1150     case cdrFilRec:
1151     markexts(vbm, &data.u.fil.filExtRec);
1152     markexts(vbm, &data.u.fil.filRExtRec);
1153    
1154     if (data.u.fil.filFlNum > lastcnid)
1155     lastcnid = data.u.fil.filFlNum;
1156     break;
1157    
1158     case cdrDirRec:
1159     if (data.u.dir.dirDirID > lastcnid)
1160     lastcnid = data.u.dir.dirDirID;
1161     break;
1162     }
1163    
1164     ++n.rnum;
1165     }
1166     }
1167    
1168     /* count free blocks */
1169    
1170     for (blks = 0, pt = vol->mdb.drNmAlBlks; pt--; )
1171     {
1172     if (! BMTST(vbm, pt))
1173     ++blks;
1174     }
1175    
1176     if (vol->mdb.drFreeBks != blks)
1177     {
1178     # ifdef DEBUG
1179     fprintf(stderr, "VOL: updating free blocks from %u to %u\n",
1180     vol->mdb.drFreeBks, blks);
1181     # endif
1182    
1183     vol->mdb.drFreeBks = blks;
1184     vol->flags |= HFS_VOL_UPDATE_MDB;
1185     }
1186    
1187     /* ensure next CNID is sane */
1188    
1189     if ((unsigned long) vol->mdb.drNxtCNID <= lastcnid)
1190     {
1191     # ifdef DEBUG
1192     fprintf(stderr, "VOL: updating next CNID from %lu to %lu\n",
1193     vol->mdb.drNxtCNID, lastcnid + 1);
1194     # endif
1195    
1196     vol->mdb.drNxtCNID = lastcnid + 1;
1197     vol->flags |= HFS_VOL_UPDATE_MDB;
1198     }
1199    
1200     # ifdef DEBUG
1201     fprintf(stderr, "VOL: scavenging complete\n");
1202     # endif
1203    
1204     done:
1205     return 0;
1206    
1207     fail:
1208     return -1;
1209     }

  ViewVC Help
Powered by ViewVC 1.1.26