/* * NAME: vol->putcatrec() * DESCRIPTION: store catalog information */ int v_putcatrec(const CatDataRec *data, node *np) { byte pdata[HFS_CATDATALEN], *ptr; int len = 0; r_packcatdata(data, pdata, &len); ptr = HFS_NODEREC(*np, np->rnum); memcpy(HFS_RECDATA(ptr), pdata, len); return bt_putnode(np); }
/* * NAME: vol->newfolder() * DESCRIPTION: create a new HFS folder */ int v_newfolder(hfsvol *vol, long parid, char *name) { CatKeyRec key; CatDataRec data; long id; unsigned char record[HFS_CATRECMAXLEN]; int i, reclen; if (bt_space(&vol->cat, 2) < 0) return -1; id = vol->mdb.drNxtCNID++; vol->flags |= HFS_UPDATE_MDB; /* create directory record */ data.cdrType = cdrDirRec; data.cdrResrv2 = 0; data.u.dir.dirFlags = 0; data.u.dir.dirVal = 0; data.u.dir.dirDirID = id; #ifdef UHFS data.u.dir.dirCrDat = 0; #else data.u.dir.dirCrDat = d_tomtime(time(0)); #endif data.u.dir.dirMdDat = data.u.dir.dirCrDat; data.u.dir.dirBkDat = 0; memset(&data.u.dir.dirUsrInfo, 0, sizeof(data.u.dir.dirUsrInfo)); memset(&data.u.dir.dirFndrInfo, 0, sizeof(data.u.dir.dirFndrInfo)); for (i = 0; i < 4; ++i) data.u.dir.dirResrv[i] = 0; r_makecatkey(&key, parid, name); r_packcatkey(&key, record, &reclen); r_packcatdata(&data, HFS_RECDATA(record), &reclen); if (bt_insert(&vol->cat, record, reclen) < 0) return -1; /* create thread record */ data.cdrType = cdrThdRec; data.cdrResrv2 = 0; data.u.dthd.thdResrv[0] = 0; data.u.dthd.thdResrv[1] = 0; data.u.dthd.thdParID = parid; strcpy(data.u.dthd.thdCName, name); r_makecatkey(&key, id, ""); r_packcatkey(&key, record, &reclen); r_packcatdata(&data, HFS_RECDATA(record), &reclen); if (bt_insert(&vol->cat, record, reclen) < 0 || v_adjvalence(vol, parid, 1, 1) < 0) return -1; return 0; }
/* * NAME: hfs->rename() * DESCRIPTION: change the name of and/or move a file or directory */ int hfs_rename(hfsvol *vol, char *srcpath, char *dstpath) { hfsvol *srcvol; CatDataRec src, dst; long srcid, dstid; CatKeyRec key; char srcname[HFS_MAX_FLEN + 1], dstname[HFS_MAX_FLEN + 1]; unsigned char record[HFS_CATRECMAXLEN]; int found, isdir, moving, reclen; node n; if (v_getvol(&vol) < 0 || v_resolve(&vol, srcpath, &src, &srcid, srcname, 0) <= 0) return -1; isdir = (src.cdrType == cdrDirRec); srcvol = vol; found = v_resolve(&vol, dstpath, &dst, &dstid, dstname, 0); if (found < 0) return -1; if (vol != srcvol) { ERROR(EINVAL, "can't move across volumes"); return -1; } if (dstid == 0) { ERROR(ENOENT, "bad destination path"); return -1; } if (found && dst.cdrType == cdrDirRec && dst.u.dir.dirDirID != src.u.dir.dirDirID) { dstid = dst.u.dir.dirDirID; strcpy(dstname, srcname); found = v_catsearch(vol, dstid, dstname, 0, 0, 0); if (found < 0) return -1; } moving = (srcid != dstid); if (found) { char *ptr; ptr = strrchr(dstpath, ':'); if (ptr == 0) ptr = dstpath; else ++ptr; if (*ptr) strcpy(dstname, ptr); if (! moving && strcmp(srcname, dstname) == 0) return 0; /* source and destination are the same */ if (moving || d_relstring(srcname, dstname)) { ERROR(EEXIST, "can't use destination name"); return -1; } } /* can't move anything into the root directory's parent */ if (moving && dstid == HFS_CNID_ROOTPAR) { ERROR(EINVAL, "can't move above root directory"); return -1; } if (moving && isdir) { long id; /* can't move root directory anywhere */ if (src.u.dir.dirDirID == HFS_CNID_ROOTDIR) { ERROR(EINVAL, "can't move root directory"); return -1; } /* make sure we aren't trying to move a directory inside itself */ for (id = dstid; id != HFS_CNID_ROOTDIR; id = dst.u.dthd.thdParID) { if (id == src.u.dir.dirDirID) { ERROR(EINVAL, "can't move directory inside itself"); return -1; } if (v_getdthread(vol, id, &dst, 0) <= 0) return -1; } } if (vol->flags & HFS_READONLY) { ERROR(EROFS, 0); return -1; } /* change volume name */ if (dstid == HFS_CNID_ROOTPAR) { if (strlen(dstname) > HFS_MAX_VLEN) { ERROR(ENAMETOOLONG, 0); return -1; } strcpy(vol->mdb.drVN, dstname); vol->flags |= HFS_UPDATE_MDB; } /* remove source record */ r_makecatkey(&key, srcid, srcname); r_packcatkey(&key, record, 0); if (bt_delete(&vol->cat, record) < 0) return -1; /* insert destination record */ r_makecatkey(&key, dstid, dstname); r_packcatkey(&key, record, &reclen); r_packcatdata(&src, HFS_RECDATA(record), &reclen); if (bt_insert(&vol->cat, record, reclen) < 0) return -1; /* update thread record */ if (isdir) { if (v_getdthread(vol, src.u.dir.dirDirID, &dst, &n) <= 0) return -1; dst.u.dthd.thdParID = dstid; strcpy(dst.u.dthd.thdCName, dstname); if (v_putcatrec(&dst, &n) < 0) return -1; } else { found = v_getfthread(vol, src.u.fil.filFlNum, &dst, &n); if (found < 0) return -1; if (found) { dst.u.fthd.fthdParID = dstid; strcpy(dst.u.fthd.fthdCName, dstname); if (v_putcatrec(&dst, &n) < 0) return -1; } } /* update directory valences */ if (moving) { if (v_adjvalence(vol, srcid, isdir, -1) < 0 || v_adjvalence(vol, dstid, isdir, 1) < 0) return -1; } return 0; }
/* * NAME: record->packcatrec() * DESCRIPTION: create a packed catalog record */ void r_packcatrec(const CatKeyRec *key, const CatDataRec *data, byte *precord, int *len) { r_packcatkey(key, precord, len); r_packcatdata(data, HFS_RECDATA(precord), len); }
/* * NAME: hfs->create() * DESCRIPTION: create a new file */ int hfs_create(hfsvol *vol, char *path, char *type, char *creator) { CatKeyRec key; CatDataRec data; long id, parid; char name[HFS_MAX_FLEN + 1]; unsigned char record[HFS_CATRECMAXLEN]; int found, i, reclen; if (v_getvol(&vol) < 0) return -1; found = v_resolve(&vol, path, &data, &parid, name, 0); if (found < 0 || parid == 0) return -1; else if (found) { ERROR(EEXIST, 0); return -1; } if (parid == HFS_CNID_ROOTPAR) { ERROR(EINVAL, 0); return -1; } if (vol->flags & HFS_READONLY) { ERROR(EROFS, 0); return -1; } /* create file `name' in parent `parid' */ if (bt_space(&vol->cat, 1) < 0) return -1; id = vol->mdb.drNxtCNID++; vol->flags |= HFS_UPDATE_MDB; /* create file record */ data.cdrType = cdrFilRec; data.cdrResrv2 = 0; data.u.fil.filFlags = 0; data.u.fil.filTyp = 0; memset(&data.u.fil.filUsrWds, 0, sizeof(data.u.fil.filUsrWds)); data.u.fil.filUsrWds.fdType = d_getl((unsigned char *) type); data.u.fil.filUsrWds.fdCreator = d_getl((unsigned char *) creator); data.u.fil.filFlNum = id; data.u.fil.filStBlk = 0; data.u.fil.filLgLen = 0; data.u.fil.filPyLen = 0; data.u.fil.filRStBlk = 0; data.u.fil.filRLgLen = 0; data.u.fil.filRPyLen = 0; data.u.fil.filCrDat = d_tomtime(/*time*/(0)); data.u.fil.filMdDat = data.u.fil.filCrDat; data.u.fil.filBkDat = 0; memset(&data.u.fil.filFndrInfo, 0, sizeof(data.u.fil.filFndrInfo)); data.u.fil.filClpSize = 0; for (i = 0; i < 3; ++i) { data.u.fil.filExtRec[i].xdrStABN = 0; data.u.fil.filExtRec[i].xdrNumABlks = 0; data.u.fil.filRExtRec[i].xdrStABN = 0; data.u.fil.filRExtRec[i].xdrNumABlks = 0; } data.u.fil.filResrv = 0; r_makecatkey(&key, parid, name); r_packcatkey(&key, record, &reclen); r_packcatdata(&data, HFS_RECDATA(record), &reclen); if (bt_insert(&vol->cat, record, reclen) < 0 || v_adjvalence(vol, parid, 0, 1) < 0) return -1; return 0; }