⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 volume.c

📁 创建一个符合iso-9660标准的iso文件系统
💻 C
字号:
/* * hfsutils - tools for reading and writing Macintosh HFS volumes * Copyright (C) 1996, 1997 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. */#include <mconfig.h>#include <stdxlib.h>#include <strdefs.h>#include <errno.h>#include <time.h>#include "internal.h"#include "data.h"#include "low.h"#include "btree.h"#include "record.h"#include "volume.h"static	void	markexts	__PR((block *vbm, ExtDataRec *exts));/* * NAME:	vol->catsearch() * DESCRIPTION:	search catalog tree */int v_catsearch(vol, parid, name, data, cname, np)	hfsvol		*vol;	long		parid;	char		*name;	CatDataRec	*data;	char		*cname;	node		*np;{  CatKeyRec key;  unsigned char pkey[HFS_CATKEYLEN];  node n;  unsigned char *ptr;  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(file, fabn, data, np)	hfsfile		*file;	unsigned int	fabn;	ExtDataRec	*data;	node		*np;{  ExtKeyRec key;  ExtDataRec extsave;  unsigned int fabnsave;  unsigned char pkey[HFS_EXTKEYLEN];  node n;  unsigned char *ptr;  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(vol, id, thread, np, type)	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 <= 0)    return found;  if (thread->cdrType != type)    {      ERROR(EIO, "bad thread record");      return -1;    }  return 1;}/* * NAME:	vol->putcatrec() * DESCRIPTION:	store catalog information */int v_putcatrec(data, np)	CatDataRec	*data;	node		*np;{  unsigned char 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->putextrec() * DESCRIPTION:	store extent information */int v_putextrec(data, np)	ExtDataRec	*data;	node		*np;{  unsigned char pdata[HFS_EXTDATALEN], *ptr;  int len = 0;  r_packextdata(data, pdata, &len);  ptr = HFS_NODEREC(*np, np->rnum);  memcpy(HFS_RECDATA(ptr), pdata, len);  return bt_putnode(np);}/* * NAME:	vol->allocblocks() * DESCRIPTION:	allocate a contiguous range of blocks */int v_allocblocks(vol, blocks)	hfsvol		*vol;	ExtDescriptor	*blocks;{  unsigned int request, found, foundat, start, end, pt;  block *vbm;  int wrap = 0;  if (vol->mdb.drFreeBks == 0)    {      ERROR(ENOSPC, "volume full");      return -1;    }  request = blocks->xdrNumABlks;  found   = 0;  foundat = 0;  start   = vol->mdb.drAllocPtr;  end     = vol->mdb.drNmAlBlks;  pt      = start;  vbm     = vol->vbm;  if (request == 0)    abort();  while (1)    {      unsigned int mark;      /* skip blocks in use */      while (pt < end && BMTST(vbm, pt))	++pt;      if (wrap && pt >= start)	break;      /* count blocks not in use */      mark = pt;      while (pt < end && pt - mark < request && ! BMTST(vbm, pt))	++pt;      if (pt - mark > found)	{	  found   = pt - mark;	  foundat = mark;	}      if (pt == end)	pt = 0, wrap = 1;      if (found == request)	break;    }  if (found == 0 || found > vol->mdb.drFreeBks)    {      ERROR(EIO, "bad volume bitmap or free block count");      return -1;    }  blocks->xdrStABN    = foundat;  blocks->xdrNumABlks = found;  vol->mdb.drAllocPtr = pt;  vol->mdb.drFreeBks -= found;  for (pt = foundat; pt < foundat + found; ++pt)    BMSET(vbm, pt);  vol->flags |= HFS_UPDATE_MDB | HFS_UPDATE_VBM;  return 0;}/* * NAME:	vol->freeblocks() * DESCRIPTION:	deallocate a contiguous range of blocks */void v_freeblocks(vol, blocks)	hfsvol		*vol;	ExtDescriptor	*blocks;{  unsigned int start, len, pt;  block *vbm;  start = blocks->xdrStABN;  len   = blocks->xdrNumABlks;  vbm   = vol->vbm;  vol->mdb.drFreeBks += len;  for (pt = start; pt < start + len; ++pt)    BMCLR(vbm, pt);  vol->flags |= HFS_UPDATE_MDB | HFS_UPDATE_VBM;}/* * NAME:	vol->resolve() * DESCRIPTION:	translate a pathname; return catalog information */int v_resolve(vol, path, data, parid, fname, np)	hfsvol		**vol;	char		*path;	CatDataRec	*data;	long		*parid;	char		*fname;	node		*np;{  long dirid;  char name[HFS_MAX_FLEN + 1], *nptr;  int found;  if (*path == 0)    {      ERROR(ENOENT, "empty path");      return -1;    }  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 <= 0)	    return found;	  if (parid)	    *parid = data->u.dthd.thdParID;	  return v_catsearch(*vol, data->u.dthd.thdParID,			     data->u.dthd.thdCName, data, fname, np);	}    }  else    {      hfsvol *check;      dirid = HFS_CNID_ROOTPAR;  /* absolute path */      if (nptr - path > HFS_MAX_VLEN)	{	  ERROR(ENAMETOOLONG, 0);	  return -1;	}      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 <= 0)	    return found;	  dirid = data->u.dthd.thdParID;	}      if (*path == 0)	{	  found = v_getdthread(*vol, dirid, data, 0);	  if (found <= 0)	    return found;	  if (parid)	    *parid = data->u.dthd.thdParID;	  return v_catsearch(*vol, data->u.dthd.thdParID,			     data->u.dthd.thdCName, data, fname, np);	}      nptr = name;      while (nptr < name + sizeof(name) - 1 && *path && *path != ':')	*nptr++ = *path++;      if (*path && *path != ':')	{	  ERROR(ENAMETOOLONG, 0);	  return -1;	}      *nptr = 0;      if (*path == ':')	++path;      if (parid)	*parid = dirid;      found = v_catsearch(*vol, dirid, name, data, fname, np);      if (found < 0)	return -1;      if (found == 0)	{	  if (*path && parid)	    *parid = 0;	  if (*path == 0 && fname)	    strcpy(fname, name);	  return 0;	}      switch (data->cdrType)	{	case cdrDirRec:	  if (*path == 0)	    return 1;	  dirid = data->u.dir.dirDirID;	  break;	case cdrFilRec:	  if (*path == 0)	    return 1;	  ERROR(ENOTDIR, "invalid pathname");	  return -1;	default:	  ERROR(EIO, "unexpected catalog record");	  return -1;	}    }}/* * NAME:	vol->destruct() * DESCRIPTION:	free memory consumed by a volume descriptor */void v_destruct(vol)	hfsvol	*vol;{  FREE(vol->vbm);  FREE(vol->ext.map);  FREE(vol->cat.map);  FREE(vol);}/* * NAME:	vol->getvol() * DESCRIPTION:	validate a volume reference */int v_getvol(vol)	hfsvol	**vol;{  if (*vol == 0)    {      if (hfs_curvol == 0)	{	  ERROR(EINVAL, "no volume is current");	  return -1;	}      *vol = hfs_curvol;    }  return 0;}/* * NAME:	vol->flush() * DESCRIPTION:	flush all pending changes (B*-tree, MDB, VBM) to disk */int v_flush(vol, umounting)	hfsvol	*vol;	int	umounting;{  if (! (vol->flags & HFS_READONLY))    {      if ((vol->ext.flags & HFS_UPDATE_BTHDR) &&	  bt_writehdr(&vol->ext) < 0)	return -1;      if ((vol->cat.flags & HFS_UPDATE_BTHDR) &&	  bt_writehdr(&vol->cat) < 0)	return -1;      if ((vol->flags & HFS_UPDATE_VBM) &&	  l_writevbm(vol) < 0)	return -1;      if (umounting &&	  ! (vol->mdb.drAtrb & HFS_ATRB_UMOUNTED))	{	  vol->mdb.drAtrb |= HFS_ATRB_UMOUNTED;	  vol->flags |= HFS_UPDATE_MDB;	}      if ((vol->flags & (HFS_UPDATE_MDB | HFS_UPDATE_ALTMDB)) &&	  l_writemdb(vol) < 0)	return -1;    }  return 0;}/* * NAME:	vol->adjvalence() * DESCRIPTION:	update a volume's valence counts */int v_adjvalence(vol, parid, isdir, adj)	hfsvol	*vol;	long	parid;	int	isdir;	int	adj;{  node n;  CatDataRec data;  if (isdir)    vol->mdb.drDirCnt += adj;  else    vol->mdb.drFilCnt += adj;  vol->flags |= HFS_UPDATE_MDB;  if (parid == HFS_CNID_ROOTDIR)    {      if (isdir)	vol->mdb.drNmRtDirs += adj;      else	vol->mdb.drNmFls    += adj;    }  else if (parid == HFS_CNID_ROOTPAR)    return 0;  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");      return -1;    }  data.u.dir.dirVal  += adj;  data.u.dir.dirMdDat = d_tomtime(time(0));  return v_putcatrec(&data, &n);}/* * NAME:	vol->newfolder() * DESCRIPTION:	create a new HFS folder */int v_newfolder(vol, parid, name)	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;  data.u.dir.dirCrDat = d_tomtime(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_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:	markexts() * DESCRIPTION:	set bits from an extent record in the volume bitmap */staticvoid markexts(vbm, exts)	block		*vbm;	ExtDataRec	*exts;{  int i;  unsigned int start, len;  for (i = 0; i < 3; ++i)    {      for (start = (*exts)[i].xdrStABN,	     len = (*exts)[i].xdrNumABlks; len--; ++start)	BMSET(vbm, start);    }}/* * NAME:	vol->scavenge() * DESCRIPTION:	safeguard blocks in the volume bitmap */int v_scavenge(vol)	hfsvol	*vol;{  block *vbm = vol->vbm;  node n;  unsigned int pt, blks;  if (vbm == 0)    return 0;  markexts(vbm, &vol->mdb.drXTExtRec);  markexts(vbm, &vol->mdb.drCTExtRec);  vol->flags |= HFS_UPDATE_VBM;  /* scavenge the extents overflow file */  n.bt   = &vol->ext;  n.nnum = vol->ext.hdr.bthFNode;  if (n.nnum > 0)    {      if (bt_getnode(&n) < 0)	return -1;      n.rnum = 0;      while (1)	{	  ExtDataRec data;	  unsigned char *ptr;	  while (n.rnum >= n.nd.ndNRecs)	    {	      n.nnum = n.nd.ndFLink;	      if (n.nnum == 0)		break;	      if (bt_getnode(&n) < 0)		return -1;	      n.rnum = 0;	    }	  if (n.nnum == 0)	    break;	  ptr = HFS_NODEREC(n, n.rnum);	  r_unpackextdata(HFS_RECDATA(ptr), &data);	  markexts(vbm, &data);	  ++n.rnum;	}    }  /* scavenge the catalog file */  n.bt   = &vol->cat;  n.nnum = vol->cat.hdr.bthFNode;  if (n.nnum > 0)    {      if (bt_getnode(&n) < 0)	return -1;      n.rnum = 0;      while (1)	{	  CatDataRec data;	  unsigned char *ptr;	  while (n.rnum >= n.nd.ndNRecs)	    {	      n.nnum = n.nd.ndFLink;	      if (n.nnum == 0)		break;	      if (bt_getnode(&n) < 0)		return -1;	      n.rnum = 0;	    }	  if (n.nnum == 0)	    break;	  ptr = HFS_NODEREC(n, n.rnum);	  r_unpackcatdata(HFS_RECDATA(ptr), &data);	  if (data.cdrType == cdrFilRec)	    {	      markexts(vbm, &data.u.fil.filExtRec);	      markexts(vbm, &data.u.fil.filRExtRec);	    }	  ++n.rnum;	}    }  for (blks = 0, pt = vol->mdb.drNmAlBlks; pt--; )    {      if (! BMTST(vbm, pt))	++blks;    }  if (vol->mdb.drFreeBks != blks)    {      vol->mdb.drFreeBks = blks;      vol->flags |= HFS_UPDATE_MDB;    }  return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -