/[pearpc]/src/io/prom/fs/hfs/hfs.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

Contents of /src/io/prom/fs/hfs/hfs.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 36150 byte(s)
import upstream CVS
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 "data.h"
33 # include "block.h"
34 # include "medium.h"
35 # include "file.h"
36 # include "btree.h"
37 # include "node.h"
38 # include "record.h"
39 # include "volume.h"
40
41 const char *hfs_error = "no error"; /* static error string */
42
43 hfsvol *hfs_mounts; /* linked list of mounted volumes */
44
45 static
46 hfsvol *curvol; /* current volume */
47
48 /*
49 * NAME: validvname()
50 * DESCRIPTION: return true if parameter is a valid volume name
51 */
52 static
53 int validvname(const char *name)
54 {
55 int len;
56
57 len = strlen(name);
58 if (len < 1)
59 ERROR(EINVAL, "volume name cannot be empty");
60 else if (len > HFS_MAX_VLEN)
61 ERROR(ENAMETOOLONG,
62 "volume name can be at most " STR(HFS_MAX_VLEN) " chars");
63
64 if (strchr(name, '/'))
65 ERROR(EINVAL, "volume name may not contain slashes");
66
67 return 1;
68
69 fail:
70 return 0;
71 }
72
73 /*
74 * NAME: getvol()
75 * DESCRIPTION: validate a volume reference
76 */
77 static
78 int getvol(hfsvol **vol)
79 {
80 if (*vol == 0)
81 {
82 if (curvol == 0)
83 ERROR(EINVAL, "no volume is current");
84
85 *vol = curvol;
86 }
87
88 return 0;
89
90 fail:
91 return -1;
92 }
93
94 /* High-Level Volume Routines ============================================== */
95
96 /*
97 * NAME: hfs->mount()
98 * DESCRIPTION: open an HFS volume; return volume descriptor or 0 (error)
99 */
100 hfsvol *hfs_mount(const void *devicehandle, int pnum, int mode)
101 {
102 hfsvol *vol, *check;
103
104 /* see if the volume is already mounted */
105
106 for (check = hfs_mounts; check; check = check->next)
107 {
108 if (check->pnum == pnum && v_same(check, devicehandle) == 1)
109 {
110 /* verify compatible read/write mode */
111
112 if (((check->flags & HFS_VOL_READONLY) &&
113 ! (mode & HFS_MODE_RDWR)) ||
114 (! (check->flags & HFS_VOL_READONLY) &&
115 (mode & (HFS_MODE_RDWR | HFS_MODE_ANY))))
116 {
117 vol = check;
118 goto done;
119 }
120 }
121 }
122
123 vol = ALLOC(hfsvol, 1);
124 if (vol == 0)
125 ERROR(ENOMEM, 0);
126
127 v_init(vol, mode);
128
129 /* open the medium */
130
131 switch (mode & HFS_MODE_MASK)
132 {
133 case HFS_MODE_RDWR:
134 case HFS_MODE_ANY:
135 if (v_open(vol, devicehandle, HFS_MODE_RDWR) != -1)
136 break;
137
138 if ((mode & HFS_MODE_MASK) == HFS_MODE_RDWR)
139 goto fail;
140
141 case HFS_MODE_RDONLY:
142 default:
143 vol->flags |= HFS_VOL_READONLY;
144
145 if (v_open(vol, devicehandle, HFS_MODE_RDONLY) == -1)
146 goto fail;
147 }
148
149 /* mount the volume */
150
151 if (v_geometry(vol, pnum) == -1 ||
152 v_mount(vol) == -1)
153 goto fail;
154
155 /* add to linked list of volumes */
156
157 vol->prev = 0;
158 vol->next = hfs_mounts;
159
160 if (hfs_mounts)
161 hfs_mounts->prev = vol;
162
163 hfs_mounts = vol;
164
165 done:
166 ++vol->refs;
167 curvol = vol;
168
169 return vol;
170
171 fail:
172 if (vol)
173 {
174 v_close(vol);
175 FREE(vol);
176 }
177
178 return 0;
179 }
180
181 /*
182 * NAME: hfs->flush()
183 * DESCRIPTION: flush all pending changes to an HFS volume
184 */
185 int hfs_flush(hfsvol *vol)
186 {
187 hfsfile *file;
188
189 if (getvol(&vol) == -1)
190 goto fail;
191
192 for (file = vol->files; file; file = file->next)
193 {
194 if (f_flush(file) == -1)
195 goto fail;
196 }
197
198 if (v_flush(vol) == -1)
199 goto fail;
200
201 return 0;
202
203 fail:
204 return -1;
205 }
206
207 /*
208 * NAME: hfs->flushall()
209 * DESCRIPTION: flush all pending changes to all mounted HFS volumes
210 */
211 void hfs_flushall(void)
212 {
213 hfsvol *vol;
214
215 for (vol = hfs_mounts; vol; vol = vol->next)
216 hfs_flush(vol);
217 }
218
219 /*
220 * NAME: hfs->umount()
221 * DESCRIPTION: close an HFS volume
222 */
223 int hfs_umount(hfsvol *vol)
224 {
225 int result = 0;
226
227 if (getvol(&vol) == -1)
228 goto fail;
229
230 if (--vol->refs)
231 {
232 result = v_flush(vol);
233 goto done;
234 }
235
236 /* close all open files and directories */
237
238 while (vol->files)
239 {
240 if (hfs_close(vol->files) == -1)
241 result = -1;
242 }
243
244 while (vol->dirs)
245 {
246 if (hfs_closedir(vol->dirs) == -1)
247 result = -1;
248 }
249
250 /* close medium */
251
252 if (v_close(vol) == -1)
253 result = -1;
254
255 /* remove from linked list of volumes */
256
257 if (vol->prev)
258 vol->prev->next = vol->next;
259 if (vol->next)
260 vol->next->prev = vol->prev;
261
262 if (vol == hfs_mounts)
263 hfs_mounts = vol->next;
264 if (vol == curvol)
265 curvol = 0;
266
267 FREE(vol);
268
269 done:
270 return result;
271
272 fail:
273 return -1;
274 }
275
276 /*
277 * NAME: hfs->umountall()
278 * DESCRIPTION: unmount all mounted volumes
279 */
280 void hfs_umountall(void)
281 {
282 while (hfs_mounts)
283 hfs_umount(hfs_mounts);
284 }
285
286 /*
287 * NAME: hfs->getvol()
288 * DESCRIPTION: return a pointer to a mounted volume
289 */
290 hfsvol *hfs_getvol(const char *name)
291 {
292 hfsvol *vol;
293
294 if (name == 0)
295 return curvol;
296
297 for (vol = hfs_mounts; vol; vol = vol->next)
298 {
299 if (d_relstring(name, vol->mdb.drVN) == 0)
300 return vol;
301 }
302
303 return 0;
304 }
305
306 /*
307 * NAME: hfs->setvol()
308 * DESCRIPTION: change the current volume
309 */
310 void hfs_setvol(hfsvol *vol)
311 {
312 curvol = vol;
313 }
314
315 /*
316 * NAME: hfs->vstat()
317 * DESCRIPTION: return volume statistics
318 */
319 int hfs_vstat(hfsvol *vol, hfsvolent *ent)
320 {
321 if (getvol(&vol) == -1)
322 goto fail;
323
324 strcpy(ent->name, vol->mdb.drVN);
325
326 ent->flags = (vol->flags & HFS_VOL_READONLY) ? HFS_ISLOCKED : 0;
327
328 ent->totbytes = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;
329 ent->freebytes = vol->mdb.drFreeBks * vol->mdb.drAlBlkSiz;
330
331 ent->alblocksz = vol->mdb.drAlBlkSiz;
332 ent->clumpsz = vol->mdb.drClpSiz;
333
334 ent->numfiles = vol->mdb.drFilCnt;
335 ent->numdirs = vol->mdb.drDirCnt;
336
337 ent->crdate = d_ltime(vol->mdb.drCrDate);
338 ent->mddate = d_ltime(vol->mdb.drLsMod);
339 ent->bkdate = d_ltime(vol->mdb.drVolBkUp);
340
341 ent->blessed = vol->mdb.drFndrInfo[0];
342
343 return 0;
344
345 fail:
346 return -1;
347 }
348
349 /*
350 * NAME: hfs->vsetattr()
351 * DESCRIPTION: change volume attributes
352 */
353 int hfs_vsetattr(hfsvol *vol, hfsvolent *ent)
354 {
355 if (getvol(&vol) == -1)
356 goto fail;
357
358 if (ent->clumpsz % vol->mdb.drAlBlkSiz != 0)
359 ERROR(EINVAL, "illegal clump size");
360
361 /* make sure "blessed" folder exists */
362
363 if (ent->blessed &&
364 v_getdthread(vol, ent->blessed, 0, 0) <= 0)
365 ERROR(EINVAL, "illegal blessed folder");
366
367 if (vol->flags & HFS_VOL_READONLY)
368 ERROR(EROFS, 0);
369
370 vol->mdb.drClpSiz = ent->clumpsz;
371
372 vol->mdb.drCrDate = d_mtime(ent->crdate);
373 vol->mdb.drLsMod = d_mtime(ent->mddate);
374 vol->mdb.drVolBkUp = d_mtime(ent->bkdate);
375
376 vol->mdb.drFndrInfo[0] = ent->blessed;
377
378 vol->flags |= HFS_VOL_UPDATE_MDB;
379
380 return 0;
381
382 fail:
383 return -1;
384 }
385
386 /* High-Level Directory Routines =========================================== */
387
388 /*
389 * NAME: hfs->chdir()
390 * DESCRIPTION: change current HFS directory
391 */
392 int hfs_chdir(hfsvol *vol, const char *path)
393 {
394 CatDataRec data;
395
396 if (getvol(&vol) == -1 ||
397 v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
398 goto fail;
399
400 if (data.cdrType != cdrDirRec)
401 ERROR(ENOTDIR, 0);
402
403 vol->cwd = data.u.dir.dirDirID;
404
405 return 0;
406
407 fail:
408 return -1;
409 }
410
411 /*
412 * NAME: hfs->getcwd()
413 * DESCRIPTION: return the current working directory ID
414 */
415 unsigned long hfs_getcwd(hfsvol *vol)
416 {
417 if (getvol(&vol) == -1)
418 return 0;
419
420 return vol->cwd;
421 }
422
423 /*
424 * NAME: hfs->setcwd()
425 * DESCRIPTION: set the current working directory ID
426 */
427 int hfs_setcwd(hfsvol *vol, unsigned long id)
428 {
429 if (getvol(&vol) == -1)
430 goto fail;
431
432 if (id == vol->cwd)
433 goto done;
434
435 /* make sure the directory exists */
436
437 if (v_getdthread(vol, id, 0, 0) <= 0)
438 goto fail;
439
440 vol->cwd = id;
441
442 done:
443 return 0;
444
445 fail:
446 return -1;
447 }
448
449 /*
450 * NAME: hfs->dirinfo()
451 * DESCRIPTION: given a directory ID, return its (name and) parent ID
452 */
453 int hfs_dirinfo(hfsvol *vol, unsigned long *id, char *name)
454 {
455 CatDataRec thread;
456
457 if (getvol(&vol) == -1 ||
458 v_getdthread(vol, *id, &thread, 0) <= 0)
459 goto fail;
460
461 *id = thread.u.dthd.thdParID;
462
463 if (name)
464 strcpy(name, thread.u.dthd.thdCName);
465
466 return 0;
467
468 fail:
469 return -1;
470 }
471
472 /*
473 * NAME: hfs->opendir()
474 * DESCRIPTION: prepare to read the contents of a directory
475 */
476 hfsdir *hfs_opendir(hfsvol *vol, const char *path)
477 {
478 hfsdir *dir = 0;
479 CatKeyRec key;
480 CatDataRec data;
481 byte pkey[HFS_CATKEYLEN];
482
483 if (getvol(&vol) == -1)
484 goto fail;
485
486 dir = ALLOC(hfsdir, 1);
487 if (dir == 0)
488 ERROR(ENOMEM, 0);
489
490 dir->vol = vol;
491
492 if (*path == 0)
493 {
494 /* meta-directory containing root dirs from all mounted volumes */
495
496 dir->dirid = 0;
497 dir->vptr = hfs_mounts;
498 }
499 else
500 {
501 if (v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
502 goto fail;
503
504 if (data.cdrType != cdrDirRec)
505 ERROR(ENOTDIR, 0);
506
507 dir->dirid = data.u.dir.dirDirID;
508 dir->vptr = 0;
509
510 r_makecatkey(&key, dir->dirid, "");
511 r_packcatkey(&key, pkey, 0);
512
513 if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
514 goto fail;
515 }
516
517 dir->prev = 0;
518 dir->next = vol->dirs;
519
520 if (vol->dirs)
521 vol->dirs->prev = dir;
522
523 vol->dirs = dir;
524
525 return dir;
526
527 fail:
528 FREE(dir);
529 return 0;
530 }
531
532 /*
533 * NAME: hfs->opendir_by_id()
534 * DESCRIPTION: prepare to read the contents of a directory
535 */
536 hfsdir *hfs_opendir_by_id(hfsvol *vol, int id)
537 {
538 hfsdir *dir = 0;
539 CatKeyRec key;
540 /* CatDataRec data;*/
541 byte pkey[HFS_CATKEYLEN];
542
543 if (getvol(&vol) == -1)
544 goto fail;
545
546 dir = ALLOC(hfsdir, 1);
547 if (dir == 0)
548 ERROR(ENOMEM, 0);
549
550 dir->vol = vol;
551
552 /* if (v_resolve(&vol, path, &data, 0, 0, 0) <= 0)
553 goto fail;
554
555 if (data.cdrType != cdrDirRec)
556 ERROR(ENOTDIR, 0);*/
557
558 dir->dirid = id;
559 dir->vptr = 0;
560
561 r_makecatkey(&key, dir->dirid, "");
562 r_packcatkey(&key, pkey, 0);
563
564 if (bt_search(&vol->cat, pkey, &dir->n) <= 0)
565 goto fail;
566
567 dir->prev = 0;
568 dir->next = vol->dirs;
569
570 if (vol->dirs)
571 vol->dirs->prev = dir;
572
573 vol->dirs = dir;
574
575 return dir;
576
577 fail:
578 FREE(dir);
579 return 0;
580 }
581
582 /*
583 * NAME: hfs->readdir()
584 * DESCRIPTION: return the next entry in the directory
585 */
586 int hfs_readdir(hfsdir *dir, hfsdirent *ent)
587 {
588 CatKeyRec key;
589 CatDataRec data;
590 const byte *ptr;
591
592 if (dir->dirid == 0)
593 {
594 hfsvol *vol;
595 char cname[HFS_MAX_FLEN + 1];
596
597 for (vol = hfs_mounts; vol; vol = vol->next)
598 {
599 if (vol == dir->vptr)
600 break;
601 }
602
603 if (vol == 0)
604 ERROR(ENOENT, "no more entries");
605
606 if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, 0) <= 0 ||
607 v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
608 &data, cname, 0) <= 0)
609 goto fail;
610
611 r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);
612
613 dir->vptr = vol->next;
614
615 goto done;
616 }
617
618 if (dir->n.rnum == -1)
619 ERROR(ENOENT, "no more entries");
620
621 while (1)
622 {
623 ++dir->n.rnum;
624
625 while (dir->n.rnum >= dir->n.nd.ndNRecs)
626 {
627 if (dir->n.nd.ndFLink == 0)
628 {
629 dir->n.rnum = -1;
630 ERROR(ENOENT, "no more entries");
631 }
632
633 if (bt_getnode(&dir->n, dir->n.bt, dir->n.nd.ndFLink) == -1)
634 {
635 dir->n.rnum = -1;
636 goto fail;
637 }
638
639 dir->n.rnum = 0;
640 }
641
642 ptr = HFS_NODEREC(dir->n, dir->n.rnum);
643
644 r_unpackcatkey(ptr, &key);
645
646 if (key.ckrParID != dir->dirid)
647 {
648 dir->n.rnum = -1;
649 ERROR(ENOENT, "no more entries");
650 }
651
652 r_unpackcatdata(HFS_RECDATA(ptr), &data);
653
654 switch (data.cdrType)
655 {
656 case cdrDirRec:
657 case cdrFilRec:
658 r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
659 goto done;
660
661 case cdrThdRec:
662 case cdrFThdRec:
663 break;
664
665 default:
666 dir->n.rnum = -1;
667 ERROR(EIO, "unexpected directory entry found");
668 }
669 }
670
671 done:
672 return 0;
673
674 fail:
675 return -1;
676 }
677
678 /*
679 * NAME: hfs->closedir()
680 * DESCRIPTION: stop reading a directory
681 */
682 int hfs_closedir(hfsdir *dir)
683 {
684 hfsvol *vol = dir->vol;
685
686 if (dir->prev)
687 dir->prev->next = dir->next;
688 if (dir->next)
689 dir->next->prev = dir->prev;
690 if (dir == vol->dirs)
691 vol->dirs = dir->next;
692
693 FREE(dir);
694
695 return 0;
696 }
697
698 /* High-Level File Routines ================================================ */
699
700 /*
701 * NAME: hfs->create()
702 * DESCRIPTION: create and open a new file
703 */
704 hfsfile *hfs_create(hfsvol *vol, const char *path,
705 const char *type, const char *creator)
706 {
707 hfsfile *file = 0;
708 unsigned long parid;
709 char name[HFS_MAX_FLEN + 1];
710 CatKeyRec key;
711 byte record[HFS_MAX_CATRECLEN];
712 unsigned reclen;
713 int found;
714
715 if (getvol(&vol) == -1)
716 goto fail;
717
718 file = ALLOC(hfsfile, 1);
719 if (file == 0)
720 ERROR(ENOMEM, 0);
721
722 found = v_resolve(&vol, path, &file->cat, &parid, name, 0);
723 if (found == -1 || parid == 0)
724 goto fail;
725
726 if (found)
727 ERROR(EEXIST, 0);
728
729 if (parid == HFS_CNID_ROOTPAR)
730 ERROR(EINVAL, 0);
731
732 if (vol->flags & HFS_VOL_READONLY)
733 ERROR(EROFS, 0);
734
735 /* create file `name' in parent `parid' */
736
737 if (bt_space(&vol->cat, 1) == -1)
738 goto fail;
739
740 f_init(file, vol, vol->mdb.drNxtCNID++, name);
741 vol->flags |= HFS_VOL_UPDATE_MDB;
742
743 file->parid = parid;
744
745 /* create catalog record */
746
747 file->cat.u.fil.filUsrWds.fdType =
748 d_getsl((const unsigned char *) type);
749 file->cat.u.fil.filUsrWds.fdCreator =
750 d_getsl((const unsigned char *) creator);
751
752 file->cat.u.fil.filCrDat = d_mtime(time(0));
753 file->cat.u.fil.filMdDat = file->cat.u.fil.filCrDat;
754
755 r_makecatkey(&key, file->parid, file->name);
756 r_packcatrec(&key, &file->cat, record, &reclen);
757
758 if (bt_insert(&vol->cat, record, reclen) == -1 ||
759 v_adjvalence(vol, file->parid, 0, 1) == -1)
760 goto fail;
761
762 /* package file handle for user */
763
764 file->next = vol->files;
765
766 if (vol->files)
767 vol->files->prev = file;
768
769 vol->files = file;
770
771 return file;
772
773 fail:
774 FREE(file);
775 return 0;
776 }
777
778 /*
779 * NAME: hfs->open()
780 * DESCRIPTION: prepare a file for I/O
781 */
782 hfsfile *hfs_open(hfsvol *vol, const char *path)
783 {
784 hfsfile *file = 0;
785
786 if (getvol(&vol) == -1)
787 goto fail;
788
789 file = ALLOC(hfsfile, 1);
790 if (file == 0)
791 ERROR(ENOMEM, 0);
792
793 if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, 0) <= 0)
794 goto fail;
795
796 if (file->cat.cdrType != cdrFilRec)
797 ERROR(EISDIR, 0);
798
799 /* package file handle for user */
800
801 file->vol = vol;
802 file->flags = 0;
803
804 f_selectfork(file, fkData);
805
806 file->prev = 0;
807 file->next = vol->files;
808
809 if (vol->files)
810 vol->files->prev = file;
811
812 vol->files = file;
813
814 return file;
815
816 fail:
817 FREE(file);
818 return 0;
819 }
820
821 /*
822 * NAME: hfs->open_by_id()
823 * DESCRIPTION: prepare a file for I/O
824 */
825 hfsfile *hfs_open_by_dirent(hfsvol *vol, hfsdirent *dirent)
826 {
827 hfsfile *file = 0;
828 int found;
829
830 if (getvol(&vol) == -1)
831 goto fail;
832
833 file = ALLOC(hfsfile, 1);
834 if (file == 0)
835 ERROR(ENOMEM, 0);
836
837 memcpy(file->name, dirent->name, 31);
838 file->name[31] = 0;
839 file->parid = dirent->parid;
840
841 found = v_catsearch(vol, file->parid, file->name, &file->cat, 0, NULL);
842 if (found != 1)
843 goto fail;
844
845 if (file->cat.cdrType != cdrFilRec)
846 ERROR(EISDIR, 0);
847
848 /* package file handle for user */
849
850 file->vol = vol;
851 file->flags = 0;
852
853 f_selectfork(file, fkData);
854
855 file->prev = 0;
856 file->next = vol->files;
857
858 if (vol->files)
859 vol->files->prev = file;
860
861 vol->files = file;
862
863 return file;
864
865 fail:
866 FREE(file);
867 return 0;
868 }
869
870 /*
871 * NAME: hfs->setfork()
872 * DESCRIPTION: select file fork for I/O operations
873 */
874 int hfs_setfork(hfsfile *file, int fork)
875 {
876 int result = 0;
877
878 if (f_trunc(file) == -1)
879 result = -1;
880
881 f_selectfork(file, fork ? fkRsrc : fkData);
882
883 return result;
884 }
885
886 /*
887 * NAME: hfs->getfork()
888 * DESCRIPTION: return the current fork for I/O operations
889 */
890 int hfs_getfork(hfsfile *file)
891 {
892 return file->fork != fkData;
893 }
894
895 /*
896 * NAME: hfs->read()
897 * DESCRIPTION: read from an open file
898 */
899 unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len)
900 {
901 unsigned long *lglen, count;
902 byte *ptr = buf;
903
904 f_getptrs(file, 0, &lglen, 0);
905
906 if (file->pos + len > *lglen)
907 len = *lglen - file->pos;
908
909 count = len;
910 while (count)
911 {
912 unsigned long bnum, offs, chunk;
913
914 bnum = file->pos >> HFS_BLOCKSZ_BITS;
915 offs = file->pos & (HFS_BLOCKSZ - 1);
916
917 chunk = HFS_BLOCKSZ - offs;
918 if (chunk > count)
919 chunk = count;
920
921 if (offs == 0 && chunk == HFS_BLOCKSZ)
922 {
923 if (f_getblock(file, bnum, (block *) ptr) == -1)
924 goto fail;
925 }
926 else
927 {
928 block b;
929
930 if (f_getblock(file, bnum, &b) == -1)
931 goto fail;
932
933 memcpy(ptr, b + offs, chunk);
934 }
935
936 ptr += chunk;
937
938 file->pos += chunk;
939 count -= chunk;
940 }
941
942 return len;
943
944 fail:
945 return -1;
946 }
947
948 /*
949 * NAME: hfs->write()
950 * DESCRIPTION: write to an open file
951 */
952 unsigned long hfs_write(hfsfile *file, const void *buf, unsigned long len)
953 {
954 unsigned long *lglen, *pylen, count;
955 const byte *ptr = buf;
956
957 if (file->vol->flags & HFS_VOL_READONLY)
958 ERROR(EROFS, 0);
959
960 f_getptrs(file, 0, &lglen, &pylen);
961
962 count = len;
963
964 /* set flag to update (at least) the modification time */
965
966 if (count)
967 {
968 file->cat.u.fil.filMdDat = d_mtime(time(0));
969 file->flags |= HFS_FILE_UPDATE_CATREC;
970 }
971
972 while (count)
973 {
974 unsigned long bnum, offs, chunk;
975
976 bnum = file->pos >> HFS_BLOCKSZ_BITS;
977 offs = file->pos & (HFS_BLOCKSZ - 1);
978
979 chunk = HFS_BLOCKSZ - offs;
980 if (chunk > count)
981 chunk = count;
982
983 if (file->pos + chunk > *pylen)
984 {
985 if (bt_space(&file->vol->ext, 1) == -1 ||
986 f_alloc(file) == -1)
987 goto fail;
988 }
989
990 if (offs == 0 && chunk == HFS_BLOCKSZ)
991 {
992 if (f_putblock(file, bnum, (block *) ptr) == -1)
993 goto fail;
994 }
995 else
996 {
997 block b;
998
999 if (f_getblock(file, bnum, &b) == -1)
1000 goto fail;
1001
1002 memcpy(b + offs, ptr, chunk);
1003
1004 if (f_putblock(file, bnum, &b) == -1)
1005 goto fail;
1006 }
1007
1008 ptr += chunk;
1009
1010 file->pos += chunk;
1011 count -= chunk;
1012
1013 if (file->pos > *lglen)
1014 *lglen = file->pos;
1015 }
1016
1017 return len;
1018
1019 fail:
1020 return -1;
1021 }
1022
1023 /*
1024 * NAME: hfs->truncate()
1025 * DESCRIPTION: truncate an open file
1026 */
1027 int hfs_truncate(hfsfile *file, unsigned long len)
1028 {
1029 unsigned long *lglen;
1030
1031 f_getptrs(file, 0, &lglen, 0);
1032
1033 if (*lglen > len)
1034 {
1035 if (file->vol->flags & HFS_VOL_READONLY)
1036 ERROR(EROFS, 0);
1037
1038 *lglen = len;
1039
1040 file->cat.u.fil.filMdDat = d_mtime(time(0));
1041 file->flags |= HFS_FILE_UPDATE_CATREC;
1042
1043 if (file->pos > len)
1044 file->pos = len;
1045 }
1046
1047 return 0;
1048
1049 fail:
1050 return -1;
1051 }
1052
1053 /*
1054 * NAME: hfs->seek()
1055 * DESCRIPTION: change file seek pointer
1056 */
1057 unsigned long hfs_seek(hfsfile *file, long offset, int from)
1058 {
1059 unsigned long *lglen, newpos;
1060
1061 f_getptrs(file, 0, &lglen, 0);
1062
1063 switch (from)
1064 {
1065 case HFS_SEEK_SET:
1066 newpos = (offset < 0) ? 0 : offset;
1067 break;
1068
1069 case HFS_SEEK_CUR:
1070 if (offset < 0 && (unsigned long) -offset > file->pos)
1071 newpos = 0;
1072 else
1073 newpos = file->pos + offset;
1074 break;
1075
1076 case HFS_SEEK_END:
1077 if (offset < 0 && (unsigned long) -offset > *lglen)
1078 newpos = 0;
1079 else
1080 newpos = *lglen + offset;
1081 break;
1082
1083 default:
1084 ERROR(EINVAL, 0);
1085 }
1086
1087 if (newpos > *lglen)
1088 newpos = *lglen;
1089
1090 file->pos = newpos;
1091
1092 return newpos;
1093
1094 fail:
1095 return -1;
1096 }
1097
1098 /*
1099 * NAME: hfs->close()
1100 * DESCRIPTION: close a file
1101 */
1102 int hfs_close(hfsfile *file)
1103 {
1104 hfsvol *vol = file->vol;
1105 int result = 0;
1106
1107 if (f_trunc(file) == -1 ||
1108 f_flush(file) == -1)
1109 result = -1;
1110
1111 if (file->prev)
1112 file->prev->next = file->next;
1113 if (file->next)
1114 file->next->prev = file->prev;
1115 if (file == vol->files)
1116 vol->files = file->next;
1117
1118 FREE(file);
1119
1120 return result;
1121 }
1122
1123 /* High-Level Catalog Routines ============================================= */
1124
1125 /*
1126 * NAME: hfs->stat()
1127 * DESCRIPTION: return catalog information for an arbitrary path
1128 */
1129 int hfs_stat(hfsvol *vol, const char *path, hfsdirent *ent)
1130 {
1131 CatDataRec data;
1132 unsigned long parid;
1133 char name[HFS_MAX_FLEN + 1];
1134
1135 if (getvol(&vol) == -1 ||
1136 v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
1137 goto fail;
1138
1139 r_unpackdirent(parid, name, &data, ent);
1140
1141 return 0;
1142
1143 fail:
1144 return -1;
1145 }
1146
1147 /*
1148 * NAME: hfs->fstat()
1149 * DESCRIPTION: return catalog information for an open file
1150 */
1151 int hfs_fstat(hfsfile *file, hfsdirent *ent)
1152 {
1153 r_unpackdirent(file->parid, file->name, &file->cat, ent);
1154
1155 return 0;
1156 }
1157
1158 /*
1159 * NAME: hfs->setattr()
1160 * DESCRIPTION: change a file's attributes
1161 */
1162 int hfs_setattr(hfsvol *vol, const char *path, const hfsdirent *ent)
1163 {
1164 CatDataRec data;
1165 node n;
1166
1167 if (getvol(&vol) == -1 ||
1168 v_resolve(&vol, path, &data, 0, 0, &n) <= 0)
1169 goto fail;
1170
1171 if (vol->flags & HFS_VOL_READONLY)
1172 ERROR(EROFS, 0);
1173
1174 r_packdirent(&data, ent);
1175
1176 return v_putcatrec(&data, &n);
1177
1178 fail:
1179 return -1;
1180 }
1181
1182 /*
1183 * NAME: hfs->fsetattr()
1184 * DESCRIPTION: change an open file's attributes
1185 */
1186 int hfs_fsetattr(hfsfile *file, const hfsdirent *ent)
1187 {
1188 if (file->vol->flags & HFS_VOL_READONLY)
1189 ERROR(EROFS, 0);
1190
1191 r_packdirent(&file->cat, ent);
1192
1193 file->flags |= HFS_FILE_UPDATE_CATREC;
1194
1195 return 0;
1196
1197 fail:
1198 return -1;
1199 }
1200
1201 /*
1202 * NAME: hfs->mkdir()
1203 * DESCRIPTION: create a new directory
1204 */
1205 int hfs_mkdir(hfsvol *vol, const char *path)
1206 {
1207 CatDataRec data;
1208 unsigned long parid;
1209 char name[HFS_MAX_FLEN + 1];
1210 int found;
1211
1212 if (getvol(&vol) == -1)
1213 goto fail;
1214
1215 found = v_resolve(&vol, path, &data, &parid, name, 0);
1216 if (found == -1 || parid == 0)
1217 goto fail;
1218
1219 if (found)
1220 ERROR(EEXIST, 0);
1221
1222 if (parid == HFS_CNID_ROOTPAR)
1223 ERROR(EINVAL, 0);
1224
1225 if (vol->flags & HFS_VOL_READONLY)
1226 ERROR(EROFS, 0);
1227
1228 return v_mkdir(vol, parid, name);
1229
1230 fail:
1231 return -1;
1232 }
1233
1234 /*
1235 * NAME: hfs->rmdir()
1236 * DESCRIPTION: delete an empty directory
1237 */
1238 int hfs_rmdir(hfsvol *vol, const char *path)
1239 {
1240 CatKeyRec key;
1241 CatDataRec data;
1242 unsigned long parid;
1243 char name[HFS_MAX_FLEN + 1];
1244 byte pkey[HFS_CATKEYLEN];
1245
1246 if (getvol(&vol) == -1 ||
1247 v_resolve(&vol, path, &data, &parid, name, 0) <= 0)
1248 goto fail;
1249
1250 if (data.cdrType != cdrDirRec)
1251 ERROR(ENOTDIR, 0);
1252
1253 if (data.u.dir.dirVal != 0)
1254 ERROR(ENOTEMPTY, 0);
1255
1256 if (parid == HFS_CNID_ROOTPAR)
1257 ERROR(EINVAL, 0);
1258
1259 if (vol->flags & HFS_VOL_READONLY)
1260 ERROR(EROFS, 0);
1261
1262 /* delete directory record */
1263
1264 r_makecatkey(&key, parid, name);
1265 r_packcatkey(&key, pkey, 0);
1266
1267 if (bt_delete(&vol->cat, pkey) == -1)
1268 goto fail;
1269
1270 /* delete thread record */
1271
1272 r_makecatkey(&key, data.u.dir.dirDirID, "");
1273 r_packcatkey(&key, pkey, 0);
1274
1275 if (bt_delete(&vol->cat, pkey) == -1 ||
1276 v_adjvalence(vol, parid, 1, -1) == -1)
1277 goto fail;
1278
1279 return 0;
1280
1281 fail:
1282 return -1;
1283 }
1284
1285 /*
1286 * NAME: hfs->delete()
1287 * DESCRIPTION: remove both forks of a file
1288 */
1289 int hfs_delete(hfsvol *vol, const char *path)
1290 {
1291 hfsfile file;
1292 CatKeyRec key;
1293 byte pkey[HFS_CATKEYLEN];
1294 int found;
1295
1296 if (getvol(&vol) == -1 ||
1297 v_resolve(&vol, path, &file.cat, &file.parid, file.name, 0) <= 0)
1298 goto fail;
1299
1300 if (file.cat.cdrType != cdrFilRec)
1301 ERROR(EISDIR, 0);
1302
1303 if (file.parid == HFS_CNID_ROOTPAR)
1304 ERROR(EINVAL, 0);
1305
1306 if (vol->flags & HFS_VOL_READONLY)
1307 ERROR(EROFS, 0);
1308
1309 /* free allocation blocks */
1310
1311 file.vol = vol;
1312 file.flags = 0;
1313
1314 file.cat.u.fil.filLgLen = 0;
1315 file.cat.u.fil.filRLgLen = 0;
1316
1317 f_selectfork(&file, fkData);
1318 if (f_trunc(&file) == -1)
1319 goto fail;
1320
1321 f_selectfork(&file, fkRsrc);
1322 if (f_trunc(&file) == -1)
1323 goto fail;
1324
1325 /* delete file record */
1326
1327 r_makecatkey(&key, file.parid, file.name);
1328 r_packcatkey(&key, pkey, 0);
1329
1330 if (bt_delete(&vol->cat, pkey) == -1 ||
1331 v_adjvalence(vol, file.parid, 0, -1) == -1)
1332 goto fail;
1333
1334 /* delete file thread, if any */
1335
1336 found = v_getfthread(vol, file.cat.u.fil.filFlNum, 0, 0);
1337 if (found == -1)
1338 goto fail;
1339
1340 if (found)
1341 {
1342 r_makecatkey(&key, file.cat.u.fil.filFlNum, "");
1343 r_packcatkey(&key, pkey, 0);
1344
1345 if (bt_delete(&vol->cat, pkey) == -1)
1346 goto fail;
1347 }
1348
1349 return 0;
1350
1351 fail:
1352 return -1;
1353 }
1354
1355 /*
1356 * NAME: hfs->rename()
1357 * DESCRIPTION: change the name of and/or move a file or directory
1358 */
1359 int hfs_rename(hfsvol *vol, const char *srcpath, const char *dstpath)
1360 {
1361 hfsvol *srcvol;
1362 CatDataRec src, dst;
1363 unsigned long srcid, dstid;
1364 CatKeyRec key;
1365 char srcname[HFS_MAX_FLEN + 1], dstname[HFS_MAX_FLEN + 1];
1366 byte record[HFS_MAX_CATRECLEN];
1367 unsigned int reclen;
1368 int found, isdir, moving;
1369 node n;
1370
1371 if (getvol(&vol) == -1 ||
1372 v_resolve(&vol, srcpath, &src, &srcid, srcname, 0) <= 0)
1373 goto fail;
1374
1375 isdir = (src.cdrType == cdrDirRec);
1376 srcvol = vol;
1377
1378 found = v_resolve(&vol, dstpath, &dst, &dstid, dstname, 0);
1379 if (found == -1)
1380 goto fail;
1381
1382 if (vol != srcvol)
1383 ERROR(EINVAL, "can't move across volumes");
1384
1385 if (dstid == 0)
1386 ERROR(ENOENT, "bad destination path");
1387
1388 if (found &&
1389 dst.cdrType == cdrDirRec &&
1390 dst.u.dir.dirDirID != src.u.dir.dirDirID)
1391 {
1392 dstid = dst.u.dir.dirDirID;
1393 strcpy(dstname, srcname);
1394
1395 found = v_catsearch(vol, dstid, dstname, 0, 0, 0);
1396 if (found == -1)
1397 goto fail;
1398 }
1399
1400 moving = (srcid != dstid);
1401
1402 if (found)
1403 {
1404 const char *ptr;
1405
1406 ptr = strrchr(dstpath, '/');
1407 if (ptr == 0)
1408 ptr = dstpath;
1409 else
1410 ++ptr;
1411
1412 if (*ptr)
1413 strcpy(dstname, ptr);
1414
1415 if (! moving && strcmp(srcname, dstname) == 0)
1416 goto done; /* source and destination are identical */
1417
1418 if (moving || d_relstring(srcname, dstname))
1419 ERROR(EEXIST, "can't use destination name");
1420 }
1421
1422 /* can't move anything into the root directory's parent */
1423
1424 if (moving && dstid == HFS_CNID_ROOTPAR)
1425 ERROR(EINVAL, "can't move above root directory");
1426
1427 if (moving && isdir)
1428 {
1429 unsigned long id;
1430
1431 /* can't move root directory anywhere */
1432
1433 if (src.u.dir.dirDirID == HFS_CNID_ROOTDIR)
1434 ERROR(EINVAL, "can't move root directory");
1435
1436 /* make sure we aren't trying to move a directory inside itself */
1437
1438 for (id = dstid; id != HFS_CNID_ROOTDIR; id = dst.u.dthd.thdParID)
1439 {
1440 if (id == src.u.dir.dirDirID)
1441 ERROR(EINVAL, "can't move directory inside itself");
1442
1443 if (v_getdthread(vol, id, &dst, 0) <= 0)
1444 goto fail;
1445 }
1446 }
1447
1448 if (vol->flags & HFS_VOL_READONLY)
1449 ERROR(EROFS, 0);
1450
1451 /* change volume name */
1452
1453 if (dstid == HFS_CNID_ROOTPAR)
1454 {
1455 if (! validvname(dstname))
1456 goto fail;
1457
1458 strcpy(vol->mdb.drVN, dstname);
1459 vol->flags |= HFS_VOL_UPDATE_MDB;
1460 }
1461
1462 /* remove source record */
1463
1464 r_makecatkey(&key, srcid, srcname);
1465 r_packcatkey(&key, record, 0);
1466
1467 if (bt_delete(&vol->cat, record) == -1)
1468 goto fail;
1469
1470 /* insert destination record */
1471
1472 r_makecatkey(&key, dstid, dstname);
1473 r_packcatrec(&key, &src, record, &reclen);
1474
1475 if (bt_insert(&vol->cat, record, reclen) == -1)
1476 goto fail;
1477
1478 /* update thread record */
1479
1480 if (isdir)
1481 {
1482 if (v_getdthread(vol, src.u.dir.dirDirID, &dst, &n) <= 0)
1483 goto fail;
1484
1485 dst.u.dthd.thdParID = dstid;
1486 strcpy(dst.u.dthd.thdCName, dstname);
1487
1488 if (v_putcatrec(&dst, &n) == -1)
1489 goto fail;
1490 }
1491 else
1492 {
1493 found = v_getfthread(vol, src.u.fil.filFlNum, &dst, &n);
1494 if (found == -1)
1495 goto fail;
1496
1497 if (found)
1498 {
1499 dst.u.fthd.fthdParID = dstid;
1500 strcpy(dst.u.fthd.fthdCName, dstname);
1501
1502 if (v_putcatrec(&dst, &n) == -1)
1503 goto fail;
1504 }
1505 }
1506
1507 /* update directory valences */
1508
1509 if (moving)
1510 {
1511 if (v_adjvalence(vol, srcid, isdir, -1) == -1 ||
1512 v_adjvalence(vol, dstid, isdir, 1) == -1)
1513 goto fail;
1514 }
1515
1516 done:
1517 return 0;
1518
1519 fail:
1520 return -1;
1521 }
1522
1523 /* High-Level Media Routines =============================================== */
1524
1525 /*
1526 * NAME: hfs->mkpart()
1527 * DESCRIPTION: create a new HFS partition
1528 */
1529 int hfs_mkpart(const void *devicehandle, unsigned long len)
1530 {
1531 hfsvol vol;
1532
1533 v_init(&vol, HFS_OPT_NOCACHE);
1534
1535 if (v_open(&vol, devicehandle, HFS_MODE_RDWR) == -1)
1536 goto fail;
1537
1538 if (m_mkpart(&vol, "MacOS", "Apple_HFS", len) == -1)
1539 goto fail;
1540
1541 if (v_close(&vol) == -1)
1542 goto fail;
1543
1544 return 0;
1545
1546 fail:
1547 v_close(&vol);
1548 return -1;
1549 }
1550
1551 /*
1552 * NAME: hfs->nparts()
1553 * DESCRIPTION: return the number of HFS partitions in the medium
1554 */
1555 int hfs_nparts(const void *devicehandle)
1556 {
1557 hfsvol vol;
1558 int nparts, found;
1559 ApplePartition map;
1560 unsigned long bnum = 0;
1561
1562 v_init(&vol, HFS_OPT_NOCACHE);
1563
1564 if (v_open(&vol, devicehandle, HFS_MODE_RDONLY) == -1)
1565 goto fail;
1566
1567 nparts = 0;
1568 while (1)
1569 {
1570 found = m_findpmentry(&vol, "Apple_HFS", &map, &bnum);
1571 if (found == -1)
1572 goto fail;
1573
1574 if (! found)
1575 break;
1576
1577 ++nparts;
1578 }
1579
1580 if (v_close(&vol) == -1)
1581 goto fail;
1582
1583 return nparts;
1584
1585 fail:
1586 v_close(&vol);
1587 return -1;
1588 }
1589
1590 /*
1591 * NAME: compare()
1592 * DESCRIPTION: comparison function for qsort of blocks to be spared
1593 */
1594 static
1595 int compare(const unsigned int *n1, const unsigned int *n2)
1596 {
1597 return *n1 - *n2;
1598 }
1599
1600 /*
1601 * NAME: hfs->format()
1602 * DESCRIPTION: write a new filesystem
1603 */
1604 int hfs_format(const void *devicehandle, int pnum, int mode, const char *vname,
1605 unsigned int nbadblocks, const unsigned long badblocks[])
1606 {
1607 hfsvol vol;
1608 btree *ext = &vol.ext;
1609 btree *cat = &vol.cat;
1610 unsigned int i, *badalloc = 0;
1611
1612 v_init(&vol, mode);
1613
1614 if (! validvname(vname))
1615 goto fail;
1616
1617 if (v_open(&vol, devicehandle, HFS_MODE_RDWR) == -1 ||
1618 v_geometry(&vol, pnum) == -1)
1619 goto fail;
1620
1621 /* initialize volume geometry */
1622
1623 vol.lpa = 1 + ((vol.vlen - 6) >> 16);
1624
1625 if (vol.flags & HFS_OPT_2048)
1626 vol.lpa = (vol.lpa + 3) & ~3;
1627
1628 vol.vbmsz = (vol.vlen / vol.lpa + 0x0fff) >> 12;
1629
1630 vol.mdb.drSigWord = HFS_SIGWORD;
1631 vol.mdb.drCrDate = d_mtime(time(0));
1632 vol.mdb.drLsMod = vol.mdb.drCrDate;
1633 vol.mdb.drAtrb = 0;
1634 vol.mdb.drNmFls = 0;
1635 vol.mdb.drVBMSt = 3;
1636 vol.mdb.drAllocPtr = 0;
1637
1638 vol.mdb.drAlBlkSiz = vol.lpa << HFS_BLOCKSZ_BITS;
1639 vol.mdb.drClpSiz = vol.mdb.drAlBlkSiz << 2;
1640 vol.mdb.drAlBlSt = vol.mdb.drVBMSt + vol.vbmsz;
1641
1642 if (vol.flags & HFS_OPT_2048)
1643 vol.mdb.drAlBlSt = ((vol.vstart & 3) + vol.mdb.drAlBlSt + 3) & ~3;
1644
1645 vol.mdb.drNmAlBlks = (vol.vlen - 2 - vol.mdb.drAlBlSt) / vol.lpa;
1646
1647 vol.mdb.drNxtCNID = HFS_CNID_ROOTDIR; /* modified later */
1648 vol.mdb.drFreeBks = vol.mdb.drNmAlBlks;
1649
1650 strcpy(vol.mdb.drVN, vname);
1651
1652 vol.mdb.drVolBkUp = 0;
1653 vol.mdb.drVSeqNum = 0;
1654 vol.mdb.drWrCnt = 0;
1655
1656 vol.mdb.drXTClpSiz = vol.mdb.drNmAlBlks / 128 * vol.mdb.drAlBlkSiz;
1657 vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz;
1658
1659 vol.mdb.drNmRtDirs = 0;
1660 vol.mdb.drFilCnt = 0;
1661 vol.mdb.drDirCnt = -1; /* incremented when root directory is created */
1662
1663 for (i = 0; i < 8; ++i)
1664 vol.mdb.drFndrInfo[i] = 0;
1665
1666 vol.mdb.drEmbedSigWord = 0x0000;
1667 vol.mdb.drEmbedExtent.xdrStABN = 0;
1668 vol.mdb.drEmbedExtent.xdrNumABlks = 0;
1669
1670 /* vol.mdb.drXTFlSize */
1671 /* vol.mdb.drCTFlSize */
1672
1673 /* vol.mdb.drXTExtRec[0..2] */
1674 /* vol.mdb.drCTExtRec[0..2] */
1675
1676 vol.flags |= HFS_VOL_UPDATE_MDB | HFS_VOL_UPDATE_ALTMDB;
1677
1678 /* initialize volume bitmap */
1679
1680 vol.vbm = ALLOC(block, vol.vbmsz);
1681 if (vol.vbm == 0)
1682 ERROR(ENOMEM, 0);
1683
1684 memset(vol.vbm, 0, vol.vbmsz << HFS_BLOCKSZ_BITS);
1685
1686 vol.flags |= HFS_VOL_UPDATE_VBM;
1687
1688 /* perform initial bad block sparing */
1689
1690 if (nbadblocks > 0)
1691 {
1692 if (nbadblocks * 4 > vol.vlen)
1693 ERROR(EINVAL, "volume contains too many bad blocks");
1694
1695 badalloc = ALLOC(unsigned int, nbadblocks);
1696 if (badalloc == 0)
1697 ERROR(ENOMEM, 0);
1698
1699 if (vol.mdb.drNmAlBlks == 1594)
1700 vol.mdb.drFreeBks = --vol.mdb.drNmAlBlks;
1701
1702 for (i = 0; i < nbadblocks; ++i)
1703 {
1704 unsigned long bnum;
1705 unsigned int anum;
1706
1707 bnum = badblocks[i];
1708
1709 if (bnum < vol.mdb.drAlBlSt || bnum == vol.vlen - 2)
1710 ERROR(EINVAL, "can't spare critical bad block");
1711 else if (bnum >= vol.vlen)
1712 ERROR(EINVAL, "bad block not in volume");
1713
1714 anum = (bnum - vol.mdb.drAlBlSt) / vol.lpa;
1715
1716 if (anum < vol.mdb.drNmAlBlks)
1717 BMSET(vol.vbm, anum);
1718
1719 badalloc[i] = anum;
1720 }
1721
1722 vol.mdb.drAtrb |= HFS_ATRB_BBSPARED;
1723 }
1724
1725 /* create extents overflow file */
1726
1727 n_init(&ext->hdrnd, ext, ndHdrNode, 0);
1728
1729 ext->hdrnd.nnum = 0;
1730 ext->hdrnd.nd.ndNRecs = 3;
1731 ext->hdrnd.roff[1] = 0x078;
1732 ext->hdrnd.roff[2] = 0x0f8;
1733 ext->hdrnd.roff[3] = 0x1f8;
1734
1735 memset(HFS_NODEREC(ext->hdrnd, 1), 0, 128);
1736
1737 ext->hdr.bthDepth = 0;
1738 ext->hdr.bthRoot = 0;
1739 ext->hdr.bthNRecs = 0;
1740 ext->hdr.bthFNode = 0;
1741 ext->hdr.bthLNode = 0;
1742 ext->hdr.bthNodeSize = HFS_BLOCKSZ;
1743 ext->hdr.bthKeyLen = 0x07;
1744 ext->hdr.bthNNodes = 0;
1745 ext->hdr.bthFree = 0;
1746 for (i = 0; i < 76; ++i)
1747 ext->hdr.bthResv[i] = 0;
1748
1749 ext->map = ALLOC(byte, HFS_MAP1SZ);
1750 if (ext->map == 0)
1751 ERROR(ENOMEM, 0);
1752
1753 memset(ext->map, 0, HFS_MAP1SZ);
1754 BMSET(ext->map, 0);
1755
1756 ext->mapsz = HFS_MAP1SZ;
1757 ext->flags = HFS_BT_UPDATE_HDR;
1758
1759 /* create catalog file */
1760
1761 n_init(&cat->hdrnd, cat, ndHdrNode, 0);
1762
1763 cat->hdrnd.nnum = 0;
1764 cat->hdrnd.nd.ndNRecs = 3;
1765 cat->hdrnd.roff[1] = 0x078;
1766 cat->hdrnd.roff[2] = 0x0f8;
1767 cat->hdrnd.roff[3] = 0x1f8;
1768
1769 memset(HFS_NODEREC(cat->hdrnd, 1), 0, 128);
1770
1771 cat->hdr.bthDepth = 0;
1772 cat->hdr.bthRoot = 0;
1773 cat->hdr.bthNRecs = 0;
1774 cat->hdr.bthFNode = 0;
1775 cat->hdr.bthLNode = 0;
1776 cat->hdr.bthNodeSize = HFS_BLOCKSZ;
1777 cat->hdr.bthKeyLen = 0x25;
1778 cat->hdr.bthNNodes = 0;
1779 cat->hdr.bthFree = 0;
1780 for (i = 0; i < 76; ++i)
1781 cat->hdr.bthResv[i] = 0;
1782
1783 cat->map = ALLOC(byte, HFS_MAP1SZ);
1784 if (cat->map == 0)
1785 ERROR(ENOMEM, 0);
1786
1787 memset(cat->map, 0, HFS_MAP1SZ);
1788 BMSET(cat->map, 0);
1789
1790 cat->mapsz = HFS_MAP1SZ;
1791 cat->flags = HFS_BT_UPDATE_HDR;
1792
1793 /* allocate space for header nodes (and initial extents) */
1794
1795 if (bt_space(ext, 1) == -1 ||
1796 bt_space(cat, 1) == -1)
1797 goto fail;
1798
1799 --ext->hdr.bthFree;
1800 --cat->hdr.bthFree;
1801
1802 /* create extent records for bad blocks */
1803
1804 if (nbadblocks > 0)
1805 {
1806 hfsfile bbfile;
1807 ExtDescriptor extent;
1808 ExtDataRec *extrec;
1809 ExtKeyRec key;
1810 byte record[HFS_MAX_EXTRECLEN];
1811 unsigned int reclen;
1812
1813 f_init(&bbfile, &vol, HFS_CNID_BADALLOC, "bad blocks");
1814
1815 qsort(badalloc, nbadblocks, sizeof(*badalloc),
1816 (int (*)(const void *, const void *)) compare);
1817
1818 for (i = 0; i < nbadblocks; ++i)
1819 {
1820 if (i == 0 || badalloc[i] != extent.xdrStABN)
1821 {
1822 extent.xdrStABN = badalloc[i];
1823 extent.xdrNumABlks = 1;
1824
1825 if (extent.xdrStABN < vol.mdb.drNmAlBlks &&
1826 f_addextent(&bbfile, &extent) == -1)
1827 goto fail;
1828 }
1829 }
1830
1831 /* flush local extents into extents overflow file */
1832
1833 f_getptrs(&bbfile, &extrec, 0, 0);
1834
1835 r_makeextkey(&key, bbfile.fork, bbfile.cat.u.fil.filFlNum, 0);
1836 r_packextrec(&key, extrec, record, &reclen);
1837
1838 if (bt_insert(&vol.ext, record, reclen) == -1)
1839 goto fail;
1840 }
1841
1842 vol.flags |= HFS_VOL_MOUNTED;
1843
1844 /* create root directory */
1845
1846 if (v_mkdir(&vol, HFS_CNID_ROOTPAR, vname) == -1)
1847 goto fail;
1848
1849 vol.mdb.drNxtCNID = 16; /* first CNID not reserved by Apple */
1850
1851 /* write boot blocks */
1852
1853 if (m_zerobb(&vol) == -1)
1854 goto fail;
1855
1856 /* zero other unused space, if requested */
1857
1858 if (vol.flags & HFS_OPT_ZERO)
1859 {
1860 block b;
1861 unsigned long bnum;
1862
1863 memset(&b, 0, sizeof(b));
1864
1865 /* between MDB and VBM (never) */
1866
1867 for (bnum = 3; bnum < vol.mdb.drVBMSt; ++bnum)
1868 b_writelb(&vol, bnum, &b);
1869
1870 /* between VBM and first allocation block (sometimes if HFS_OPT_2048) */
1871
1872 for (bnum = vol.mdb.drVBMSt + vol.vbmsz; bnum < vol.mdb.drAlBlSt; ++bnum)
1873 b_writelb(&vol, bnum, &b);
1874
1875 /* between last allocation block and alternate MDB (sometimes) */
1876
1877 for (bnum = vol.mdb.drAlBlSt + vol.mdb.drNmAlBlks * vol.lpa;
1878 bnum < vol.vlen - 2; ++bnum)
1879 b_writelb(&vol, bnum, &b);
1880
1881 /* final block (always) */
1882
1883 b_writelb(&vol, vol.vlen - 1, &b);
1884 }
1885
1886 /* flush remaining state and close volume */
1887
1888 if (v_close(&vol) == -1)
1889 goto fail;
1890
1891 FREE(badalloc);
1892
1893 return 0;
1894
1895 fail:
1896 v_close(&vol);
1897
1898 FREE(badalloc);
1899
1900 return -1;
1901 }

  ViewVC Help
Powered by ViewVC 1.1.26