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

📄 fatfs.c

📁 xdos源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if(find_fname(fnp, szFileName, szFileExt))
	{
		dir_close(fnp);
		return DE_ACCESS;
	}
	else
	{
		BOOL is_free;

		/* Reset the directory by a close followed by   */
		/* an open                                      */
		fnp -> f_flags.f_dmod = FALSE;
		parent = fnp -> f_dirstart;
		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(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                            */
		fnp -> f_mode = WRONLY;
		fnp -> f_back = LONG_LAST_CLUSTER;

		fnp -> f_dir.dir_size = 0l;
		fnp -> f_dir.dir_start = FREE;
		fnp -> f_dir.dir_attrib = D_DIR;
		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;

		fnp -> f_highwater = 0l;
		fnp -> f_offset = 0l;
	}

	/* get an empty cluster, so that we make it into a      */
	/* directory.                                           */
	free_fat = find_fat_free(fnp);

	/* No empty clusters, disk is FULL! Translate into a    */
	/* useful error message.                                */
	if(free_fat == LONG_LAST_CLUSTER)
	{
		dir_close(fnp);
		return DE_HNDLDSKFULL;
	}

	/* Mark the cluster in the FAT as used                  */
	fnp -> f_dir.dir_start = fnp -> f_cluster = free_fat;
	link_fat(fnp -> f_dpb, (UCOUNT)free_fat, LONG_LAST_CLUSTER);

	/* Craft the new directory. Note that if we're in a new */
	/* directory just under the root, ".." pointer is 0.    */
	bp = getblock((LONG)clus2phys(free_fat,
		fnp -> f_dpb -> dpb_clssize,
		fnp -> f_dpb -> dpb_data),
		fnp -> f_dpb -> dpb_unit);
	if(bp == NULL)
	{
		dir_close(fnp);
		return DE_BLKINVLD;
	}

	/* Create the "." entry                                 */
	bcopy(".       ", (BYTE *)DirEntBuffer.dir_name, FNAME_SIZE);
	bcopy("   ", (BYTE *)DirEntBuffer.dir_ext, FEXT_SIZE);
	DirEntBuffer.dir_attrib = D_DIR;
	DirEntBuffer.dir_time = dos_gettime();
	DirEntBuffer.dir_date = dos_getdate();
	DirEntBuffer.dir_start = free_fat;
	DirEntBuffer.dir_size = 0l;

	/* And put it out                                       */
	putdirent((struct dirent FAR *)&DirEntBuffer, (BYTE FAR *)bp ->b_buffer);

	/* create the ".." entry                                */
	bcopy("..      ", (BYTE *)DirEntBuffer.dir_name, FNAME_SIZE);
	DirEntBuffer.dir_start = parent;

	/* and put it out                                       */
	putdirent((struct dirent FAR *)&DirEntBuffer, (BYTE FAR *)&bp -> b_buffer[DIRENT_SIZE]);

	/* fill the rest of the block with zeros                */
	for(p = (BYTE FAR *)&bp -> b_buffer[2 *DIRENT_SIZE];
	 p < &bp -> b_buffer[BUFFERSIZE]; )
		*p++ = NULL;

	/* Mark the block to be written out                     */
	bp -> b_flag |= BFR_DIRTY;

	/* clear out the rest of the blocks in the cluster      */
	for(idx = 1; idx < fnp -> f_dpb -> dpb_clssize; idx++)
	{
		REG COUNT i;

		bp = getblock(
			(LONG)clus2phys(fnp -> f_dir.dir_start,
			fnp -> f_dpb -> dpb_clssize,
			fnp -> f_dpb -> dpb_data) + idx,
			fnp -> f_dpb -> dpb_unit);
		if(bp == NULL)
		{
			dir_close(fnp);
			return DE_BLKINVLD;
		}
		for(i = 0, p = (BYTE FAR *)bp -> b_buffer; i < BUFFERSIZE; i++)
			*p++ = NULL;
		bp -> b_flag |= BFR_DIRTY;
	}

	/* flush the drive buffers so that all info is written  */
	flush_buffers((COUNT)(fnp -> f_dpb -> dpb_unit));

	/* Close the directory so that the entry is updated     */
	fnp -> f_flags.f_dmod = TRUE;
	dir_close(fnp);

	return SUCCESS;
}
#endif


BOOL 
last_link (struct f_node FAR *fnp)
{
	return (((UWORD)fnp -> f_cluster == (UWORD)LONG_LAST_CLUSTER)
	 || ((UWORD)fnp -> f_cluster == (UWORD)LAST_CLUSTER));
}

#ifndef IPL
static BOOL 
extend (struct f_node FAR *fnp)
{
	UWORD free_fat;

	/* get an empty cluster, so that we use it to extend the file.  */
	free_fat = find_fat_free(fnp);

	/* No empty clusters, disk is FULL! Translate into a useful     */
	/* error message.                                               */
	if(free_fat == LONG_LAST_CLUSTER)
		return FALSE;

	/* Now that we've found a free FAT entry, mark it as the last   */
	/* entry and save.                                              */
	link_fat(fnp -> f_dpb, (UCOUNT)fnp -> f_back, free_fat);
	fnp -> f_cluster = free_fat;
	link_fat(fnp -> f_dpb, (UCOUNT)free_fat, LONG_LAST_CLUSTER);

	/* Mark the directory so that the entry is updated              */
	fnp -> f_flags.f_dmod = TRUE;
	return TRUE;
}


static COUNT 
extend_dir (struct f_node FAR *fnp)
{
	REG COUNT idx;

	if(!extend(fnp))
	{
		dir_close(fnp);
		return DE_HNDLDSKFULL;
	}

	/* clear out the rest of the blocks in the cluster              */
	for(idx = 0; idx < fnp -> f_dpb -> dpb_clssize; idx++)
	{
		REG COUNT i;
		REG BYTE FAR *p;
		REG struct buffer FAR *bp;

		bp = getblock(
			(LONG)clus2phys(fnp -> f_cluster,
			fnp -> f_dpb -> dpb_clssize,
			fnp -> f_dpb -> dpb_data) + idx,
			fnp -> f_dpb -> dpb_unit);
		if(bp == NULL)
		{
			dir_close(fnp);
			return DE_BLKINVLD;
		}
		for(i = 0, p = (BYTE FAR *)bp -> b_buffer; i < BUFFERSIZE; i++)
			*p++ = NULL;
		bp -> b_flag |= BFR_DIRTY;
	}

	if(!find_free(fnp))
	{
		dir_close(fnp);
		return DE_HNDLDSKFULL;
	}

	/* flush the drive buffers so that all info is written          */
	flush_buffers((COUNT)(fnp -> f_dpb -> dpb_unit));

	return SUCCESS;

}


static BOOL 
first_fat (struct f_node FAR *fnp)
{
	UWORD free_fat;

	/* get an empty cluster, so that we make it into a file.        */
	free_fat = find_fat_free(fnp);

	/* No empty clusters, disk is FULL! Translate into a useful     */
	/* error message.                                               */
	if(free_fat == LONG_LAST_CLUSTER)
		return FALSE;

	/* Now that we've found a free FAT entry, mark it as the last   */
	/* entry and save it.                                           */
	fnp -> f_dir.dir_start = free_fat;
	link_fat(fnp -> f_dpb, (UCOUNT)free_fat, LONG_LAST_CLUSTER);

	/* Mark the directory so that the entry is updated              */
	fnp -> f_flags.f_dmod = TRUE;
	return TRUE;
}
#endif


COUNT 
map_cluster (REG struct f_node FAR *fnp, COUNT mode)
{
	ULONG idx;
	WORD clssize, secsize;

	/* Set internal index and cluster size.                 */
	idx = fnp -> f_offset;
	
	/* The variable clssize will be used later.             */
	secsize = fnp -> f_dpb -> dpb_secsize;
	clssize = secsize * fnp -> f_dpb -> dpb_clssize;

#ifndef IPL
	/* If someone did a seek, but no writes have occured, we will   */
	/* need to initialize the fnode.                                */
	if((mode == XFR_WRITE) && (fnp -> f_dir.dir_start == FREE))
	{        
		if(!first_fat(fnp))
			return DE_HNDLDSKFULL;
	}
#endif

	/* Now begin the linear search. The relative cluster is         */
	/* maintained as part of the set of physical indices. It is     */
	/* also the highest order index and is mapped directly into     */
	/* physical cluster. Our search is performed by pacing an index */
	/* up to the relative cluster position where the index falls    */
	/* within the cluster.                                          */
	/*                                                              */
	/* NOTE: make sure your compiler does not optimize for loop     */
	/* tests to the loop exit. We need to fall out immediately for  */
	/* files whose length < cluster size.                           */
	for(fnp -> f_cluster = fnp -> f_flags.f_ddir ?
				fnp -> f_dirstart :
				fnp -> f_dir.dir_start;
	  idx >= clssize;
	   idx -= clssize)
	{
		/* If this is a read and the next is a LAST_CLUSTER,    */
		/* then we are going to read past EOF, return zero read */
		if((mode == XFR_READ) && last_link(fnp))
			return DE_SEEK;
#ifndef IPL
	/* expand the list if we're going to write and have run into    */
	/* the last cluster marker.                                     */
		else if((mode == XFR_WRITE) && last_link(fnp))
		{
			
			if(!extend(fnp))
			{
				dir_close(fnp);
				return DE_HNDLDSKFULL;
			}
		}
#endif
		fnp -> f_back = fnp -> f_cluster;
		fnp -> f_cluster = next_cluster(fnp -> f_dpb,fnp -> f_cluster);
	}
	return SUCCESS;
}

UCOUNT 
rdwrblock (COUNT fd, VOID FAR *buffer, UCOUNT count, COUNT mode, COUNT *err)
{
	REG struct f_node FAR *fnp;
	REG struct buffer FAR *bp;
	UCOUNT xfr_cnt = 0, ret_cnt = 0;
	LONG idx;
	WORD secsize;
	UCOUNT to_xfer = count;

#ifdef DEBUG
	if(bDumpRdWrParms)
	{
		printf("rdwrblock: mode = %s\n",
		 mode == XFR_WRITE ? "WRITE" : "READ");
		printf(" fd   buffer     count\n --   ------     -----\n");
		printf(" %02d   %04x:%04x   %d\n",
		 fd, (COUNT)FP_SEG(buffer), (COUNT)FP_OFF(buffer), count);
	}
#endif
	/* Translate the fd into an fnode pointer, since all internal   */
	/* operations are achieved through fnodes.                      */
	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)
	{
		*err = DE_INVLDHNDL;
		return 0;
	}
	
	/* Test that we are really about to do a data transfer. If the  */
	/* count is zero and the mode is XFR_READ, just exit. (Any	*/
	/* read with a count of zero is a nop).                         */
	/*                                                              */
	/* A write (mode is XFR_WRITE) is a special case.  It sets the	*/
	/* file length to the current length (truncates it).            */
	/*                                                              */
	/* NOTE: doing this up front saves a lot of headaches later.    */
	if(count == 0)
	{
		if(mode == XFR_WRITE)
		{
			fnp -> f_highwater = fnp -> f_offset;
		}

		*err = SUCCESS;
		return 0;
	}

	/* Another test is to check for a seek past EOF on an XFR_READ  */
	/* operation.                                                   */
	if(mode == XFR_READ
	 && !fnp -> f_flags.f_ddir
	 && (fnp -> f_offset >= fnp -> f_dir.dir_size))
	{
		*err = SUCCESS;
		return 0;
	}

	/* test that we have a valid mode for this fnode                */
	switch(mode)
	{
	case XFR_READ:
		if(fnp -> f_mode != RDONLY && fnp -> f_mode != RDWR)
		{
			*err = DE_INVLDACC;
			return 0;
		}
		break;

#ifndef IPL
	case XFR_WRITE:
		if(fnp -> f_mode != WRONLY && fnp -> f_mode != RDWR)
		{
			*err = DE_INVLDACC;
			return 0;
		}
		break;
#endif
	default:
		*err = DE_INVLDACC;
		return 0;
	}

	/* The variable secsize will be used later.                     */
	secsize = fnp -> f_dpb -> dpb_secsize;

	/* Adjust the far pointer from user space to supervisor space   */
	buffer = adjust_far((VOID FAR *)buffer);

	/* Do the data transfer. Use block transfer methods so that we  */
	/* can utilize memory management in future DOS-C versions.	*/
	while(ret_cnt < count)
	{
		/* Position the file to the fnode's pointer position. This is   */
		/* done by updating the fnode's cluster, block (sector) and     */
		/* byte offset so that read or write becomes a simple data move */
		/* into or out of the block data buffer.                        */
		if(fnp -> f_offset == 0l)
		{
#ifndef IPL
			/* For the write case, a newly created file     */
			/* will have a start cluster of FREE. If we're  */
			/* doing a write and this is the first time     */
			/* through, allocate a new cluster to the file. */
			if((mode == XFR_WRITE)
			 && (fnp -> f_dir.dir_start == FREE))
				if(!first_fat(fnp))
				{
					dir_close(fnp);
					*err = DE_HNDLDSKFULL;
					return ret_cnt;
				}
#endif
			/* complete the common operations of            */
			/* initializing to the starting cluster and     */
			/* setting all offsets to zero.                 */
			fnp -> f_cluster = fnp -> f_dir.dir_start;
			fnp -> f_back = LONG_LAST_CLUSTER;
			fnp -> f_sector = 0;
			fnp -> f_boff = 0;
		}

		/* The more difficult scenario is the (more common)     */
		/* file offset case. Here, we need to take the fnode's  */
		/* offset pointer (f_offset) and translate it into a    */
		/* relative cluster position, cluster block (sector)    */
		/* offset (f_sector) and byte offset (f_boff). Once we  */
		/* have this information, we need to translate the      */
		/* relative cluster position into an absolute cluster   */
		/* position (f_cluster). This is unfortunate because it */
		/* requires a linear search through the file's FAT      */
		/* entries. It made sense when DOS was originally       */
		/* designed as a simple floppy disk operating system    */
		/* where the FAT was contained in core, but now         */
		/* requires a search through the FAT blocks.            */
		/*                                                      */
		/* The algorithm in this function takes advantage of    */
		/* the blockio block buffering scheme to simplify the   */
		/* task.                                                */
		else
			switch(map_cluster(fnp, mode))
			{
			case DE_SEEK:
				*err = DE_SEEK;
				dir_close(fnp);
				return ret_cnt;

			default:
				dir_close(fnp);
				*err = DE_HNDLDSKFULL;
				return ret_cnt;

			case SUCCESS:
				break;
			}
#ifndef IPL
		/* XFR_WRITE case only - if we're at the end, the next  */
		/* FAT is an EOF marker, so just extend the file length */

⌨️ 快捷键说明

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