/* * NAME: hfs->lseek() * DESCRIPTION: change file seek pointer */ long hfs_lseek(hfsfile *file, long offset, int from) { unsigned long *lglen; long newpos; f_getptrs(file, &lglen, 0, 0); switch (from) { case SEEK_SET: newpos = offset; break; case SEEK_CUR: newpos = file->pos + offset; break; case SEEK_END: newpos = *lglen + offset; break; default: ERROR(EINVAL, 0); return -1; } if (newpos < 0) newpos = 0; else if (newpos > *lglen) newpos = *lglen; file->pos = newpos; return newpos; }
/* * NAME: hfs->truncate() * DESCRIPTION: truncate an open file */ int hfs_truncate(hfsfile *file, unsigned long len) { unsigned long *lglen; f_getptrs(file, 0, &lglen, 0); if (*lglen > len) { if (file->vol->flags & HFS_VOL_READONLY) ERROR(EROFS, 0); *lglen = len; file->cat.u.fil.filMdDat = d_mtime(time(0)); file->flags |= HFS_FILE_UPDATE_CATREC; if (file->pos > len) file->pos = len; } return 0; fail: return -1; }
/* * NAME: hfs->truncate() * DESCRIPTION: truncate an open file */ int hfs_truncate(hfsfile *file, unsigned long len) { unsigned long *lglen; f_getptrs(file, &lglen, 0, 0); if (*lglen > len) { if (file->vol->flags & HFS_READONLY) { ERROR(EROFS, 0); return -1; } *lglen = len; file->cat.u.fil.filMdDat = d_tomtime(/*time*/(0)); file->flags |= HFS_UPDATE_CATREC; if (file->pos > len) file->pos = len; } return 0; }
/* * NAME: hfs->read() * DESCRIPTION: read from an open file */ long hfs_read(hfsfile *file, void *buf, unsigned long len) { unsigned long *lglen, count; unsigned char *ptr = buf; f_getptrs(file, &lglen, 0, 0); if (file->pos + len > *lglen) len = *lglen - file->pos; count = len; while (count) { block b; unsigned long bnum, offs, chunk; bnum = file->pos / HFS_BLOCKSZ; offs = file->pos % HFS_BLOCKSZ; chunk = HFS_BLOCKSZ - offs; if (chunk > count) chunk = count; if (f_getblock(file, bnum, &b) < 0) return -1; memcpy(ptr, b + offs, chunk); ptr += chunk; file->pos += chunk; count -= chunk; } return len; }
/* * 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: hfs->read() * DESCRIPTION: read from an open file */ unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len) { unsigned long *lglen, count; byte *ptr = buf; f_getptrs(file, NULL, &lglen, NULL); if (file->pos + len > *lglen) len = *lglen - file->pos; count = len; while (count) { unsigned long bnum, offs, chunk; bnum = file->pos >> HFS_BLOCKSZ_BITS; offs = file->pos & (HFS_BLOCKSZ - 1); chunk = HFS_BLOCKSZ - offs; if (chunk > count) chunk = count; if (offs == 0 && chunk == HFS_BLOCKSZ) { if (f_getblock(file, bnum, (block *) ptr) == -1) goto fail; } else { block b; if (f_getblock(file, bnum, &b) == -1) goto fail; memcpy(ptr, b + offs, chunk); } ptr += chunk; file->pos += chunk; count -= chunk; } return len; fail: return -1; }
/* * NAME: hfs->seek() * DESCRIPTION: change file seek pointer */ unsigned long hfs_seek(hfsfile *file, long offset, int from) { unsigned long *lglen, newpos; f_getptrs(file, NULL, &lglen, NULL); switch (from) { case HFS_SEEK_SET: newpos = (offset < 0) ? 0 : offset; break; case HFS_SEEK_CUR: if (offset < 0 && (unsigned long) -offset > file->pos) newpos = 0; else newpos = file->pos + offset; break; case HFS_SEEK_END: if (offset < 0 && (unsigned long) -offset > *lglen) newpos = 0; else newpos = *lglen + offset; break; default: ERROR(EINVAL, NULL); } if (newpos > *lglen) newpos = *lglen; file->pos = newpos; return newpos; 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: hfs->write() * DESCRIPTION: write to an open file */ unsigned long hfs_write(hfsfile *file, const void *buf, unsigned long len) { unsigned long *lglen, *pylen, count; const byte *ptr = buf; if (file->vol->flags & HFS_VOL_READONLY) ERROR(EROFS, 0); f_getptrs(file, 0, &lglen, &pylen); count = len; /* set flag to update (at least) the modification time */ if (count) { file->cat.u.fil.filMdDat = d_mtime(time(0)); file->flags |= HFS_FILE_UPDATE_CATREC; } while (count) { unsigned long bnum, offs, chunk; bnum = file->pos >> HFS_BLOCKSZ_BITS; offs = file->pos & (HFS_BLOCKSZ - 1); chunk = HFS_BLOCKSZ - offs; if (chunk > count) chunk = count; if (file->pos + chunk > *pylen) { if (bt_space(&file->vol->ext, 1) == -1 || f_alloc(file) == -1) goto fail; } if (offs == 0 && chunk == HFS_BLOCKSZ) { if (f_putblock(file, bnum, (block *) ptr) == -1) goto fail; } else { block b; if (f_getblock(file, bnum, &b) == -1) goto fail; memcpy(b + offs, ptr, chunk); if (f_putblock(file, bnum, &b) == -1) goto fail; } ptr += chunk; file->pos += chunk; count -= chunk; if (file->pos > *lglen) *lglen = file->pos; } return len; fail: return -1; }
int hfs_callback_format(oscallback func, void* cookie, int mode, const char* vname) #endif { hfsvol vol; btree *ext = &vol.ext; btree *cat = &vol.cat; unsigned int i, *badalloc = 0; v_init(&vol, mode); if (! validvname(vname)) goto fail; #ifdef CP_NOT_USED if (v_open(&vol, path, HFS_MODE_RDWR) == -1 || v_geometry(&vol, pnum) == -1) goto fail; #else if (v_callback_open(&vol, func, cookie) != 0 || v_geometry(&vol, 0) != 0) goto fail; #endif /* initialize volume geometry */ vol.lpa = 1 + ((vol.vlen - 6) >> 16); if (vol.flags & HFS_OPT_2048) vol.lpa = (vol.lpa + 3) & ~3; vol.vbmsz = (vol.vlen / vol.lpa + 0x0fff) >> 12; vol.mdb.drSigWord = HFS_SIGWORD; vol.mdb.drCrDate = d_mtime(time(0)); vol.mdb.drLsMod = vol.mdb.drCrDate; vol.mdb.drAtrb = 0; vol.mdb.drNmFls = 0; vol.mdb.drVBMSt = 3; vol.mdb.drAllocPtr = 0; vol.mdb.drAlBlkSiz = vol.lpa << HFS_BLOCKSZ_BITS; vol.mdb.drClpSiz = vol.mdb.drAlBlkSiz << 2; vol.mdb.drAlBlSt = vol.mdb.drVBMSt + vol.vbmsz; if (vol.flags & HFS_OPT_2048) vol.mdb.drAlBlSt = ((vol.vstart & 3) + vol.mdb.drAlBlSt + 3) & ~3; vol.mdb.drNmAlBlks = (vol.vlen - 2 - vol.mdb.drAlBlSt) / vol.lpa; vol.mdb.drNxtCNID = HFS_CNID_ROOTDIR; /* modified later */ vol.mdb.drFreeBks = vol.mdb.drNmAlBlks; strcpy(vol.mdb.drVN, vname); vol.mdb.drVolBkUp = 0; vol.mdb.drVSeqNum = 0; vol.mdb.drWrCnt = 0; vol.mdb.drXTClpSiz = vol.mdb.drNmAlBlks / 128 * vol.mdb.drAlBlkSiz; vol.mdb.drCTClpSiz = vol.mdb.drXTClpSiz; vol.mdb.drNmRtDirs = 0; vol.mdb.drFilCnt = 0; vol.mdb.drDirCnt = -1; /* incremented when root directory is created */ for (i = 0; i < 8; ++i) vol.mdb.drFndrInfo[i] = 0; vol.mdb.drEmbedSigWord = 0x0000; vol.mdb.drEmbedExtent.xdrStABN = 0; vol.mdb.drEmbedExtent.xdrNumABlks = 0; /* vol.mdb.drXTFlSize */ /* vol.mdb.drCTFlSize */ /* vol.mdb.drXTExtRec[0..2] */ /* vol.mdb.drCTExtRec[0..2] */ vol.flags |= HFS_VOL_UPDATE_MDB | HFS_VOL_UPDATE_ALTMDB; /* initialize volume bitmap */ vol.vbm = ALLOC(block, vol.vbmsz); if (vol.vbm == 0) ERROR(ENOMEM, 0); memset(vol.vbm, 0, vol.vbmsz << HFS_BLOCKSZ_BITS); vol.flags |= HFS_VOL_UPDATE_VBM; /* perform initial bad block sparing */ #ifdef CP_NOT_USED if (nbadblocks > 0) { if (nbadblocks * 4 > vol.vlen) ERROR(EINVAL, "volume contains too many bad blocks"); badalloc = ALLOC(unsigned int, nbadblocks); if (badalloc == 0) ERROR(ENOMEM, 0); if (vol.mdb.drNmAlBlks == 1594) vol.mdb.drFreeBks = --vol.mdb.drNmAlBlks; for (i = 0; i < nbadblocks; ++i) { unsigned long bnum; unsigned int anum; bnum = badblocks[i]; if (bnum < vol.mdb.drAlBlSt || bnum == vol.vlen - 2) ERROR(EINVAL, "can't spare critical bad block"); else if (bnum >= vol.vlen) ERROR(EINVAL, "bad block not in volume"); anum = (bnum - vol.mdb.drAlBlSt) / vol.lpa; if (anum < vol.mdb.drNmAlBlks) BMSET(vol.vbm, anum); badalloc[i] = anum; } vol.mdb.drAtrb |= HFS_ATRB_BBSPARED; } #endif /* create extents overflow file */ n_init(&ext->hdrnd, ext, ndHdrNode, 0); ext->hdrnd.nnum = 0; ext->hdrnd.nd.ndNRecs = 3; ext->hdrnd.roff[1] = 0x078; ext->hdrnd.roff[2] = 0x0f8; ext->hdrnd.roff[3] = 0x1f8; memset(HFS_NODEREC(ext->hdrnd, 1), 0, 128); ext->hdr.bthDepth = 0; ext->hdr.bthRoot = 0; ext->hdr.bthNRecs = 0; ext->hdr.bthFNode = 0; ext->hdr.bthLNode = 0; ext->hdr.bthNodeSize = HFS_BLOCKSZ; ext->hdr.bthKeyLen = 0x07; ext->hdr.bthNNodes = 0; ext->hdr.bthFree = 0; for (i = 0; i < 76; ++i) ext->hdr.bthResv[i] = 0; ext->map = ALLOC(byte, HFS_MAP1SZ); if (ext->map == 0) ERROR(ENOMEM, 0); memset(ext->map, 0, HFS_MAP1SZ); BMSET(ext->map, 0); ext->mapsz = HFS_MAP1SZ; ext->flags = HFS_BT_UPDATE_HDR; /* create catalog file */ n_init(&cat->hdrnd, cat, ndHdrNode, 0); cat->hdrnd.nnum = 0; cat->hdrnd.nd.ndNRecs = 3; cat->hdrnd.roff[1] = 0x078; cat->hdrnd.roff[2] = 0x0f8; cat->hdrnd.roff[3] = 0x1f8; memset(HFS_NODEREC(cat->hdrnd, 1), 0, 128); cat->hdr.bthDepth = 0; cat->hdr.bthRoot = 0; cat->hdr.bthNRecs = 0; cat->hdr.bthFNode = 0; cat->hdr.bthLNode = 0; cat->hdr.bthNodeSize = HFS_BLOCKSZ; cat->hdr.bthKeyLen = 0x25; cat->hdr.bthNNodes = 0; cat->hdr.bthFree = 0; for (i = 0; i < 76; ++i) cat->hdr.bthResv[i] = 0; cat->map = ALLOC(byte, HFS_MAP1SZ); if (cat->map == 0) ERROR(ENOMEM, 0); memset(cat->map, 0, HFS_MAP1SZ); BMSET(cat->map, 0); cat->mapsz = HFS_MAP1SZ; cat->flags = HFS_BT_UPDATE_HDR; /* allocate space for header nodes (and initial extents) */ if (bt_space(ext, 1) == -1 || bt_space(cat, 1) == -1) goto fail; --ext->hdr.bthFree; --cat->hdr.bthFree; /* create extent records for bad blocks */ #ifdef CP_NOT_USED if (nbadblocks > 0) { hfsfile bbfile; ExtDescriptor extent; ExtDataRec *extrec; ExtKeyRec key; byte record[HFS_MAX_EXTRECLEN]; unsigned int reclen; f_init(&bbfile, &vol, HFS_CNID_BADALLOC, "bad blocks"); qsort(badalloc, nbadblocks, sizeof(*badalloc), (int (*)(const void *, const void *)) compare); for (i = 0; i < nbadblocks; ++i) { if (i == 0 || badalloc[i] != extent.xdrStABN) { extent.xdrStABN = badalloc[i]; extent.xdrNumABlks = 1; if (extent.xdrStABN < vol.mdb.drNmAlBlks && f_addextent(&bbfile, &extent) == -1) goto fail; } } /* flush local extents into extents overflow file */ f_getptrs(&bbfile, &extrec, 0, 0); r_makeextkey(&key, bbfile.fork, bbfile.cat.u.fil.filFlNum, 0); r_packextrec(&key, extrec, record, &reclen); if (bt_insert(&vol.ext, record, reclen) == -1) goto fail; } #endif vol.flags |= HFS_VOL_MOUNTED; /* create root directory */ if (v_mkdir(&vol, HFS_CNID_ROOTPAR, vname) == -1) goto fail; vol.mdb.drNxtCNID = 16; /* first CNID not reserved by Apple */ /* write boot blocks */ if (m_zerobb(&vol) == -1) goto fail; /* zero other unused space, if requested */ if (vol.flags & HFS_OPT_ZERO) { block b; unsigned long bnum; memset(&b, 0, sizeof(b)); /* between MDB and VBM (never) */ for (bnum = 3; bnum < vol.mdb.drVBMSt; ++bnum) b_writelb(&vol, bnum, &b); /* between VBM and first allocation block (sometimes if HFS_OPT_2048) */ for (bnum = vol.mdb.drVBMSt + vol.vbmsz; bnum < vol.mdb.drAlBlSt; ++bnum) b_writelb(&vol, bnum, &b); /* between last allocation block and alternate MDB (sometimes) */ for (bnum = vol.mdb.drAlBlSt + vol.mdb.drNmAlBlks * vol.lpa; bnum < vol.vlen - 2; ++bnum) b_writelb(&vol, bnum, &b); /* final block (always) */ b_writelb(&vol, vol.vlen - 1, &b); } /* flush remaining state and close volume */ if (v_close(&vol) == -1) goto fail; FREE(badalloc); return 0; fail: v_close(&vol); FREE(badalloc); 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; }
/* * NAME: hfs->write() * DESCRIPTION: write to an open file */ long hfs_write(hfsfile *file, void *buf, unsigned long len) { unsigned long *lglen, *pylen, count; unsigned char *ptr = buf; if (file->vol->flags & HFS_READONLY) { ERROR(EROFS, 0); return -1; } f_getptrs(file, &lglen, &pylen, 0); count = len; /* set flag to update (at least) the modification time */ if (count) { file->cat.u.fil.filMdDat = d_tomtime(/*time*/(0)); file->flags |= HFS_UPDATE_CATREC; } while (count) { block b; unsigned long bnum, offs, chunk; bnum = file->pos / HFS_BLOCKSZ; offs = file->pos % HFS_BLOCKSZ; chunk = HFS_BLOCKSZ - offs; if (chunk > count) chunk = count; if (file->pos + chunk > *pylen) { if (bt_space(&file->vol->ext, 1) < 0 || f_alloc(file) < 0) return -1; } if (offs > 0 || chunk < HFS_BLOCKSZ) { if (f_getblock(file, bnum, &b) < 0) return -1; } memcpy(b + offs, ptr, chunk); ptr += chunk; if (f_putblock(file, bnum, &b) < 0) return -1; file->pos += chunk; count -= chunk; if (file->pos > *lglen) *lglen = file->pos; } return len; }