Пример #1
0
/*
 * NAME:	hfs->vsetattr()
 * DESCRIPTION:	change volume attributes
 */
int hfs_vsetattr(hfsvol *vol, hfsvolent *ent)
{
  if (getvol(&vol) == -1)
    goto fail;

  if (ent->clumpsz % vol->mdb.drAlBlkSiz != 0)
    ERROR(EINVAL, "illegal clump size");

  /* make sure "blessed" folder exists */

  if (ent->blessed &&
      v_getdthread(vol, ent->blessed, 0, 0) <= 0)
    ERROR(EINVAL, "illegal blessed folder");

  if (vol->flags & HFS_VOL_READONLY)
    ERROR(EROFS, 0);

  vol->mdb.drClpSiz      = ent->clumpsz;

  vol->mdb.drCrDate      = d_mtime(ent->crdate);
  vol->mdb.drLsMod       = d_mtime(ent->mddate);
  vol->mdb.drVolBkUp     = d_mtime(ent->bkdate);

  vol->mdb.drFndrInfo[0] = ent->blessed;

  vol->flags |= HFS_VOL_UPDATE_MDB;

  return 0;

fail:
  return -1;
}
Пример #2
0
/*
 * 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;
}
Пример #3
0
/*
 * NAME:	vol->mkdir()
 * DESCRIPTION:	create a new HFS directory
 */
int v_mkdir(hfsvol *vol, long parid, const char *name)
{
    CatKeyRec key;
    CatDataRec data;
    long id;
    byte record[HFS_MAX_CATRECLEN];
    int i, reclen;

    if (bt_space(&vol->cat, 2) == -1)
        goto fail;

    id = vol->mdb.drNxtCNID++;
    vol->flags |= HFS_VOL_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;
    data.u.dir.dirCrDat = d_mtime(time(0));
    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_packcatrec(&key, &data, record, &reclen);

    if (bt_insert(&vol->cat, record, reclen) == -1)
        goto fail;

    /* 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_packcatrec(&key, &data, record, &reclen);

    if (bt_insert(&vol->cat, record, reclen) == -1 ||
            v_adjvalence(vol, parid, 1, 1) == -1)
        goto fail;

    return 0;

fail:
    return -1;
}
Пример #4
0
/*
 * NAME:	vol->adjvalence()
 * DESCRIPTION:	update a volume's valence counts
 */
int v_adjvalence(hfsvol *vol, long parid, int isdir, int adj)
{
    node n;
    CatDataRec data;
    int result = 0;

    if (isdir)
        vol->mdb.drDirCnt += adj;
    else
        vol->mdb.drFilCnt += adj;

    vol->flags |= HFS_VOL_UPDATE_MDB;

    if (parid == HFS_CNID_ROOTDIR)
    {
        if (isdir)
            vol->mdb.drNmRtDirs += adj;
        else
            vol->mdb.drNmFls    += adj;
    }
    else if (parid == HFS_CNID_ROOTPAR)
        goto done;

    if (v_getdthread(vol, parid, &data, 0) <= 0 ||
            v_catsearch(vol, data.u.dthd.thdParID, data.u.dthd.thdCName,
                        &data, 0, &n) <= 0 ||
            data.cdrType != cdrDirRec)
        ERROR(EIO, "can't find parent directory");

    data.u.dir.dirVal  += adj;
    data.u.dir.dirMdDat = d_mtime(time(0));

    result = v_putcatrec(&data, &n);

done:
    return result;

fail:
    return -1;
}
Пример #5
0
/*
 * NAME:	record->packdirent()
 * DESCRIPTION:	make changes to a catalog record
 */
void r_packdirent(CatDataRec *data, const hfsdirent *ent)
{
  switch (data->cdrType)
    {
    case cdrDirRec:
      data->u.dir.dirCrDat = d_mtime(ent->crdate);
      data->u.dir.dirMdDat = d_mtime(ent->mddate);
      data->u.dir.dirBkDat = d_mtime(ent->bkdate);

      data->u.dir.dirUsrInfo.frFlags      = ent->fdflags;
      data->u.dir.dirUsrInfo.frLocation.v = ent->fdlocation.v;
      data->u.dir.dirUsrInfo.frLocation.h = ent->fdlocation.h;

      data->u.dir.dirUsrInfo.frRect.top    = ent->u.dir.rect.top;
      data->u.dir.dirUsrInfo.frRect.left   = ent->u.dir.rect.left;
      data->u.dir.dirUsrInfo.frRect.bottom = ent->u.dir.rect.bottom;
      data->u.dir.dirUsrInfo.frRect.right  = ent->u.dir.rect.right;

      break;

    case cdrFilRec:
      if (ent->flags & HFS_ISLOCKED)
	data->u.fil.filFlags |=  (1 << 0);
      else
	data->u.fil.filFlags &= ~(1 << 0);

      data->u.fil.filCrDat = d_mtime(ent->crdate);
      data->u.fil.filMdDat = d_mtime(ent->mddate);
      data->u.fil.filBkDat = d_mtime(ent->bkdate);

      data->u.fil.filUsrWds.fdFlags      = ent->fdflags;
      data->u.fil.filUsrWds.fdLocation.v = ent->fdlocation.v;
      data->u.fil.filUsrWds.fdLocation.h = ent->fdlocation.h;

      data->u.fil.filUsrWds.fdType =
	d_getsl((unsigned char *) ent->u.file.type);
      data->u.fil.filUsrWds.fdCreator =
	d_getsl((unsigned char *) ent->u.file.creator);

      break;
    }
}
Пример #6
0
/*
 * NAME:	do_macb()
 * DESCRIPTION:	perform copy using MacBinary II translation
 */
static
int do_macb(hfsfile *ifile, int ofile)
{
  hfsdirent ent;
  unsigned char buf[MACB_BLOCKSZ];
  long bytes;

  if (hfs_fstat(ifile, &ent) == -1)
    {
      ERROR(errno, hfs_error);
      return -1;
    }

  memset(buf, 0, MACB_BLOCKSZ);

  buf[1] = strlen(ent.name);
  strcpy((char *) &buf[2], ent.name);

  memcpy(&buf[65], ent.u.file.type,    4);
  memcpy(&buf[69], ent.u.file.creator, 4);

  buf[73] = ent.fdflags >> 8;

  d_putul(&buf[83], ent.u.file.dsize);
  d_putul(&buf[87], ent.u.file.rsize);

  d_putul(&buf[91], d_mtime(ent.crdate));
  d_putul(&buf[95], d_mtime(ent.mddate));

  buf[101] = ent.fdflags & 0xff;
  buf[122] = buf[123] = 129;

  d_putuw(&buf[124], crc_macb(buf, 124, 0x0000));

  bytes = write(ofile, buf, MACB_BLOCKSZ);
  if (bytes == -1)
    {
      ERROR(errno, "error writing data");
      return -1;
    }
  else if (bytes != MACB_BLOCKSZ)
    {
      ERROR(EIO, "wrote incomplete chunk");
      return -1;
    }

  if (hfs_setfork(ifile, 0) == -1)
    {
      ERROR(errno, hfs_error);
      return -1;
    }

  if (fork_macb(ifile, ofile, ent.u.file.dsize) == -1)
    return -1;

  if (hfs_setfork(ifile, 1) == -1)
    {
      ERROR(errno, hfs_error);
      return -1;
    }

  if (fork_macb(ifile, ofile, ent.u.file.rsize) == -1)
    return -1;

  return 0;
}
Пример #7
0
/*
 * 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;
}
Пример #8
0
/*
 * NAME:	hfs->create()
 * DESCRIPTION:	create and open a new file
 */
hfsfile *hfs_create(hfsvol *vol, const char *path,
		    const char *type, const char *creator)
{
  hfsfile *file = 0;
  unsigned long parid;
  char name[HFS_MAX_FLEN + 1];
  CatKeyRec key;
  byte record[HFS_MAX_CATRECLEN];
  unsigned reclen;
  int found;

  if (getvol(&vol) == -1)
    goto fail;

  file = ALLOC(hfsfile, 1);
  if (file == 0)
    ERROR(ENOMEM, 0);

  found = v_resolve(&vol, path, &file->cat, &parid, name, 0);
  if (found == -1 || parid == 0)
    goto fail;

  if (found)
    ERROR(EEXIST, 0);

  if (parid == HFS_CNID_ROOTPAR)
    ERROR(EINVAL, 0);

  if (vol->flags & HFS_VOL_READONLY)
    ERROR(EROFS, 0);

  /* create file `name' in parent `parid' */

  if (bt_space(&vol->cat, 1) == -1)
    goto fail;

  f_init(file, vol, vol->mdb.drNxtCNID++, name);
  vol->flags |= HFS_VOL_UPDATE_MDB;

  file->parid = parid;

  /* create catalog record */

  file->cat.u.fil.filUsrWds.fdType =
    d_getsl((const unsigned char *) type);
  file->cat.u.fil.filUsrWds.fdCreator =
    d_getsl((const unsigned char *) creator);

  file->cat.u.fil.filCrDat = d_mtime(time(0));
  file->cat.u.fil.filMdDat = file->cat.u.fil.filCrDat;

  r_makecatkey(&key, file->parid, file->name);
  r_packcatrec(&key, &file->cat, record, &reclen);

  if (bt_insert(&vol->cat, record, reclen) == -1 ||
      v_adjvalence(vol, file->parid, 0, 1) == -1)
    goto fail;

  /* package file handle for user */

  file->next = vol->files;

  if (vol->files)
    vol->files->prev = file;

  vol->files = file;

  return file;

fail:
  FREE(file);
  return 0;
}
Пример #9
0
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;
}