2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)file.c 1.3 04/06/17 joerg */
15 * hfsutils - tools for reading and writing Macintosh HFS volumes
16 * Copyright (C) 1996, 1997 Robert Leslie
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
45 /* #include <stdio.h> */
49 * NAME: file->selectfork()
50 * DESCRIPTION: choose a fork for file operations
52 void f_selectfork(hfsfile *file, int ffork)
57 memcpy(file->ext, file->cat.u.fil.filExtRec, sizeof(ExtDataRec));
62 memcpy(file->ext, file->cat.u.fil.filRExtRec, sizeof(ExtDataRec));
70 * NAME: file->getptrs()
71 * DESCRIPTION: make pointers to the current fork's lengths and extents
73 void f_getptrs(hfsfile *file, unsigned long **lglen, unsigned long **pylen,
76 if (file->fork == fkData)
79 *lglen = &file->cat.u.fil.filLgLen;
81 *pylen = &file->cat.u.fil.filPyLen;
83 *extrec = &file->cat.u.fil.filExtRec;
88 *lglen = &file->cat.u.fil.filRLgLen;
90 *pylen = &file->cat.u.fil.filRPyLen;
92 *extrec = &file->cat.u.fil.filRExtRec;
97 * NAME: file->doblock()
98 * DESCRIPTION: read or write a numbered block from a file
100 int f_doblock(hfsfile *file, unsigned long number, block *bp,
101 int (*func)(hfsvol *, unsigned int, unsigned int, block *))
108 abnum = number / file->vol->lpa;
109 blnum = number % file->vol->lpa;
111 /* locate the appropriate extent record */
119 f_getptrs(file, 0, 0, &extrec);
121 fabn = file->fabn = 0;
122 memcpy(file->ext, extrec, sizeof(ExtDataRec));
131 for (i = 0; i < 3; ++i)
133 num = file->ext[i].xdrNumABlks;
137 /* SHOULD NOT HAPPEN! - all the files should not be fragmented
138 if this happens, then a serious problem has occured, may be
139 a hard linked file? */
141 fprintf(stderr,"fragmented file: %s %d\n",file->name, i); */
143 ERROR(HCE_ERROR, "Possible Catalog file overflow - please report error");
146 #endif /* APPLE_HYB */
148 return func(file->vol, file->ext[i].xdrStABN + abnum, blnum, bp);
154 if (v_extsearch(file, fabn, &file->ext, 0) <= 0)
162 * NAME: file->alloc()
163 * DESCRIPTION: reserve disk blocks for a file
165 int f_alloc(hfsfile *file)
167 hfsvol *vol = file->vol;
168 ExtDescriptor blocks;
170 unsigned long *pylen, clumpsz;
171 unsigned int start, end;
175 clumpsz = file->clump;
177 clumpsz = vol->mdb.drClpSiz;
179 blocks.xdrNumABlks = clumpsz / vol->mdb.drAlBlkSiz;
181 if (v_allocblocks(vol, &blocks) < 0)
184 /* update the file's extents */
186 f_getptrs(file, 0, &pylen, &extrec);
189 end = *pylen / vol->mdb.drAlBlkSiz;
196 for (i = 0; i < 3; ++i)
200 num = file->ext[i].xdrNumABlks;
205 else if (start > end)
207 v_freeblocks(vol, &blocks);
208 ERROR(EIO, "file extents exceed file physical length");
213 v_freeblocks(vol, &blocks);
214 ERROR(EIO, "empty file extent");
222 if (v_extsearch(file, start, &file->ext, &n) <= 0)
224 v_freeblocks(vol, &blocks);
232 file->ext[i].xdrStABN + file->ext[i].xdrNumABlks == blocks.xdrStABN)
233 file->ext[i].xdrNumABlks += blocks.xdrNumABlks;
236 /* create a new extent descriptor */
239 file->ext[i] = blocks;
243 unsigned char record[HFS_EXTRECMAXLEN];
246 /* record is full; create a new one */
248 file->ext[0] = blocks;
250 for (i = 1; i < 3; ++i)
252 file->ext[i].xdrStABN = 0;
253 file->ext[i].xdrNumABlks = 0;
258 r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, end);
259 r_packextkey(&key, record, &reclen);
260 r_packextdata(&file->ext, HFS_RECDATA(record), &reclen);
262 if (bt_insert(&vol->ext, record, reclen) < 0)
264 v_freeblocks(vol, &blocks);
274 /* store the modified extent record */
279 v_extsearch(file, file->fabn, 0, &n) <= 0) ||
280 v_putextrec(&file->ext, &n) < 0)
282 v_freeblocks(vol, &blocks);
287 memcpy(extrec, file->ext, sizeof(ExtDataRec));
290 *pylen += blocks.xdrNumABlks * vol->mdb.drAlBlkSiz;
292 file->flags |= HFS_UPDATE_CATREC;
294 return blocks.xdrNumABlks;
298 * NAME: file->trunc()
299 * DESCRIPTION: release disk blocks unneeded by a file
301 int f_trunc(hfsfile *file)
304 unsigned long *lglen, *pylen, alblksz, newpylen;
305 unsigned int dlen, start, end;
309 f_getptrs(file, &lglen, &pylen, &extrec);
311 alblksz = file->vol->mdb.drAlBlkSiz;
312 newpylen = (*lglen / alblksz + (*lglen % alblksz != 0)) * alblksz;
314 if (newpylen > *pylen)
316 ERROR(EIO, "file size exceeds physical length");
319 else if (newpylen == *pylen)
322 dlen = (*pylen - newpylen) / alblksz;
325 end = newpylen / alblksz;
329 start = file->fabn = 0;
330 memcpy(file->ext, extrec, sizeof(ExtDataRec));
338 for (i = 0; i < 3; ++i)
342 num = file->ext[i].xdrNumABlks;
349 ERROR(EIO, "empty file extent");
357 if (v_extsearch(file, start, &file->ext, &n) <= 0)
365 ExtDescriptor blocks;
367 file->ext[i].xdrNumABlks -= start - end;
370 blocks.xdrStABN = file->ext[i].xdrStABN + file->ext[i].xdrNumABlks;
371 blocks.xdrNumABlks = start - end;
373 v_freeblocks(file->vol, &blocks);
378 file->flags |= HFS_UPDATE_CATREC;
382 while (dlen && ++i < 3)
386 num = file->ext[i].xdrNumABlks;
391 ERROR(EIO, "empty file extent");
396 ERROR(EIO, "file extents exceed physical size");
401 v_freeblocks(file->vol, &file->ext[i]);
403 file->ext[i].xdrStABN = 0;
404 file->ext[i].xdrNumABlks = 0;
410 v_extsearch(file, file->fabn, 0, &n) <= 0)
413 if (file->ext[0].xdrNumABlks)
415 if (v_putextrec(&file->ext, &n) < 0)
420 if (bt_delete(&file->vol->ext, HFS_NODEREC(n, n.rnum)) < 0)
427 memcpy(extrec, file->ext, sizeof(ExtDataRec));
431 if (v_extsearch(file, start, &file->ext, &n) <= 0)
444 * NAME: file->flush()
445 * DESCRIPTION: flush all pending changes to an open file
447 int f_flush(hfsfile *file)
449 hfsvol *vol = file->vol;
451 if (! (vol->flags & HFS_READONLY))
453 if (file->flags & HFS_UPDATE_CATREC)
457 file->cat.u.fil.filStBlk = file->cat.u.fil.filExtRec[0].xdrStABN;
458 file->cat.u.fil.filRStBlk = file->cat.u.fil.filRExtRec[0].xdrStABN;
459 file->cat.u.fil.filClpSize = file->clump;
461 if (v_catsearch(file->vol, file->parid, file->name, 0, 0, &n) <= 0 ||
462 v_putcatrec(&file->cat, &n) < 0)
465 file->flags &= ~HFS_UPDATE_CATREC;