/* * NAME: node->new() * DESCRIPTION: allocate a new b*-tree node */ int n_new(node *np) { btree *bt = np->bt; unsigned long num; if (bt->hdr.bthFree == 0) ERROR(EIO, "b*-tree full"); num = 0; while (num < bt->hdr.bthNNodes && BMTST(bt->map, num)) ++num; if (num == bt->hdr.bthNNodes) ERROR(EIO, "free b*-tree node not found"); np->nnum = num; BMSET(bt->map, num); --bt->hdr.bthFree; bt->flags |= HFS_BT_UPDATE_HDR; return 0; fail: return -1; }
/* * NAME: vol->allocblocks() * DESCRIPTION: allocate a contiguous range of blocks */ int v_allocblocks(hfsvol *vol, ExtDescriptor *blocks) { unsigned int request, found, foundat, start, end; register unsigned int pt; const block *vbm; int wrap = 0; if (vol->mdb.drFreeBks == 0) ERROR(ENOSPC, "volume full"); request = blocks->xdrNumABlks; found = 0; foundat = 0; start = vol->mdb.drAllocPtr; end = vol->mdb.drNmAlBlks; vbm = vol->vbm; # ifdef DEBUG if (request == 0) abort(); # endif /* backtrack the start pointer to recover unused space */ if (! BMTST(vbm, start)) { while (start > 0 && ! BMTST(vbm, start - 1)) --start; } /* find largest unused block which satisfies request */ pt = start; while (1) { unsigned int mark; /* skip blocks in use */ while (pt < end && BMTST(vbm, pt)) ++pt; if (wrap && pt >= start) break; /* count blocks not in use */ mark = pt; while (pt < end && pt - mark < request && ! BMTST(vbm, pt)) ++pt; if (pt - mark > found) { found = pt - mark; foundat = mark; } if (wrap && pt >= start) break; if (pt == end) pt = 0, wrap = 1; if (found == request) break; } if (found == 0 || found > vol->mdb.drFreeBks) ERROR(EIO, "bad volume bitmap or free block count"); blocks->xdrStABN = foundat; blocks->xdrNumABlks = found; vol->mdb.drAllocPtr = pt; vol->mdb.drFreeBks -= found; for (pt = foundat; pt < foundat + found; ++pt) BMSET(vbm, pt); vol->flags |= HFS_VOL_UPDATE_MDB | HFS_VOL_UPDATE_VBM; return 0; fail: return -1; }
/* * NAME: vol->scavenge() * DESCRIPTION: safeguard blocks in the volume bitmap */ int v_scavenge(hfsvol *vol) { const block *vbm = vol->vbm; node n; unsigned int pt, blks; if (vbm == 0) goto done; markexts(vbm, &vol->mdb.drXTExtRec); markexts(vbm, &vol->mdb.drCTExtRec); vol->flags |= HFS_VOL_UPDATE_VBM; /* scavenge the extents overflow file */ n.bt = &vol->ext; n.nnum = vol->ext.hdr.bthFNode; if (n.nnum > 0) { if (bt_getnode(&n) == -1) goto fail; n.rnum = 0; while (1) { ExtDataRec data; const byte *ptr; while (n.rnum >= n.nd.ndNRecs) { n.nnum = n.nd.ndFLink; if (n.nnum == 0) break; if (bt_getnode(&n) == -1) goto fail; n.rnum = 0; } if (n.nnum == 0) break; ptr = HFS_NODEREC(n, n.rnum); r_unpackextdata(HFS_RECDATA(ptr), &data); markexts(vbm, &data); ++n.rnum; } } /* scavenge the catalog file */ n.bt = &vol->cat; n.nnum = vol->cat.hdr.bthFNode; if (n.nnum > 0) { if (bt_getnode(&n) == -1) goto fail; n.rnum = 0; while (1) { CatDataRec data; const byte *ptr; while (n.rnum >= n.nd.ndNRecs) { n.nnum = n.nd.ndFLink; if (n.nnum == 0) break; if (bt_getnode(&n) == -1) goto fail; n.rnum = 0; } if (n.nnum == 0) break; ptr = HFS_NODEREC(n, n.rnum); r_unpackcatdata(HFS_RECDATA(ptr), &data); if (data.cdrType == cdrFilRec) { markexts(vbm, &data.u.fil.filExtRec); markexts(vbm, &data.u.fil.filRExtRec); } ++n.rnum; } } for (blks = 0, pt = vol->mdb.drNmAlBlks; pt--; ) { if (! BMTST(vbm, pt)) ++blks; } if (vol->mdb.drFreeBks != blks) { vol->mdb.drFreeBks = blks; vol->flags |= HFS_VOL_UPDATE_MDB; } done: return 0; fail: return -1; }
/* * NAME: vol->allocblocks() * DESCRIPTION: allocate a contiguous range of blocks */ int v_allocblocks(hfsvol *vol, ExtDescriptor *blocks) { unsigned int request, found, foundat, start, end, pt; block *vbm; int wrap = 0; if (vol->mdb.drFreeBks == 0) { ERROR(ENOSPC, "volume full"); return -1; } request = blocks->xdrNumABlks; found = 0; foundat = 0; start = vol->mdb.drAllocPtr; end = vol->mdb.drNmAlBlks; pt = start; vbm = vol->vbm; if (request == 0) abort(); while (1) { unsigned int mark; /* skip blocks in use */ while (pt < end && BMTST(vbm, pt)) ++pt; if (wrap && pt >= start) break; /* count blocks not in use */ mark = pt; while (pt < end && pt - mark < request && ! BMTST(vbm, pt)) ++pt; if (pt - mark > found) { found = pt - mark; foundat = mark; } if (pt == end) pt = 0, wrap = 1; if (found == request) break; } if (found == 0 || found > vol->mdb.drFreeBks) { ERROR(EIO, "bad volume bitmap or free block count"); return -1; } blocks->xdrStABN = foundat; blocks->xdrNumABlks = found; vol->mdb.drAllocPtr = pt; vol->mdb.drFreeBks -= found; for (pt = foundat; pt < foundat + found; ++pt) BMSET(vbm, pt); vol->flags |= HFS_UPDATE_MDB | HFS_UPDATE_VBM; return 0; }