📄 fatfs.c
字号:
/****************************************************************/
/* */
/* fatfs.c */
/* DOS-C */
/* */
/* FAT File System I/O 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 "../../hdr/portab.h"
#include "globals.h"
#ifdef VERSION_STRINGS
BYTE *RcsId = "$Header: C:/dos-c/src/fs/fatfs.c_v 1.12 03 Feb 1998 11:28:04 patv $";
#endif
/* $Log: C:/dos-c/src/fs/fatfs.c_v $
*
* Rev 1.12 03 Feb 1998 11:28:04 patv
* Fixed lseek bug.
*
* Rev 1.11 22 Jan 1998 5:38:08 patv
* Corrected remaining file name and extension copies that did not
* account for far file nodes due to allocated FILES= spec.
*
* Rev 1.10 22 Jan 1998 4:09:00 patv
* Fixed pointer problems affecting SDA
*
* Rev 1.9 04 Jan 1998 23:14:40 patv
* Changed Log for strip utility
*
* Rev 1.8 04 Jan 1998 17:24:14 patv
* Corrected subdirectory bug
*
* Rev 1.7 03 Jan 1998 8:36:04 patv
* Converted data area to SDA format
*
* Rev 1.6 22 Jan 1997 13:00:30 patv
* pre-0.92 bug fixes
*
* Rev 1.5 16 Jan 1997 12:46:24 patv
* pre-Release 0.92 feature additions
*
* Rev 1.4 29 May 1996 21:15:16 patv
* bug fixes for v0.91a
*
* Rev 1.3 19 Feb 1996 3:20:10 patv
* Added NLS, int2f and config.sys processing
*
* Rev 1.2 01 Sep 1995 17:48:40 patv
* First GPL release.
*
* Rev 1.1 30 Jul 1995 20:50:24 patv
* Eliminated version strings in ipl
*
* Rev 1.0 02 Jul 1995 8:04:46 patv
* Initial revision.
*/
/* $EndLog$ */
/* */
/* function prototypes */
/* */
struct f_node FAR *xlt_fd(COUNT);
COUNT xlt_fnp(struct f_node FAR *);
struct f_node FAR *split_path(BYTE FAR *, BYTE *, BYTE *, BYTE *);
BOOL find_fname(struct f_node FAR *, BYTE *, BYTE *);
date dos_getdate(VOID);
time dos_gettime(VOID);
BOOL find_free(struct f_node FAR *);
UWORD find_fat_free(struct f_node FAR *);
VOID wipe_out(struct f_node FAR *);
BOOL last_link(struct f_node FAR *);
BOOL extend(struct f_node FAR *);
COUNT extend_dir(struct f_node FAR *);
BOOL first_fat(struct f_node FAR *);
COUNT map_cluster(struct f_node FAR *, COUNT);
/************************************************************************/
/* */
/* Internal file handlers - open, create, read, write, close, etc. */
/* */
/************************************************************************/
/* Open a file given the path. Flags is 0 for read, 1 for write and 2 */
/* for update. */
/* Returns an integer file desriptor or a negative error code */
COUNT
dos_open (BYTE FAR *path, COUNT flag)
{
REG struct f_node FAR *fnp;
COUNT i;
BYTE FAR *fnamep;
/* First test the flag to see if the user has passed a valid */
/* file mode... */
if(flag < 0 || flag > 2)
return DE_INVLDACC;
/* first split the passed dir into comopnents (i.e. - path to */
/* new directory and name of new directory. */
if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
{
dir_close(fnp);
return DE_PATHNOTFND;
}
/* Look for the file. If we can't find it, just return a not */
/* found error. */
if(!find_fname(fnp, szFileName, szFileExt))
{
dir_close(fnp);
return DE_FILENOTFND;
}
/* Set the fnode to the desired mode */
fnp -> f_mode = flag;
/* Initialize the rest of the fnode. */
fnp -> f_offset = 0l;
fnp -> f_highwater = fnp -> f_dir.dir_size;
fnp -> f_back = LONG_LAST_CLUSTER;
fnp -> f_cluster = fnp -> f_dir.dir_start;
fnp -> f_flags.f_dmod = FALSE;
fnp -> f_flags.f_dnew = FALSE;
fnp -> f_flags.f_ddir = FALSE;
return xlt_fnp(fnp);
}
#ifndef IPL
BOOL fcmp(s1, s2, n)
BYTE FAR *s1, FAR *s2;
COUNT n;
{
while(n--)
if(*s1++ != *s2++)
return FALSE;
return TRUE;
}
BOOL fcmp_wild(s1, s2, n)
BYTE FAR *s1, FAR *s2;
COUNT n;
{
while(n--)
{
if(*s1 == '?')
{
++s1, ++s2;
continue;
}
if(*s1++ != *s2++)
return FALSE;
}
return TRUE;
}
#endif
COUNT
dos_close (COUNT fd)
{
struct f_node FAR *fnp;
/* Translate the fd into a useful pointer */
fnp = xlt_fd(fd);
/* If the fd was invalid because it was out of range or the */
/* requested file was not open, tell the caller and exit */
/* note: an invalid fd is indicated by a 0 return */
if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
return DE_INVLDHNDL;
if(fnp -> f_mode != RDONLY)
{
fnp -> f_dir.dir_size = fnp -> f_highwater;
fnp -> f_flags.f_dmod = TRUE;
}
fnp -> f_flags.f_ddir = TRUE;
dir_close(fnp);
return SUCCESS;
}
/* */
/* split a path into it's component directory and file name */
/* */
static struct f_node FAR *
split_path (BYTE FAR *path, BYTE *dname, BYTE *fname, BYTE *fext)
{
REG struct f_node FAR *fnp;
COUNT nDrive;
struct dpb *dpbp;
/* Start off by parsing out the components. */
ParseDosName(adjust_far(path), &nDrive, &dname[2], fname, fext);
if(nDrive < 0)
nDrive = default_drive;
dname[0] = 'A' + nDrive;
dname[1] = ':';
/* Add trailing spaces to the file name and extension */
SpacePad(fname, FNAME_SIZE);
SpacePad(fext, FEXT_SIZE);
/* If the path is null, we to default to the current */
/* directory... */
if(!dname[2])
{
dpbp = &blk_devices[nDrive];
fsncopy((BYTE FAR *)dpbp -> dpb_path,
(BYTE FAR *)&dname[2],
PARSE_MAX);
}
/* Translate the path into a useful pointer */
fnp = dir_open((BYTE FAR *)dname);
/* If the fd was invalid because it was out of range or the */
/* requested file was not open, tell the caller and exit... */
/* note: an invalid fd is indicated by a 0 return */
if(fnp == (struct f_node FAR *)0 || fnp -> f_count <= 0)
{
dir_close(fnp);
return (struct f_node FAR *)0;
}
/* Convert the name into an absolute name for comparison... */
upMem((BYTE FAR *)dname, strlen(dname));
upMem((BYTE FAR *)fname, FNAME_SIZE);
upMem((BYTE FAR *)fext, FEXT_SIZE);
return fnp;
}
static BOOL
find_fname (struct f_node FAR *fnp, BYTE *fname, BYTE *fext)
{
BOOL found = FALSE;
while(dir_read(fnp) == DIRENT_SIZE)
{
if(fnp -> f_dir.dir_name[0] != '\0')
{
if(fnp -> f_dir.dir_name[0] == DELETED)
continue;
if(fcmp((BYTE FAR *)fname, (BYTE FAR *)fnp -> f_dir.dir_name, FNAME_SIZE)
&& fcmp((BYTE FAR *)fext, (BYTE FAR *)fnp -> f_dir.dir_ext, FEXT_SIZE))
{
found = TRUE;
break;
}
}
}
return found;
}
#ifndef IPL
COUNT
dos_creat (BYTE FAR *path, COUNT attrib)
{
REG struct f_node FAR *fnp;
/* first split the passed dir into comopnents (i.e. - */
/* path to new directory and name of new directory */
if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
{
dir_close(fnp);
return DE_PATHNOTFND;
}
/* Check that we don't have a duplicate name, so if we */
/* find one, truncate it. */
if(find_fname(fnp, szFileName, szFileExt))
{
/* The only permissable attribute is archive, */
/* check for any other bit set. If it is, give */
/* an access error. */
if((fnp -> f_dir.dir_attrib & (D_RDONLY | D_DIR | D_VOLID))
|| (fnp -> f_dir.dir_attrib & ~D_ARCHIVE & ~attrib))
{
dir_close(fnp);
return DE_ACCESS;
}
/* Release the existing files FAT and set the */
/* length to zero, effectively truncating the */
/* file to zero. */
wipe_out(fnp);
}
else
{
BOOL is_free;
REG COUNT idx;
struct buffer FAR *bp;
BYTE FAR *p;
/* Reset the directory by a close followed by */
/* an open */
fnp -> f_flags.f_dmod = FALSE;
dir_close(fnp);
fnp = dir_open((BYTE FAR *)szDirName);
/* Get a free f_node pointer so that we can use */
/* it in building the new file. */
/* Note that if we're in the root and we don't */
/* find an empty slot, we need to abort. */
if(!(is_free = find_free(fnp)) && (fnp -> f_flags.f_droot))
{
fnp -> f_flags.f_dmod = FALSE;
dir_close(fnp);
return DE_TOOMANY;
}
/* Otherwise just expand the directory */
else if(!is_free && !(fnp -> f_flags.f_droot))
{
COUNT ret;
if((ret = extend_dir(fnp)) != SUCCESS)
return ret;
}
/* put the fnode's name into the directory. */
fbcopy((BYTE FAR *)szFileName,
(BYTE FAR *)fnp -> f_dir.dir_name, FNAME_SIZE);
fbcopy((BYTE FAR *)szFileExt,
(BYTE FAR *)fnp -> f_dir.dir_ext, FEXT_SIZE);
}
/* Set the fnode to the desired mode */
/* Updating the directory entry first. */
fnp -> f_mode = RDWR;
fnp -> f_dir.dir_size = 0l;
fnp -> f_dir.dir_start = FREE;
fnp -> f_dir.dir_attrib = attrib | D_ARCHIVE;
fnp -> f_dir.dir_time = dos_gettime();
fnp -> f_dir.dir_date = dos_getdate();
fnp -> f_flags.f_dmod = TRUE;
fnp -> f_flags.f_dnew = FALSE;
fnp -> f_flags.f_ddir = TRUE;
if(dir_write(fnp) != DIRENT_SIZE)
{
release_f_node(fnp);
return DE_ACCESS;
}
/* Now change to file */
fnp -> f_offset = 0l;
fnp -> f_highwater = 0l;
fnp -> f_back = LONG_LAST_CLUSTER;
fnp -> f_cluster = fnp -> f_dir.dir_start = FREE;
fnp -> f_flags.f_dmod = TRUE;
fnp -> f_flags.f_dnew = FALSE;
fnp -> f_flags.f_ddir = FALSE;
return xlt_fnp(fnp);
}
COUNT
dos_delete (BYTE FAR *path)
{
REG struct f_node FAR *fnp;
/* first split the passed dir into components (i.e. - */
/* path to new directory and name of new directory */
if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
{
dir_close(fnp);
return DE_PATHNOTFND;
}
/* Check that we don't have a duplicate name, so if we */
/* find one, it's an error. */
if(find_fname(fnp, szFileName, szFileExt))
{
/* The only permissable attribute is archive, */
/* check for any other bit set. If it is, give */
/* an access error. */
if(fnp -> f_dir.dir_attrib & ~D_ARCHIVE)
{
dir_close(fnp);
return DE_ACCESS;
}
/* Ok, so we can delete. Start out by */
/* clobbering all FAT entries for this file */
/* (or, in English, truncate the FAT). */
wipe_out(fnp);
fnp -> f_dir.dir_size = 0l;
*(fnp -> f_dir.dir_name) = DELETED;
/* The directory has been modified, so set the */
/* bit before closing it, allowing it to be */
/* updated */
fnp -> f_flags.f_dmod = TRUE;
dir_close(fnp);
/* SUCCESSful completion, return it */
return SUCCESS;
}
else
{
/* No such file, return the error */
dir_close(fnp);
return DE_FILENOTFND;
}
}
COUNT
dos_rmdir (BYTE FAR *path)
{
REG struct f_node FAR *fnp;
REG struct f_node FAR *fnp1;
BOOL found;
/* first split the passed dir into comopnents (i.e. - */
/* path to new directory and name of new directory */
if((fnp = split_path(path, szDirName, szFileName, szFileExt)) == NULL)
{
dir_close(fnp);
return DE_PATHNOTFND;
}
/* Check that we're not trying to remove the root! */
if((path[0] == '\\') && (path[1] == NULL))
{
dir_close(fnp);
return DE_ACCESS;
}
/* Check that we don't have a duplicate name, so if we */
/* find one, it's an error. */
if(find_fname(fnp, szFileName, szFileExt))
{
/* The only permissable attribute is directory, */
/* check for any other bit set. If it is, give */
/* an access error. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -