📄 fatdir.c
字号:
/****************************************************************/
/* */
/* 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 + -