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

📄 fatdir.c

📁 开源DOS的C代码源程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************/
/*                                                              */
/*                          fatdir.c                            */
/*                            DOS-C                             */
/*                                                              */
/*                 FAT File System dir Functions                */
/*                                                              */
/*                      Copyright (c) 1995                      */
/*                      Pasquale J. Villani                     */
/*                      All Rights Reserved                     */
/*                                                              */
/* This file is part of DOS-C.                                  */
/*                                                              */
/* DOS-C 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, or (at your option) any later version.                    */
/*                                                              */
/* DOS-C 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 DOS-C; see the file COPYING.  If not,     */
/* write to the Free Software Foundation, 675 Mass Ave,         */
/* Cambridge, MA 02139, USA.                                    */
/****************************************************************/

#include "portab.h"
#include "globals.h"

#ifdef VERSION_STRINGS
static BYTE *fatdirRcsId =
    "$Id: fatdir.c,v 1.47 2004/05/23 18:28:18 bartoldeman Exp $";
#endif

/* Description.
 *  Initialize a fnode so that it will point to the directory with 
 *  dirstart starting cluster; in case of passing dirstart == 0
 *  fnode will point to the start of a root directory */
VOID dir_init_fnode(f_node_ptr fnp, CLUSTER dirstart)
{
  /* reset the directory flags    */
  fnp->f_flags = F_DDIR;
  fnp->f_diroff = 0;
  fnp->f_offset = 0l;
  fnp->f_cluster_offset = 0;

  /* root directory */
#ifdef WITHFAT32
  if (dirstart == 0)
    if (ISFAT32(fnp->f_dpb))
      dirstart = fnp->f_dpb->dpb_xrootclst;
#endif
  fnp->f_cluster = fnp->f_dirstart = dirstart;
}

f_node_ptr dir_open(register const char *dirname)
{
  f_node_ptr fnp;
  int i;
  char fcbname[FNAME_SIZE + FEXT_SIZE];

  /* Allocate an fnode if possible - error return (0) if not.     */
  if ((fnp = get_f_node()) == (f_node_ptr) 0)
  {
    return (f_node_ptr) 0;
  }

  /* Force the fnode into read-write mode                         */
  fnp->f_mode = RDWR;

  /* determine what drive and dpb we are using...                 */
  fnp->f_dpb = get_dpb(dirname[0]-'A');
  /* Perform all directory common handling after all special      */
  /* handling has been performed.                                 */

  if (media_check(fnp->f_dpb) < 0)
  {
    release_f_node(fnp);
    return (f_node_ptr) 0;
  }

  /* Walk the directory tree to find the starting cluster         */
  /*                                                              */
  /* Start from the root directory (dirstart = 0)                 */

  /* The CDS's cdsStartCls may be used to shorten the search
     beginning at the CWD, see mapPath() and CDS.H in order
     to enable this behaviour there.
           -- 2001/09/04 ska*/

  dir_init_fnode(fnp, 0);

  dirname += 2;               /* Assume FAT style drive       */
  while(*dirname != '\0')
  {
    /* skip all path seperators                             */
    while (*dirname == '\\')
      ++dirname;
    /* don't continue if we're at the end                   */
    if (*dirname == '\0')
      break;

    /* Convert the name into an absolute name for           */
    /* comparison...                                        */

    memset(fcbname, ' ', FNAME_SIZE + FEXT_SIZE);

    for (i = 0; i < FNAME_SIZE + FEXT_SIZE; i++, dirname++)
    {
      char c = *dirname;
      if (c == '.')
        i = FNAME_SIZE - 1;
      else if (c != '\0' && c != '\\')
        fcbname[i] = c;
      else
        break;
    }

    /* Now search through the directory to  */
    /* find the entry...                    */
    i = FALSE;

    while (dir_read(fnp) == 1)
    {
      if (!(fnp->f_dir.dir_attrib & D_VOLID) &&
          fcbmatch(fcbname, fnp->f_dir.dir_name))
      {
        i = TRUE;
        break;
      }
      fnp->f_diroff++;
    }

    if (!i || !(fnp->f_dir.dir_attrib & D_DIR))
    {
      release_f_node(fnp);
      return (f_node_ptr) 0;
    }
    else
    {
      /* make certain we've moved off */
      /* root                         */
      dir_init_fnode(fnp, getdstart(fnp->f_dpb, &fnp->f_dir));
    }
  }
  return fnp;
}

/* swap internal and external delete flags */
STATIC void swap_deleted(char *name)
{
  if (name[0] == DELETED || name[0] == EXT_DELETED)
    name[0] ^= EXT_DELETED - DELETED; /* 0xe0 */
}

STATIC struct buffer FAR *getblock_from_off(f_node_ptr fnp, unsigned secsize)
{
  /* Compute the block within the cluster and the */
  /* offset within the block.                     */
  unsigned sector;

  sector = (UBYTE)(fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask;

  /* Get the block we need from cache             */
  return getblock(clus2phys(fnp->f_cluster, fnp->f_dpb) + sector,
                  fnp->f_dpb->dpb_unit);
}

/* Description.
 *  Read next consequitive directory entry, pointed by fnp.
 *  If some error occures the other critical
 *  fields aren't changed, except those used for caching.
 *  The fnp->f_diroff always corresponds to the directory entry
 *  which has been read.
 * Return value.
 *  1              - all OK, directory entry having been read is not empty.
 *  0              - Directory entry is empty.
 *  DE_SEEK        - Attempt to read beyound the end of the directory.
 *  DE_BLKINVLD    - Invalid block.
 * Note. Empty directory entries always resides at the end of the directory. */
COUNT dir_read(REG f_node_ptr fnp)
{
  struct buffer FAR *bp;
  REG UWORD secsize = fnp->f_dpb->dpb_secsize;

  /* can't have more than 65535 directory entries */
  if (fnp->f_diroff >= 65535U)
      return DE_SEEK;

  /* Determine if we hit the end of the directory. If we have,    */
  /* bump the offset back to the end and exit. If not, fill the   */
  /* dirent portion of the fnode, clear the f_dmod bit and leave, */
  /* but only for root directories                                */

  if (fnp->f_dirstart == 0)
  {
    if (fnp->f_diroff >= fnp->f_dpb->dpb_dirents)
      return DE_SEEK;

    bp = getblock(fnp->f_diroff / (secsize / DIRENT_SIZE)
                           + fnp->f_dpb->dpb_dirstrt, fnp->f_dpb->dpb_unit);
#ifdef DISPLAY_GETBLOCK
    printf("DIR (dir_read)\n");
#endif
  }
  else
  {
    /* Do a "seek" to the directory position        */
    fnp->f_offset = fnp->f_diroff * (ULONG)DIRENT_SIZE;

    /* Search through the FAT to find the block     */
    /* that this entry is in.                       */
#ifdef DISPLAY_GETBLOCK
    printf("dir_read: ");
#endif
    if (map_cluster(fnp, XFR_READ) != SUCCESS)
      return DE_SEEK;

    bp = getblock_from_off(fnp, secsize);
#ifdef DISPLAY_GETBLOCK
    printf("DIR (dir_read)\n");
#endif
  }

  /* Now that we have the block for our entry, get the    */
  /* directory entry.                                     */
  if (bp == NULL)
    return DE_BLKINVLD;

  bp->b_flag &= ~(BFR_DATA | BFR_FAT);
  bp->b_flag |= BFR_DIR | BFR_VALID;

  getdirent((BYTE FAR *) & bp->
            b_buffer[(fnp->f_diroff * DIRENT_SIZE) % fnp->f_dpb->dpb_secsize],
            &fnp->f_dir);

  swap_deleted(fnp->f_dir.dir_name);

  /* Update the fnode's directory info                    */
  fnp->f_flags &= ~F_DMOD;

  /* and for efficiency, stop when we hit the first       */
  /* unused entry.                                        */
  /* either returns 1 or 0                                */
  return (fnp->f_dir.dir_name[0] != '\0');
}

/* Description.
 *  Writes directory entry pointed by fnp to disk. In case of erroneous
 *  situation fnode is released.
 *  The caller should set
 *    1. F_DMOD flag if original directory entry was modified.
 * Return value.
 *  TRUE  - all OK.
 *  FALSE - error occured (fnode is released).
 */
#ifndef IPL
BOOL dir_write(REG f_node_ptr fnp)
{
  struct buffer FAR *bp;
  REG UWORD secsize = fnp->f_dpb->dpb_secsize;

  if (!(fnp->f_flags & F_DDIR))
    return FALSE;

  /* Update the entry if it was modified by a write or create...  */
  if (fnp->f_flags & F_DMOD)
  {
    /* Root is a consecutive set of blocks, so handling is  */
    /* simple.                                              */
    if (fnp->f_dirstart == 0)
    {
      bp = getblock(fnp->f_diroff / (secsize / DIRENT_SIZE)
                             + fnp->f_dpb->dpb_dirstrt,
                    fnp->f_dpb->dpb_unit);
#ifdef DISPLAY_GETBLOCK
      printf("DIR (dir_write)\n");
#endif
    }

    /* All other directories are just files. The only       */
    /* special handling is resetting the offset so that we  */
    /* can continually update the same directory entry.     */
    else
    {

      /* Do a "seek" to the directory position        */
      /* and convert the fnode to a directory fnode.  */
      fnp->f_offset = fnp->f_diroff * (ULONG)DIRENT_SIZE;
      fnp->f_cluster = fnp->f_dirstart;
      fnp->f_cluster_offset = 0;

⌨️ 快捷键说明

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