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

📄 fatfs.c

📁 xdos源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************/
/*                                                              */
/*                          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 + -