/* * NAME: file->doblock() * DESCRIPTION: read or write a numbered block from a file */ int f_doblock(hfsfile *file, unsigned long number, block *bp, int (*func)(hfsvol *, unsigned int, unsigned int, block *)) { unsigned int abnum; unsigned int blnum; unsigned int fabn; int i; abnum = number / file->vol->lpa; blnum = number % file->vol->lpa; /* locate the appropriate extent record */ fabn = file->fabn; if (abnum < fabn) { ExtDataRec *extrec; f_getptrs(file, 0, 0, &extrec); fabn = file->fabn = 0; memcpy(file->ext, extrec, sizeof(ExtDataRec)); } else abnum -= fabn; for (;;) { unsigned int num; for (i = 0; i < 3; ++i) { num = file->ext[i].xdrNumABlks; #ifdef APPLE_HYB if (i > 0) { /* SHOULD NOT HAPPEN! - all the files should not be fragmented if this happens, then a serious problem has occured, may be a hard linked file? */ #ifdef DEBUG fprintf(stderr,"fragmented file: %s %d\n",file->name, i); */ #endif /* DEBUG */ ERROR(HCE_ERROR, "Possible Catalog file overflow - please report error"); return -1; } #endif /* APPLE_HYB */ if (abnum < num) return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp); fabn += num; abnum -= num; } if (v_extsearch(file, fabn, &file->ext, 0) <= 0) return -1; file->fabn = fabn; }
/* * NAME: file->doblock() * DESCRIPTION: read or write a numbered block from a file */ int f_doblock(hfsfile *file, unsigned long num, block *bp, int (*func)(hfsvol *, unsigned int, unsigned int, block *)) { unsigned int abnum; unsigned int blnum; unsigned int fabn; int i; abnum = num / file->vol->lpa; blnum = num % file->vol->lpa; /* locate the appropriate extent record */ fabn = file->fabn; if (abnum < fabn) { ExtDataRec *extrec; f_getptrs(file, &extrec, 0, 0); fabn = file->fabn = 0; memcpy(&file->ext, extrec, sizeof(ExtDataRec)); } else abnum -= fabn; while (1) { unsigned int n; for (i = 0; i < 3; ++i) { n = file->ext[i].xdrNumABlks; if (abnum < n) return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp); fabn += n; abnum -= n; } if (v_extsearch(file, fabn, &file->ext, 0) <= 0) goto fail; file->fabn = fabn; } fail: return -1; }
/* * NAME: file->trunc() * DESCRIPTION: release allocation blocks unneeded by a file */ int f_trunc(hfsfile *file) { hfsvol *vol = file->vol; ExtDataRec *extrec; ULongInt *lglen, *pylen, alblksz, newpylen; unsigned int dlen, start, end; node n; int i; if (vol->flags & HFS_VOL_READONLY) goto done; f_getptrs(file, &extrec, &lglen, &pylen); alblksz = vol->mdb.drAlBlkSiz; newpylen = (*lglen / alblksz + (*lglen % alblksz != 0)) * alblksz; if (newpylen > *pylen) ERROR(EIO, "file size exceeds physical length"); else if (newpylen == *pylen) goto done; dlen = (*pylen - newpylen) / alblksz; start = file->fabn; end = newpylen / alblksz; if (start >= end) { start = file->fabn = 0; memcpy(&file->ext, extrec, sizeof(ExtDataRec)); } n.nnum = 0; i = -1; while (start < end) { for (i = 0; i < 3; ++i) { unsigned int num; num = file->ext[i].xdrNumABlks; start += num; if (start >= end) break; else if (num == 0) ERROR(EIO, "empty file extent"); } if (start >= end) break; if (v_extsearch(file, start, &file->ext, &n) <= 0) goto fail; file->fabn = start; } if (start > end) { ExtDescriptor blocks; file->ext[i].xdrNumABlks -= start - end; dlen -= start - end; blocks.xdrStABN = file->ext[i].xdrStABN + file->ext[i].xdrNumABlks; blocks.xdrNumABlks = start - end; if (v_freeblocks(vol, &blocks) == -1) goto fail; } *pylen = newpylen; file->flags |= HFS_FILE_UPDATE_CATREC; do { while (dlen && ++i < 3) { unsigned int num; num = file->ext[i].xdrNumABlks; start += num; if (num == 0) ERROR(EIO, "empty file extent"); else if (num > dlen) ERROR(EIO, "file extents exceed physical size"); dlen -= num; if (v_freeblocks(vol, &file->ext[i]) == -1) goto fail; file->ext[i].xdrStABN = 0; file->ext[i].xdrNumABlks = 0; } if (file->fabn) { if (n.nnum == 0 && v_extsearch(file, file->fabn, 0, &n) <= 0) goto fail; if (file->ext[0].xdrNumABlks) { if (v_putextrec(&file->ext, &n) == -1) goto fail; } else { if (bt_delete(&vol->ext, HFS_NODEREC(n, n.rnum)) == -1) goto fail; n.nnum = 0; } } else memcpy(extrec, &file->ext, sizeof(ExtDataRec)); if (dlen) { if (v_extsearch(file, start, &file->ext, &n) <= 0) goto fail; file->fabn = start; i = -1; } } while (dlen); done: return 0; fail: return -1; }
/* * NAME: file->addextent() * DESCRIPTION: add an extent to a file */ int f_addextent(hfsfile *file, ExtDescriptor *blocks) { hfsvol *vol = file->vol; ExtDataRec *extrec; ULongInt *pylen; unsigned int start, end; node n; int i; f_getptrs(file, &extrec, 0, &pylen); start = file->fabn; end = *pylen / vol->mdb.drAlBlkSiz; n.nnum = 0; i = -1; while (start < end) { for (i = 0; i < 3; ++i) { unsigned int num; num = file->ext[i].xdrNumABlks; start += num; if (start == end) break; else if (start > end) ERROR(EIO, "file extents exceed file physical length"); else if (num == 0) ERROR(EIO, "empty file extent"); } if (start == end) break; if (v_extsearch(file, start, &file->ext, &n) <= 0) goto fail; file->fabn = start; } if (i >= 0 && file->ext[i].xdrStABN + file->ext[i].xdrNumABlks == blocks->xdrStABN) file->ext[i].xdrNumABlks += blocks->xdrNumABlks; else { /* create a new extent descriptor */ if (++i < 3) file->ext[i] = *blocks; else { ExtKeyRec key; byte record[HFS_MAX_EXTRECLEN]; unsigned int reclen; /* record is full; create a new one */ file->ext[0] = *blocks; for (i = 1; i < 3; ++i) { file->ext[i].xdrStABN = 0; file->ext[i].xdrNumABlks = 0; } file->fabn = start; r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, end); r_packextrec(&key, &file->ext, record, &reclen); if (bt_insert(&vol->ext, record, reclen) == -1) goto fail; i = -1; } } if (i >= 0) { /* store the modified extent record */ if (file->fabn) { if ((n.nnum == 0 && v_extsearch(file, file->fabn, 0, &n) <= 0) || v_putextrec(&file->ext, &n) == -1) goto fail; } else memcpy(extrec, &file->ext, sizeof(ExtDataRec)); } *pylen += blocks->xdrNumABlks * vol->mdb.drAlBlkSiz; file->flags |= HFS_FILE_UPDATE_CATREC; return 0; fail: return -1; }
/* * NAME: file->alloc() * DESCRIPTION: reserve disk blocks for a file */ int f_alloc(hfsfile *file) { hfsvol *vol = file->vol; ExtDescriptor blocks; ExtDataRec *extrec; unsigned long *pylen, clumpsz; unsigned int start, end; node n; int i; clumpsz = file->clump; if (clumpsz == 0) clumpsz = vol->mdb.drClpSiz; blocks.xdrNumABlks = clumpsz / vol->mdb.drAlBlkSiz; if (v_allocblocks(vol, &blocks) < 0) return -1; /* update the file's extents */ f_getptrs(file, 0, &pylen, &extrec); start = file->fabn; end = *pylen / vol->mdb.drAlBlkSiz; n.nnum = 0; i = -1; while (start < end) { for (i = 0; i < 3; ++i) { unsigned int num; num = file->ext[i].xdrNumABlks; start += num; if (start == end) break; else if (start > end) { v_freeblocks(vol, &blocks); ERROR(EIO, "file extents exceed file physical length"); return -1; } else if (num == 0) { v_freeblocks(vol, &blocks); ERROR(EIO, "empty file extent"); return -1; } } if (start == end) break; if (v_extsearch(file, start, &file->ext, &n) <= 0) { v_freeblocks(vol, &blocks); return -1; } file->fabn = start; } if (i >= 0 && file->ext[i].xdrStABN + file->ext[i].xdrNumABlks == blocks.xdrStABN) file->ext[i].xdrNumABlks += blocks.xdrNumABlks; else { /* create a new extent descriptor */ if (++i < 3) file->ext[i] = blocks; else { ExtKeyRec key; unsigned char record[HFS_EXTRECMAXLEN]; int reclen; /* record is full; create a new one */ file->ext[0] = blocks; for (i = 1; i < 3; ++i) { file->ext[i].xdrStABN = 0; file->ext[i].xdrNumABlks = 0; } file->fabn = start; r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, end); r_packextkey(&key, record, &reclen); r_packextdata(&file->ext, HFS_RECDATA(record), &reclen); if (bt_insert(&vol->ext, record, reclen) < 0) { v_freeblocks(vol, &blocks); return -1; } i = -1; } } if (i >= 0) { /* store the modified extent record */ if (file->fabn) { if ((n.nnum == 0 && v_extsearch(file, file->fabn, 0, &n) <= 0) || v_putextrec(&file->ext, &n) < 0) { v_freeblocks(vol, &blocks); return -1; } } else memcpy(extrec, file->ext, sizeof(ExtDataRec)); } *pylen += blocks.xdrNumABlks * vol->mdb.drAlBlkSiz; file->flags |= HFS_UPDATE_CATREC; return blocks.xdrNumABlks; }