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

📄 hfs.c

📁 open source bios with linux platform, very good and can be reused.
💻 C
字号:
/* * libhfs - library for reading and writing Macintosh HFS volumes * Copyright (C) 1996-1998 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. * * $Id: hfs.c,v 1.15 1998/11/02 22:09:00 rob Exp $ */#include "openbios/config.h"#include "libhfs.h"#include "data.h"#include "block.h"#include "medium.h"#include "file.h"#include "btree.h"#include "node.h"#include "record.h"#include "volume.h"const char *hfs_error = "no error";	/* static error string */hfsvol *hfs_mounts;			/* linked list of mounted volumes */statichfsvol *curvol;				/* current volume *//* * NAME:	getvol() * DESCRIPTION:	validate a volume reference */staticint getvol(hfsvol **vol){  if (*vol == 0)    {      if (curvol == 0)	ERROR(EINVAL, "no volume is current");      *vol = curvol;    }  return 0;fail:  return -1;}/* High-Level Volume Routines ============================================== *//* * NAME:	hfs->mount() * DESCRIPTION:	open an HFS volume; return volume descriptor or 0 (error) */hfsvol *hfs_mount( int os_fd, int pnum){  hfsvol *vol, *check;  int mode = HFS_MODE_RDONLY;    /* see if the volume is already mounted */  for (check = hfs_mounts; check; check = check->next)    {      if (check->pnum == pnum && v_same(check, os_fd) == 1)	{	    vol = check;	    goto done;	}    }  vol = ALLOC(hfsvol, 1);  if (vol == 0)    ERROR(ENOMEM, 0);  v_init(vol, mode);  vol->flags |= HFS_VOL_READONLY;  if( v_open(vol, os_fd) == -1 )	  goto fail;  /* mount the volume */  if (v_geometry(vol, pnum) == -1 ||      v_mount(vol) == -1)    goto fail;  /* add to linked list of volumes */  vol->prev = 0;  vol->next = hfs_mounts;  if (hfs_mounts)    hfs_mounts->prev = vol;  hfs_mounts = vol;done:  ++vol->refs;  curvol = vol;  return vol;fail:  if (vol)    {      v_close(vol);      FREE(vol);    }  return 0;}/* * NAME:	hfs->umount() * DESCRIPTION:	close an HFS volume */int hfs_umount(hfsvol *vol){  int result = 0;  if (getvol(&vol) == -1)    goto fail;  if (--vol->refs)    {      goto done;    }  /* close all open files and directories */  while (vol->files)    {      if (hfs_close(vol->files) == -1)	result = -1;    }  while (vol->dirs)    {      if (hfs_closedir(vol->dirs) == -1)	result = -1;    }  /* close medium */  if (v_close(vol) == -1)    result = -1;  /* remove from linked list of volumes */  if (vol->prev)    vol->prev->next = vol->next;  if (vol->next)    vol->next->prev = vol->prev;  if (vol == hfs_mounts)    hfs_mounts = vol->next;  if (vol == curvol)    curvol = 0;  FREE(vol);done:  return result;fail:  return -1;}/* * NAME:	hfs->umountall() * DESCRIPTION:	unmount all mounted volumes */void hfs_umountall(void){  while (hfs_mounts)    hfs_umount(hfs_mounts);}/* * NAME:	hfs->getvol() * DESCRIPTION:	return a pointer to a mounted volume */hfsvol *hfs_getvol(const char *name){  hfsvol *vol;  if (name == 0)    return curvol;  for (vol = hfs_mounts; vol; vol = vol->next)    {      if (d_relstring(name, vol->mdb.drVN) == 0)	return vol;    }  return 0;}/* * NAME:	hfs->setvol() * DESCRIPTION:	change the current volume */void hfs_setvol(hfsvol *vol){  curvol = vol;}/* * NAME:	hfs->vstat() * DESCRIPTION:	return volume statistics */int hfs_vstat(hfsvol *vol, hfsvolent *ent){  if (getvol(&vol) == -1)    goto fail;  strcpy(ent->name, vol->mdb.drVN);  ent->flags     = (vol->flags & HFS_VOL_READONLY) ? HFS_ISLOCKED : 0;  ent->totbytes  = vol->mdb.drNmAlBlks * vol->mdb.drAlBlkSiz;  ent->freebytes = vol->mdb.drFreeBks  * vol->mdb.drAlBlkSiz;  ent->alblocksz = vol->mdb.drAlBlkSiz;  ent->clumpsz   = vol->mdb.drClpSiz;  ent->numfiles  = vol->mdb.drFilCnt;  ent->numdirs   = vol->mdb.drDirCnt;  ent->crdate    = d_ltime(vol->mdb.drCrDate);  ent->mddate    = d_ltime(vol->mdb.drLsMod);  ent->bkdate    = d_ltime(vol->mdb.drVolBkUp);  ent->blessed   = vol->mdb.drFndrInfo[0];  return 0;fail:  return -1;}/* High-Level Directory Routines =========================================== *//* * NAME:	hfs->chdir() * DESCRIPTION:	change current HFS directory */int hfs_chdir(hfsvol *vol, const char *path){  CatDataRec data;  if (getvol(&vol) == -1 ||      v_resolve(&vol, path, &data, 0, 0, 0) <= 0)    goto fail;  if (data.cdrType != cdrDirRec)    ERROR(ENOTDIR, 0);  vol->cwd = data.u.dir.dirDirID;  return 0;fail:  return -1;}/* * NAME:	hfs->getcwd() * DESCRIPTION:	return the current working directory ID */unsigned long hfs_getcwd(hfsvol *vol){  if (getvol(&vol) == -1)    return 0;  return vol->cwd;}/* * NAME:	hfs->setcwd() * DESCRIPTION:	set the current working directory ID */int hfs_setcwd(hfsvol *vol, unsigned long id){  if (getvol(&vol) == -1)    goto fail;  if (id == vol->cwd)    goto done;  /* make sure the directory exists */  if (v_getdthread(vol, id, 0, 0) <= 0)    goto fail;  vol->cwd = id;done:  return 0;fail:  return -1;}/* * NAME:	hfs->dirinfo() * DESCRIPTION:	given a directory ID, return its (name and) parent ID */int hfs_dirinfo(hfsvol *vol, unsigned long *id, char *name){  CatDataRec thread;  if (getvol(&vol) == -1 ||      v_getdthread(vol, *id, &thread, 0) <= 0)    goto fail;  *id = thread.u.dthd.thdParID;  if (name)    strcpy(name, thread.u.dthd.thdCName);  return 0;fail:  return -1;}/* * NAME:	hfs->opendir() * DESCRIPTION:	prepare to read the contents of a directory */hfsdir *hfs_opendir(hfsvol *vol, const char *path){  hfsdir *dir = 0;  CatKeyRec key;  CatDataRec data;  byte pkey[HFS_CATKEYLEN];  if (getvol(&vol) == -1)    goto fail;  dir = ALLOC(hfsdir, 1);  if (dir == 0)    ERROR(ENOMEM, 0);  dir->vol = vol;  if (*path == 0)    {      /* meta-directory containing root dirs from all mounted volumes */      dir->dirid = 0;      dir->vptr  = hfs_mounts;    }  else    {      if (v_resolve(&vol, path, &data, 0, 0, 0) <= 0)	goto fail;      if (data.cdrType != cdrDirRec)	ERROR(ENOTDIR, 0);      dir->dirid = data.u.dir.dirDirID;      dir->vptr  = 0;      r_makecatkey(&key, dir->dirid, "");      r_packcatkey(&key, pkey, 0);      if (bt_search(&vol->cat, pkey, &dir->n) <= 0)	goto fail;    }  dir->prev = 0;  dir->next = vol->dirs;  if (vol->dirs)    vol->dirs->prev = dir;  vol->dirs = dir;  return dir;fail:  FREE(dir);  return 0;}/* * 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 == 0)	ERROR(ENOENT, "no more entries");      if (v_getdthread(vol, HFS_CNID_ROOTDIR, &data, 0) <= 0 ||	  v_catsearch(vol, HFS_CNID_ROOTPAR, data.u.dthd.thdCName,		      &data, cname, 0) <= 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;}/* * NAME:	hfs->closedir() * DESCRIPTION:	stop reading a directory */int hfs_closedir(hfsdir *dir){  hfsvol *vol = dir->vol;  if (dir->prev)    dir->prev->next = dir->next;  if (dir->next)    dir->next->prev = dir->prev;  if (dir == vol->dirs)    vol->dirs = dir->next;  FREE(dir);  return 0;}/* High-Level File Routines ================================================ *//* * NAME:	hfs->open() * DESCRIPTION:	prepare a file for I/O */hfsfile *hfs_open(hfsvol *vol, const char *path){  hfsfile *file = 0;  if (getvol(&vol) == -1)    goto fail;  file = ALLOC(hfsfile, 1);  if (file == 0)    ERROR(ENOMEM, 0);  if (v_resolve(&vol, path, &file->cat, &file->parid, file->name, 0) <= 0)    goto fail;  if (file->cat.cdrType != cdrFilRec)    ERROR(EISDIR, 0);  /* package file handle for user */  file->vol   = vol;  file->flags = 0;  f_selectfork(file, fkData);  file->prev = 0;  file->next = vol->files;  if (vol->files)    vol->files->prev = file;  vol->files = file;  return file;fail:  FREE(file);  return 0;}/* * NAME:	hfs->setfork() * DESCRIPTION:	select file fork for I/O operations */int hfs_setfork(hfsfile *file, int fork){  int result = 0;  f_selectfork(file, fork ? fkRsrc : fkData);  return result;}/* * NAME:	hfs->getfork() * DESCRIPTION:	return the current fork for I/O operations */int hfs_getfork(hfsfile *file){  return file->fork != fkData;}/* * NAME:	hfs->read() * DESCRIPTION:	read from an open file */unsigned long hfs_read(hfsfile *file, void *buf, unsigned long len){  unsigned long *lglen, count;  byte *ptr = buf;  f_getptrs(file, 0, &lglen, 0);  if (file->pos + len > *lglen)    len = *lglen - file->pos;  count = len;  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 (offs == 0 && chunk == HFS_BLOCKSZ)	{	  if (f_getblock(file, bnum, (block *) ptr) == -1)	    goto fail;	}      else	{	  block b;	  if (f_getblock(file, bnum, &b) == -1)	    goto fail;	  memcpy(ptr, b + offs, chunk);	}      ptr += chunk;      file->pos += chunk;      count     -= chunk;    }  return len;fail:  return -1;}/* * NAME:	hfs->seek() * DESCRIPTION:	change file seek pointer */unsigned long hfs_seek(hfsfile *file, long offset, int from){  unsigned long *lglen, newpos;  f_getptrs(file, 0, &lglen, 0);  switch (from)    {    case HFS_SEEK_SET:      newpos = (offset < 0) ? 0 : offset;      break;    case HFS_SEEK_CUR:      if (offset < 0 && (unsigned long) -offset > file->pos)	newpos = 0;      else	newpos = file->pos + offset;      break;    case HFS_SEEK_END:      if (offset < 0 && (unsigned long) -offset > *lglen)	newpos = 0;      else	newpos = *lglen + offset;      break;    default:      ERROR(EINVAL, 0);    }  if (newpos > *lglen)    newpos = *lglen;  file->pos = newpos;  return newpos;fail:  return -1;}/* * NAME:	hfs->close() * DESCRIPTION:	close a file */int hfs_close(hfsfile *file){  hfsvol *vol = file->vol;  int result = 0;  if (file->prev)    file->prev->next = file->next;  if (file->next)    file->next->prev = file->prev;  if (file == vol->files)    vol->files = file->next;  FREE(file);  return result;}/* High-Level Catalog Routines ============================================= *//* * NAME:	hfs->stat() * DESCRIPTION:	return catalog information for an arbitrary path */int hfs_stat(hfsvol *vol, const char *path, hfsdirent *ent){  CatDataRec data;  unsigned long parid;  char name[HFS_MAX_FLEN + 1];  if (getvol(&vol) == -1 ||      v_resolve(&vol, path, &data, &parid, name, 0) <= 0)    goto fail;  r_unpackdirent(parid, name, &data, ent);  return 0;fail:  return -1;}/* * NAME:	hfs->fstat() * DESCRIPTION:	return catalog information for an open file */int hfs_fstat(hfsfile *file, hfsdirent *ent){  r_unpackdirent(file->parid, file->name, &file->cat, ent);  return 0;}

⌨️ 快捷键说明

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