Exemplo n.º 1
0
/*
 * NAME:	file->flush()
 * DESCRIPTION:	flush all pending changes to an open file
 */
int f_flush(hfsfile *file)
{
  hfsvol *vol = file->vol;

  if (vol->flags & HFS_VOL_READONLY)
    goto done;

  if (file->flags & HFS_FILE_UPDATE_CATREC)
    {
      node n;

      file->cat.u.fil.filStBlk  = file->cat.u.fil.filExtRec[0].xdrStABN;
      file->cat.u.fil.filRStBlk = file->cat.u.fil.filRExtRec[0].xdrStABN;

      if (v_catsearch(vol, file->parid, file->name, 0, 0, &n) <= 0 ||
	  v_putcatrec(&file->cat, &n) == -1)
	goto fail;

      file->flags &= ~HFS_FILE_UPDATE_CATREC;
    }

done:
  return 0;

fail:
  return -1;
}
Exemplo n.º 2
0
/*
 * NAME:	vol->getthread()
 * DESCRIPTION:	retrieve catalog thread information for a file or directory
 */
int v_getthread(hfsvol *vol, 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;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
/*
 * NAME:	file->flush()
 * DESCRIPTION:	flush all pending changes to an open file
 */
int f_flush(hfsfile *file)
{
  hfsvol *vol = file->vol;

  if (! (vol->flags & HFS_READONLY))
    {
      if (file->flags & HFS_UPDATE_CATREC)
	{
	  node n;

	  file->cat.u.fil.filStBlk   = file->cat.u.fil.filExtRec[0].xdrStABN;
	  file->cat.u.fil.filRStBlk  = file->cat.u.fil.filRExtRec[0].xdrStABN;
	  file->cat.u.fil.filClpSize = file->clump;

	  if (v_catsearch(file->vol, file->parid, file->name, 0, 0, &n) <= 0 ||
	      v_putcatrec(&file->cat, &n) < 0)
	    return -1;

	  file->flags &= ~HFS_UPDATE_CATREC;
	}
    }

  return 0;
}
Exemplo n.º 5
0
/*
 * 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)
{
    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;
}
Exemplo n.º 6
0
Arquivo: hfs.c Projeto: 3a9LL/panda
/*
 * NAME:	hfs->readdir()
 * DESCRIPTION:	return the next entry in the directory
 */
int hfs_readdir(hfsdir *dir, hfsdirent *ent)
{
  CatKeyRec key;
  CatDataRec data;
  const byte *ptr;

  if (dir->dirid == 0)
    {
      hfsvol *vol;
      char cname[HFS_MAX_FLEN + 1];

      for (vol = hfs_mounts; vol; vol = vol->next)
	{
	  if (vol == dir->vptr)
	    break;
	}

      if (vol == NULL)
	ERROR(ENOENT, "no more entries");

      if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, NULL) <= 0 ||
	  v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,
                      &data, cname, NULL) <= 0)
	goto fail;

      r_unpackdirent(HFS_CNID_ROOTPAR, cname, &data, ent);

      dir->vptr = vol->next;

      goto done;
    }

  if (dir->n.rnum == -1)
    ERROR(ENOENT, "no more entries");

  while (1)
    {
      ++dir->n.rnum;

      while (dir->n.rnum >= dir->n.nd.ndNRecs)
	{
	  if (dir->n.nd.ndFLink == 0)
	    {
	      dir->n.rnum = -1;
	      ERROR(ENOENT, "no more entries");
	    }

	  if (bt_getnode(&dir->n, dir->n.bt, dir->n.nd.ndFLink) == -1)
	    {
	      dir->n.rnum = -1;
	      goto fail;
	    }

	  dir->n.rnum = 0;
	}

      ptr = HFS_NODEREC(dir->n, dir->n.rnum);

      r_unpackcatkey(ptr, &key);

      if (key.ckrParID != dir->dirid)
	{
	  dir->n.rnum = -1;
	  ERROR(ENOENT, "no more entries");
	}

      r_unpackcatdata(HFS_RECDATA(ptr), &data);

      switch (data.cdrType)
	{
	case cdrDirRec:
	case cdrFilRec:
	  r_unpackdirent(key.ckrParID, key.ckrCName, &data, ent);
	  goto done;

	case cdrThdRec:
	case cdrFThdRec:
	  break;

	default:
	  dir->n.rnum = -1;
	  ERROR(EIO, "unexpected directory entry found");
	}
    }

done:
  return 0;

fail:
  return -1;
}
Exemplo n.º 7
0
/*
 * NAME:	hfs->rename()
 * DESCRIPTION:	change the name of and/or move a file or directory
 */
int hfs_rename(hfsvol *vol, const char *srcpath, const char *dstpath)
{
  hfsvol *srcvol;
  CatDataRec src, dst;
  unsigned long srcid, dstid;
  CatKeyRec key;
  char srcname[HFS_MAX_FLEN + 1], dstname[HFS_MAX_FLEN + 1];
  byte record[HFS_MAX_CATRECLEN];
  unsigned int reclen;
  int found, isdir, moving;
  node n;

  if (getvol(&vol) == -1 ||
      v_resolve(&vol, srcpath, &src, &srcid, srcname, 0) <= 0)
    goto fail;

  isdir  = (src.cdrType == cdrDirRec);
  srcvol = vol;

  found = v_resolve(&vol, dstpath, &dst, &dstid, dstname, 0);
  if (found == -1)
    goto fail;

  if (vol != srcvol)
    ERROR(EINVAL, "can't move across volumes");

  if (dstid == 0)
    ERROR(ENOENT, "bad destination path");

  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 == -1)
	goto fail;
    }

  moving = (srcid != dstid);

  if (found)
    {
      const char *ptr;

      ptr = strrchr(dstpath, ':');
      if (ptr == 0)
	ptr = dstpath;
      else
	++ptr;

      if (*ptr)
	strcpy(dstname, ptr);

      if (! moving && strcmp(srcname, dstname) == 0)
	goto done;  /* source and destination are identical */

      if (moving || d_relstring(srcname, dstname))
	ERROR(EEXIST, "can't use destination name");
    }

  /* can't move anything into the root directory's parent */

  if (moving && dstid == HFS_CNID_ROOTPAR)
    ERROR(EINVAL, "can't move above root directory");

  if (moving && isdir)
    {
      unsigned long id;

      /* can't move root directory anywhere */

      if (src.u.dir.dirDirID == HFS_CNID_ROOTDIR)
	ERROR(EINVAL, "can't move root directory");

      /* 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");

	  if (v_getdthread(vol, id, &dst, 0) <= 0)
	    goto fail;
	}
    }

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

  /* change volume name */

  if (dstid == HFS_CNID_ROOTPAR)
    {
      if (! validvname(dstname))
	goto fail;

      strcpy(vol->mdb.drVN, dstname);
      vol->flags |= HFS_VOL_UPDATE_MDB;
    }

  /* remove source record */

  r_makecatkey(&key, srcid, srcname);
  r_packcatkey(&key, record, 0);

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

  /* insert destination record */

  r_makecatkey(&key, dstid, dstname);
  r_packcatrec(&key, &src, record, &reclen);

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

  /* update thread record */

  if (isdir)
    {
      if (v_getdthread(vol, src.u.dir.dirDirID, &dst, &n) <= 0)
	goto fail;

      dst.u.dthd.thdParID = dstid;
      strcpy(dst.u.dthd.thdCName, dstname);

      if (v_putcatrec(&dst, &n) == -1)
	goto fail;
    }
  else
    {
      found = v_getfthread(vol, src.u.fil.filFlNum, &dst, &n);
      if (found == -1)
	goto fail;

      if (found)
	{
	  dst.u.fthd.fthdParID = dstid;
	  strcpy(dst.u.fthd.fthdCName, dstname);

	  if (v_putcatrec(&dst, &n) == -1)
	    goto fail;
	}
    }

  /* update directory valences */

  if (moving)
    {
      if (v_adjvalence(vol, srcid, isdir, -1) == -1 ||
	  v_adjvalence(vol, dstid, isdir,  1) == -1)
	goto fail;
    }

done:
  return 0;

fail:
  return -1;
}