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