📄 volume.c
字号:
/* * libhfs - library for reading and writing Macintosh HFS volumes * Copyright (C) 1996-1998 Robert Leslie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: volume.c,v 1.12 1998/11/02 22:09:10 rob Exp $ */#include "openbios/config.h"#include "libhfs.h"#include "volume.h"#include "data.h"#include "block.h"#include "low.h"#include "medium.h"#include "file.h"#include "btree.h"#include "record.h"#include "os.h"/* * NAME: vol->init() * DESCRIPTION: initialize volume structure */void v_init(hfsvol *vol, int flags){ btree *ext = &vol->ext; btree *cat = &vol->cat; vol->os_fd = 0; vol->flags = flags & HFS_VOL_OPT_MASK; vol->pnum = -1; vol->vstart = 0; vol->vlen = 0; vol->lpa = 0; vol->cache = 0; vol->vbm = 0; vol->vbmsz = 0; f_init(&ext->f, vol, HFS_CNID_EXT, "extents overflow"); ext->map = 0; ext->mapsz = 0; ext->flags = 0; ext->keyunpack = (keyunpackfunc) r_unpackextkey; ext->keycompare = (keycomparefunc) r_compareextkeys; f_init(&cat->f, vol, HFS_CNID_CAT, "catalog"); cat->map = 0; cat->mapsz = 0; cat->flags = 0; cat->keyunpack = (keyunpackfunc) r_unpackcatkey; cat->keycompare = (keycomparefunc) r_comparecatkeys; vol->cwd = HFS_CNID_ROOTDIR; vol->refs = 0; vol->files = 0; vol->dirs = 0; vol->prev = 0; vol->next = 0;}/* * NAME: vol->open() * DESCRIPTION: open volume source and lock against concurrent updates */int v_open(hfsvol *vol, int os_fd ){ if (vol->flags & HFS_VOL_OPEN) ERROR(EINVAL, "volume already open"); vol->flags |= HFS_VOL_OPEN; vol->os_fd = os_fd; /* initialize volume block cache (OK to fail) */ if (! (vol->flags & HFS_OPT_NOCACHE) && b_init(vol) != -1) vol->flags |= HFS_VOL_USINGCACHE; return 0;fail: return -1;}/* * NAME: vol->close() * DESCRIPTION: close access path to volume source */int v_close(hfsvol *vol){ int result = 0; if (! (vol->flags & HFS_VOL_OPEN)) goto done; if ((vol->flags & HFS_VOL_USINGCACHE) && b_finish(vol) == -1) result = -1; vol->flags &= ~(HFS_VOL_OPEN | HFS_VOL_MOUNTED | HFS_VOL_USINGCACHE); /* free dynamically allocated structures */ FREE(vol->vbm); vol->vbm = 0; vol->vbmsz = 0; FREE(vol->ext.map); FREE(vol->cat.map); vol->ext.map = 0; vol->cat.map = 0;done: return result;}/* * NAME: vol->same() * DESCRIPTION: return 1 iff path is same as open volume */int v_same(hfsvol *vol, int os_fd ){ return vol->os_fd == os_fd;}/* * NAME: vol->geometry() * DESCRIPTION: determine volume location and size (possibly in a partition) */int v_geometry(hfsvol *vol, int pnum){ Partition map; unsigned long bnum = 0; int found; vol->pnum = pnum; if (pnum == 0) { vol->vstart = 0; vol->vlen = b_size(vol); if (vol->vlen == 0) goto fail; } else { while (pnum--) { found = m_findpmentry(vol, "Apple_HFS", &map, &bnum); if (found == -1 || ! found) goto fail; } vol->vstart = map.pmPyPartStart; vol->vlen = map.pmPartBlkCnt; if (map.pmDataCnt) { if ((unsigned long) map.pmLgDataStart + (unsigned long) map.pmDataCnt > vol->vlen) ERROR(EINVAL, "partition data overflows partition"); vol->vstart += (unsigned long) map.pmLgDataStart; vol->vlen = map.pmDataCnt; } if (vol->vlen == 0) ERROR(EINVAL, "volume partition is empty"); } if (vol->vlen < 800 * (1024 >> HFS_BLOCKSZ_BITS)) ERROR(EINVAL, "volume is smaller than 800K"); return 0;fail: return -1;}/* * NAME: vol->readmdb() * DESCRIPTION: load Master Directory Block into memory */int v_readmdb(hfsvol *vol){ if (l_getmdb(vol, &vol->mdb, 0) == -1) goto fail; if (vol->mdb.drSigWord != HFS_SIGWORD) { if (vol->mdb.drSigWord == HFS_SIGWORD_MFS) ERROR(EINVAL, "MFS volume format not supported"); else ERROR(EINVAL, "not a Macintosh HFS volume"); } if (vol->mdb.drAlBlkSiz % HFS_BLOCKSZ != 0) ERROR(EINVAL, "bad volume allocation block size"); vol->lpa = vol->mdb.drAlBlkSiz >> HFS_BLOCKSZ_BITS; /* extents pseudo-file structs */ vol->ext.f.cat.u.fil.filStBlk = vol->mdb.drXTExtRec[0].xdrStABN; vol->ext.f.cat.u.fil.filLgLen = vol->mdb.drXTFlSize; vol->ext.f.cat.u.fil.filPyLen = vol->mdb.drXTFlSize; vol->ext.f.cat.u.fil.filCrDat = vol->mdb.drCrDate; vol->ext.f.cat.u.fil.filMdDat = vol->mdb.drLsMod; memcpy(&vol->ext.f.cat.u.fil.filExtRec, &vol->mdb.drXTExtRec, sizeof(ExtDataRec)); f_selectfork(&vol->ext.f, fkData); /* catalog pseudo-file structs */ vol->cat.f.cat.u.fil.filStBlk = vol->mdb.drCTExtRec[0].xdrStABN; vol->cat.f.cat.u.fil.filLgLen = vol->mdb.drCTFlSize; vol->cat.f.cat.u.fil.filPyLen = vol->mdb.drCTFlSize; vol->cat.f.cat.u.fil.filCrDat = vol->mdb.drCrDate; vol->cat.f.cat.u.fil.filMdDat = vol->mdb.drLsMod; memcpy(&vol->cat.f.cat.u.fil.filExtRec, &vol->mdb.drCTExtRec, sizeof(ExtDataRec)); f_selectfork(&vol->cat.f, fkData); return 0;fail: return -1;}/* * NAME: vol->readvbm() * DESCRIPTION: read volume bitmap into memory */int v_readvbm(hfsvol *vol){ unsigned int vbmst = vol->mdb.drVBMSt; unsigned int vbmsz = (vol->mdb.drNmAlBlks + 0x0fff) >> 12; block *bp; ASSERT(vol->vbm == 0); if (vol->mdb.drAlBlSt - vbmst < vbmsz) ERROR(EIO, "volume bitmap collides with volume data"); vol->vbm = ALLOC(block, vbmsz); if (vol->vbm == 0) ERROR(ENOMEM, 0); vol->vbmsz = vbmsz; for (bp = vol->vbm; vbmsz--; ++bp) { if (b_readlb(vol, vbmst++, bp) == -1) goto fail; } return 0;fail: FREE(vol->vbm); vol->vbm = 0; vol->vbmsz = 0; return -1;}/* * NAME: vol->mount() * DESCRIPTION: load volume information into memory */int v_mount(hfsvol *vol){ /* read the MDB, volume bitmap, and extents/catalog B*-tree headers */ if (v_readmdb(vol) == -1 || v_readvbm(vol) == -1 || bt_readhdr(&vol->ext) == -1 || bt_readhdr(&vol->cat) == -1) goto fail; if (vol->mdb.drAtrb & HFS_ATRB_SLOCKED) vol->flags |= HFS_VOL_READONLY; else if (vol->flags & HFS_VOL_READONLY) vol->mdb.drAtrb |= HFS_ATRB_HLOCKED; else vol->mdb.drAtrb &= ~HFS_ATRB_HLOCKED; vol->flags |= HFS_VOL_MOUNTED; return 0;fail: return -1;}/* * NAME: vol->catsearch() * DESCRIPTION: search catalog tree */int v_catsearch(hfsvol *vol, unsigned long parid, const char *name, CatDataRec *data, char *cname, node *np){ CatKeyRec key; byte pkey[HFS_CATKEYLEN]; const byte *ptr; node n; int found; if (np == 0) np = &n; r_makecatkey(&key, parid, name); r_packcatkey(&key, pkey, 0); found = bt_search(&vol->cat, pkey, np); if (found <= 0) return found; ptr = HFS_NODEREC(*np, np->rnum); if (cname) { r_unpackcatkey(ptr, &key); strcpy(cname, key.ckrCName); } if (data) r_unpackcatdata(HFS_RECDATA(ptr), data); return 1;}/* * NAME: vol->extsearch() * DESCRIPTION: search extents tree */int v_extsearch(hfsfile *file, unsigned int fabn, ExtDataRec *data, node *np){ ExtKeyRec key; ExtDataRec extsave; unsigned int fabnsave; byte pkey[HFS_EXTKEYLEN]; const byte *ptr; node n; int found; if (np == 0) np = &n; r_makeextkey(&key, file->fork, file->cat.u.fil.filFlNum, fabn); r_packextkey(&key, pkey, 0); /* in case bt_search() clobbers these */ memcpy(&extsave, &file->ext, sizeof(ExtDataRec)); fabnsave = file->fabn; found = bt_search(&file->vol->ext, pkey, np); memcpy(&file->ext, &extsave, sizeof(ExtDataRec)); file->fabn = fabnsave; if (found <= 0) return found; if (data) { ptr = HFS_NODEREC(*np, np->rnum); r_unpackextdata(HFS_RECDATA(ptr), data); } return 1;}/* * NAME: vol->getthread() * DESCRIPTION: retrieve catalog thread information for a file or directory */int v_getthread(hfsvol *vol, unsigned long id, CatDataRec *thread, node *np, int type){ CatDataRec rec; int found; if (thread == 0) thread = &rec; found = v_catsearch(vol, id, "", thread, 0, np); if (found == 1 && thread->cdrType != type) ERROR(EIO, "bad thread record"); return found;fail: return -1;}/* * NAME: vol->resolve() * DESCRIPTION: translate a pathname; return catalog information */int v_resolve(hfsvol **vol, const char *path, CatDataRec *data, long *parid, char *fname, node *np){ unsigned long dirid; char name[HFS_MAX_FLEN + 1], *nptr; int found = 0; if (*path == 0) ERROR(ENOENT, "empty path"); if (parid) *parid = 0; nptr = strchr(path, ':'); if (*path == ':' || nptr == 0) { dirid = (*vol)->cwd; /* relative path */ if (*path == ':') ++path; if (*path == 0) { found = v_getdthread(*vol, dirid, data, 0); if (found == -1) goto fail; if (found) { if (parid) *parid = data->u.dthd.thdParID; found = v_catsearch(*vol, data->u.dthd.thdParID, data->u.dthd.thdCName, data, fname, np); if (found == -1) goto fail; } goto done; } } else { hfsvol *check; dirid = HFS_CNID_ROOTPAR; /* absolute path */ if (nptr - path > HFS_MAX_VLEN) ERROR(ENAMETOOLONG, 0); strncpy(name, path, nptr - path); name[nptr - path] = 0; for (check = hfs_mounts; check; check = check->next) { if (d_relstring(check->mdb.drVN, name) == 0) { *vol = check; break; } } } while (1) { while (*path == ':') { ++path; found = v_getdthread(*vol, dirid, data, 0); if (found == -1) goto fail; else if (! found) goto done; dirid = data->u.dthd.thdParID; } if (*path == 0) { found = v_getdthread(*vol, dirid, data, 0); if (found == -1) goto fail; if (found) { if (parid) *parid = data->u.dthd.thdParID; found = v_catsearch(*vol, data->u.dthd.thdParID, data->u.dthd.thdCName, data, fname, np); if (found == -1) goto fail; } goto done; } nptr = name; while (nptr < name + sizeof(name) - 1 && *path && *path != ':') *nptr++ = *path++; if (*path && *path != ':') ERROR(ENAMETOOLONG, 0); *nptr = 0; if (*path == ':') ++path; if (parid) *parid = dirid; found = v_catsearch(*vol, dirid, name, data, fname, np); if (found == -1) goto fail; if (! found) { if (*path && parid) *parid = 0; if (*path == 0 && fname) strcpy(fname, name); goto done; } switch (data->cdrType) { case cdrDirRec: if (*path == 0) goto done; dirid = data->u.dir.dirDirID; break; case cdrFilRec: if (*path == 0) goto done; ERROR(ENOTDIR, "invalid pathname"); default: ERROR(EIO, "unexpected catalog record"); } }done: return found;fail: return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -