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

📄 btree.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 "internal.h"#include "data.h"#include "block.h"#include "file.h"#include "btree.h"#include "node.h"/* * NAME:	btree->getnode() * DESCRIPTION:	retrieve a numbered node from a B*-tree file */int bt_getnode(np)	node	*np;{  btree *bt = np->bt;  block *bp = &np->data;  unsigned char *ptr;  int i;  /* verify the node exists and is marked as in-use */  if (np->nnum < 0 || (np->nnum > 0 && np->nnum >= bt->hdr.bthNNodes))    {      ERROR(EIO, "read nonexistent b*-tree node");      return -1;    }  if (bt->map && ! BMTST(bt->map, np->nnum))    {      ERROR(EIO, "read unallocated b*-tree node");      return -1;    }  if (f_getblock(&bt->f, np->nnum, bp) < 0)    return -1;  ptr = *bp;  d_fetchl(&ptr, (long *) &np->nd.ndFLink);  d_fetchl(&ptr, (long *) &np->nd.ndBLink);  d_fetchb(&ptr, (char *) &np->nd.ndType);  d_fetchb(&ptr, (char *) &np->nd.ndNHeight);  d_fetchw(&ptr, (short *) &np->nd.ndNRecs);  d_fetchw(&ptr, &np->nd.ndResv2);  if (np->nd.ndNRecs > HFS_MAXRECS)    {      ERROR(EIO, "too many b*-tree node records");      return -1;    }  i = np->nd.ndNRecs + 1;  ptr = *bp + HFS_BLOCKSZ - (2 * i);  while (i--)    d_fetchw(&ptr, (short *) &np->roff[i]);  return 0;}/* * NAME:	btree->putnode() * DESCRIPTION:	store a numbered node into a B*-tree file */int bt_putnode(np)	node	*np;{  btree *bt = np->bt;  block *bp = &np->data;  unsigned char *ptr;  int i;  /* verify the node exists and is marked as in-use */  if (np->nnum && np->nnum >= bt->hdr.bthNNodes)    {      ERROR(EIO, "write nonexistent b*-tree node");      return -1;    }  else if (bt->map && ! BMTST(bt->map, np->nnum))    {      ERROR(EIO, "write unallocated b*-tree node");      return -1;    }  ptr = *bp;  d_storel(&ptr, np->nd.ndFLink);  d_storel(&ptr, np->nd.ndBLink);  d_storeb(&ptr, np->nd.ndType);  d_storeb(&ptr, np->nd.ndNHeight);  d_storew(&ptr, np->nd.ndNRecs);  d_storew(&ptr, np->nd.ndResv2);  if (np->nd.ndNRecs > HFS_MAXRECS)    {      ERROR(EIO, "too many b*-tree node records");      return -1;    }  i = np->nd.ndNRecs + 1;  ptr = *bp + HFS_BLOCKSZ - (2 * i);  while (i--)    d_storew(&ptr, np->roff[i]);  if (f_putblock(&bt->f, np->nnum, bp) < 0)    return -1;  return 0;}/* * NAME:	btree->readhdr() * DESCRIPTION:	read the header node of a B*-tree */int bt_readhdr(bt)	btree	*bt;{  unsigned char *ptr;  char *map;  int i;  unsigned long nnum;  bt->hdrnd.bt   = bt;  bt->hdrnd.nnum = 0;  if (bt_getnode(&bt->hdrnd) < 0)    return -1;  if (bt->hdrnd.nd.ndType != ndHdrNode ||      bt->hdrnd.nd.ndNRecs != 3 ||      bt->hdrnd.roff[0] != 0x00e ||      bt->hdrnd.roff[1] != 0x078 ||      bt->hdrnd.roff[2] != 0x0f8 ||      bt->hdrnd.roff[3] != 0x1f8)    {      ERROR(EIO, "malformed b*-tree header node");      return -1;    }  /* read header record */  ptr = HFS_NODEREC(bt->hdrnd, 0);  d_fetchw(&ptr, (short *) &bt->hdr.bthDepth);  d_fetchl(&ptr, (long *) &bt->hdr.bthRoot);  d_fetchl(&ptr, (long *) &bt->hdr.bthNRecs);  d_fetchl(&ptr, (long *) &bt->hdr.bthFNode);  d_fetchl(&ptr, (long *) &bt->hdr.bthLNode);  d_fetchw(&ptr, (short *) &bt->hdr.bthNodeSize);  d_fetchw(&ptr, (short *) &bt->hdr.bthKeyLen);  d_fetchl(&ptr, (long *) &bt->hdr.bthNNodes);  d_fetchl(&ptr, (long *) &bt->hdr.bthFree);  for (i = 0; i < 76; ++i)    d_fetchb(&ptr, (char *) &bt->hdr.bthResv[i]);  if (bt->hdr.bthNodeSize != HFS_BLOCKSZ)    {      ERROR(EINVAL, "unsupported b*-tree node size");      return -1;    }  /* read map record; construct btree bitmap */  /* don't set bt->map until we're done, since getnode() checks it */  map = ALLOC(char, HFS_MAP1SZ);  if (map == 0)    {      ERROR(ENOMEM, 0);      return -1;    }  memcpy(map, HFS_NODEREC(bt->hdrnd, 2), HFS_MAP1SZ);  bt->mapsz = HFS_MAP1SZ;  /* read continuation map records, if any */  nnum = bt->hdrnd.nd.ndFLink;  while (nnum)    {      node n;      char *newmap;      n.bt   = bt;      n.nnum = nnum;      if (bt_getnode(&n) < 0)	{	  FREE(map);	  return -1;	}      if (n.nd.ndType != ndMapNode ||	  n.nd.ndNRecs != 1 ||	  n.roff[0] != 0x00e ||	  n.roff[1] != 0x1fa)	{	  FREE(map);	  ERROR(EIO, "malformed b*-tree map node");	  return -1;	}      newmap = REALLOC(map, char, bt->mapsz + HFS_MAPXSZ);      if (newmap == 0)	{	  FREE(map);	  ERROR(ENOMEM, 0);	  return -1;	}      map = newmap;      memcpy(map + bt->mapsz, HFS_NODEREC(n, 0), HFS_MAPXSZ);      bt->mapsz += HFS_MAPXSZ;      nnum = n.nd.ndFLink;    }  bt->map = map;  return 0;}/* * NAME:	btree->writehdr() * DESCRIPTION:	write the header node of a B*-tree */int bt_writehdr(bt)	btree	*bt;{  unsigned char *ptr;  char *map;  unsigned long mapsz, nnum;  int i;  if (bt->hdrnd.bt != bt ||      bt->hdrnd.nnum != 0 ||      bt->hdrnd.nd.ndType != ndHdrNode ||      bt->hdrnd.nd.ndNRecs != 3)    abort();  ptr = HFS_NODEREC(bt->hdrnd, 0);  d_storew(&ptr, bt->hdr.bthDepth);  d_storel(&ptr, bt->hdr.bthRoot);  d_storel(&ptr, bt->hdr.bthNRecs);  d_storel(&ptr, bt->hdr.bthFNode);  d_storel(&ptr, bt->hdr.bthLNode);  d_storew(&ptr, bt->hdr.bthNodeSize);  d_storew(&ptr, bt->hdr.bthKeyLen);  d_storel(&ptr, bt->hdr.bthNNodes);  d_storel(&ptr, bt->hdr.bthFree);  for (i = 0; i < 76; ++i)    d_storeb(&ptr, bt->hdr.bthResv[i]);  memcpy(HFS_NODEREC(bt->hdrnd, 2), bt->map, HFS_MAP1SZ);  if (bt_putnode(&bt->hdrnd) < 0)    return -1;  map   = bt->map   + HFS_MAP1SZ;  mapsz = bt->mapsz - HFS_MAP1SZ;  nnum  = bt->hdrnd.nd.ndFLink;  while (mapsz)    {      node n;      if (nnum == 0)	{	  ERROR(EIO, "truncated b*-tree map");	  return -1;	}      n.bt   = bt;      n.nnum = nnum;      if (bt_getnode(&n) < 0)	return -1;      if (n.nd.ndType != ndMapNode ||	  n.nd.ndNRecs != 1 ||	  n.roff[0] != 0x00e ||	  n.roff[1] != 0x1fa)	{	  ERROR(EIO, "malformed b*-tree map node");	  return -1;	}      memcpy(HFS_NODEREC(n, 0), map, HFS_MAPXSZ);      if (bt_putnode(&n) < 0)	return -1;      map   += HFS_MAPXSZ;      mapsz -= HFS_MAPXSZ;      nnum = n.nd.ndFLink;    }  bt->flags &= ~HFS_UPDATE_BTHDR;  return 0;}/* High-Level B*-Tree Routines ============================================= *//* * NAME:	btree->space() * DESCRIPTION:	assert space for new records, or extend the file */int bt_space(bt, nrecs)	btree		*bt;	unsigned int	nrecs;{  unsigned int nnodes;  int space;  nnodes = nrecs * (bt->hdr.bthDepth + 1);  if (nnodes <= bt->hdr.bthFree)    return 0;  /* make sure the extents tree has room too */  if (bt != &bt->f.vol->ext)    {      if (bt_space(&bt->f.vol->ext, 1) < 0)	return -1;    }  space = f_alloc(&bt->f);  if (space < 0)    return -1;  nnodes = space * (bt->f.vol->mdb.drAlBlkSiz / bt->hdr.bthNodeSize);  bt->hdr.bthNNodes += nnodes;  bt->hdr.bthFree   += nnodes;  bt->flags |= HFS_UPDATE_BTHDR;  bt->f.vol->flags |= HFS_UPDATE_ALTMDB;  while (bt->hdr.bthNNodes > bt->mapsz * 8)    {      char *newmap;      node mapnd;      /* extend tree map */      newmap = REALLOC(bt->map, char, bt->mapsz + HFS_MAPXSZ);      if (newmap == 0)	{	  ERROR(ENOMEM, 0);	  return -1;	}      memset(newmap + bt->mapsz, 0, HFS_MAPXSZ);      bt->map    = newmap;      bt->mapsz += HFS_MAPXSZ;      n_init(&mapnd, bt, ndMapNode, 0);      if (n_new(&mapnd) < 0)	return -1;      /* link the new map node */      if (bt->hdrnd.nd.ndFLink == 0)	{	  bt->hdrnd.nd.ndFLink = mapnd.nnum;	  mapnd.nd.ndBLink     = 0;	}      else	{	  node n;	  n.bt   = bt;	  n.nnum = bt->hdrnd.nd.ndFLink;	  while (1)	    {	      if (bt_getnode(&n) < 0)		return -1;	      if (n.nd.ndFLink == 0)		break;	      n.nnum = n.nd.ndFLink;	    }	  n.nd.ndFLink     = mapnd.nnum;	  mapnd.nd.ndBLink = n.nnum;	  if (bt_putnode(&n) < 0)	    return -1;	}      mapnd.nd.ndNRecs = 1;      mapnd.roff[1]    = 0x1fa;      if (bt_putnode(&mapnd) < 0)	return -1;    }  return 0;}/* * NAME:	btree->insertx() * DESCRIPTION:	recursively locate a node and insert a record */int bt_insertx(np, record, reclen)	node		*np;	unsigned char	*record;	int		*reclen;{  node child;  unsigned char *rec;  if (n_search(np, record))    {      ERROR(EIO, "b*-tree record already exists");      return -1;    }  switch ((unsigned char) np->nd.ndType)    {    case ndIndxNode:      if (np->rnum < 0)	rec = HFS_NODEREC(*np, 0);      else	rec = HFS_NODEREC(*np, np->rnum);      child.bt   = np->bt;      child.nnum = d_getl(HFS_RECDATA(rec));      if (bt_getnode(&child) < 0 ||	  bt_insertx(&child, record, reclen) < 0)	return -1;      if (np->rnum < 0)	{	  n_index(np->bt, HFS_NODEREC(child, 0), child.nnum, rec, 0);	  if (*reclen == 0)	    return bt_putnode(np);	}      return *reclen ? n_insert(np, record, reclen) : 0;    case ndLeafNode:      return n_insert(np, record, reclen);    default:      ERROR(EIO, "unexpected b*-tree node");      return -1;    }}/* * NAME:	btree->insert() * DESCRIPTION:	insert a new node record into a tree */int bt_insert(bt, record, reclen)	btree		*bt;	unsigned char	*record;	int		reclen;{  node root;  if (bt->hdr.bthRoot == 0)    {      /* create root node */      n_init(&root, bt, ndLeafNode, 1);      if (n_new(&root) < 0 ||	  bt_putnode(&root) < 0)	return -1;      bt->hdr.bthDepth = 1;      bt->hdr.bthRoot  = root.nnum;      bt->hdr.bthFNode = root.nnum;      bt->hdr.bthLNode = root.nnum;      bt->flags |= HFS_UPDATE_BTHDR;    }  else    {      root.bt   = bt;      root.nnum = bt->hdr.bthRoot;      if (bt_getnode(&root) < 0)	return -1;    }  if (bt_insertx(&root, record, &reclen) < 0)    return -1;  if (reclen)    {      unsigned char oroot[HFS_MAXRECLEN];      int orootlen;      /* root node was split; create a new root */      n_index(bt, HFS_NODEREC(root, 0), root.nnum, oroot, &orootlen);      n_init(&root, bt, ndIndxNode, root.nd.ndNHeight + 1);      if (n_new(&root) < 0)	return -1;      ++bt->hdr.bthDepth;      bt->hdr.bthRoot = root.nnum;      bt->flags |= HFS_UPDATE_BTHDR;      /* insert index records for new root */      n_search(&root, oroot);      n_insertx(&root, oroot, orootlen);      n_search(&root, record);      n_insertx(&root, record, reclen);      if (bt_putnode(&root) < 0)	return -1;    }  ++bt->hdr.bthNRecs;  bt->flags |= HFS_UPDATE_BTHDR;  return 0;}/* * NAME:	btree->deletex() * DESCRIPTION:	recursively locate a node and delete a record */int bt_deletex(np, key, record, flag)	node		*np;	unsigned char	*key;	unsigned char	*record;	int		*flag;{  node child;  unsigned char *rec;  int found;  found = n_search(np, key);  switch ((unsigned char) np->nd.ndType)    {    case ndIndxNode:      if (np->rnum < 0)	{	  ERROR(EIO, "b*-tree record not found");	  return -1;	}      rec = HFS_NODEREC(*np, np->rnum);      child.bt   = np->bt;      child.nnum = d_getl(HFS_RECDATA(rec));      if (bt_getnode(&child) < 0 ||	  bt_deletex(&child, key, rec, flag) < 0)	return -1;      if (*flag)	{	  *flag = 0;	  if (HFS_RECKEYLEN(rec) == 0)	    return n_delete(np, record, flag);	  if (np->rnum == 0)	    {	      n_index(np->bt, HFS_NODEREC(*np, 0), np->nnum, record, 0);	      *flag = 1;	    }	  return bt_putnode(np);	}      return 0;    case ndLeafNode:      if (found == 0)	{	  ERROR(EIO, "b*-tree record not found");	  return -1;	}      return n_delete(np, record, flag);    default:      ERROR(EIO, "unexpected b*-tree node");      return -1;    }}/* * NAME:	btree->delete() * DESCRIPTION:	remove a node record from a tree */int bt_delete(bt, key)	btree		*bt;	unsigned char	*key;{  node root;  unsigned char record[HFS_MAXRECLEN];  int flag = 0;  root.bt   = bt;  root.nnum = bt->hdr.bthRoot;  if (root.nnum == 0)    {      ERROR(EIO, "empty b*-tree");      return -1;    }  if (bt_getnode(&root) < 0 ||      bt_deletex(&root, key, record, &flag) < 0)    return -1;  if (bt->hdr.bthDepth > 1 && root.nd.ndNRecs == 1)    {      unsigned char *rec;      /* chop the root */      rec = HFS_NODEREC(root, 0);      --bt->hdr.bthDepth;      bt->hdr.bthRoot = d_getl(HFS_RECDATA(rec));      n_free(&root);    }  else if (bt->hdr.bthDepth == 1 && root.nd.ndNRecs == 0)    {      /* delete the root node */      bt->hdr.bthDepth = 0;      bt->hdr.bthRoot  = 0;      bt->hdr.bthFNode = 0;      bt->hdr.bthLNode = 0;      n_free(&root);    }  --bt->hdr.bthNRecs;  bt->flags |= HFS_UPDATE_BTHDR;  return 0;}/* * NAME:	btree->search() * DESCRIPTION:	locate a data record given a search key */int bt_search(bt, key, np)	btree		*bt;	unsigned char	*key;	node		*np;{  np->bt   = bt;  np->nnum = bt->hdr.bthRoot;  if (np->nnum == 0)    {      ERROR(ENOENT, 0);      return 0;    }  while (1)    {      int found;      unsigned char *rec;      if (bt_getnode(np) < 0)	return -1;      found = n_search(np, key);      switch ((unsigned char) np->nd.ndType)	{	case ndIndxNode:	  if (np->rnum < 0)	    {	      ERROR(ENOENT, 0);	      return 0;	    }	  rec = HFS_NODEREC(*np, np->rnum);	  np->nnum = d_getl(HFS_RECDATA(rec));	  break;	case ndLeafNode:	  if (! found)	    ERROR(ENOENT, 0);	  return found;	default:	  ERROR(EIO, "unexpected b*-tree node");	  return -1;	}    }}

⌨️ 快捷键说明

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