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

📄 fatfs.c

📁 xdos源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		if(mode == XFR_WRITE && last_link(fnp))
			if(!extend(fnp))
			{
				dir_close(fnp);
				*err = DE_HNDLDSKFULL;
				return ret_cnt;
			}
#endif

		/* Compute the block within the cluster and the offset  */
		/* within the block.                                    */
		fnp -> f_sector =
		 (fnp -> f_offset / secsize) & fnp -> f_dpb -> dpb_clsmask;
		fnp -> f_boff = fnp -> f_offset % secsize;

#ifdef DSK_DEBUG
	printf("%d links; dir offset %ld, starting at cluster %d\n",
		fnp -> f_count,
		fnp -> f_diroff,
		fnp -> f_cluster);
#endif
		/* Do an EOF test and return whatever was transferred   */
		/* but only for regular files in XFR_READ mode          */
		if((mode == XFR_READ) && !(fnp -> f_flags.f_ddir)
		  && (fnp -> f_offset >= fnp -> f_dir.dir_size))
		{
			*err = SUCCESS;
			return ret_cnt;
		}
		
		/* Get the block we need from cache                     */
		bp = getblock(
			(LONG)clus2phys(fnp -> f_cluster,
				fnp -> f_dpb -> dpb_clssize,
				fnp -> f_dpb -> dpb_data) + fnp -> f_sector,
			fnp -> f_dpb -> dpb_unit);
		
		if(bp == (struct buffer *)0)
		{
			*err = DE_BLKINVLD;
			return ret_cnt;
		}

		/* transfer a block                                     */
		/* Transfer size as either a full block size, or the    */
		/* requested transfer size, whichever is smaller.       */
		/* Then compare to what is left, since we can transfer  */
		/* a maximum of what is left.                           */
		switch(mode)
		{
		case XFR_READ:
			if(fnp -> f_flags.f_ddir)
				xfr_cnt = min(to_xfer,
				 secsize - fnp -> f_boff);
			else
				xfr_cnt = min(min(to_xfer,
				 secsize - fnp -> f_boff),
				  fnp -> f_dir.dir_size - fnp -> f_offset);
			fbcopy((BYTE FAR *)&bp -> b_buffer[fnp -> f_boff],
			 buffer,
			  xfr_cnt);
			break;

#ifndef IPL
		case XFR_WRITE:
			xfr_cnt = min(to_xfer, secsize - fnp -> f_boff);
			fbcopy(buffer,
			 (BYTE FAR *)&bp -> b_buffer[fnp -> f_boff],
			  xfr_cnt);
			bp -> b_flag |= BFR_DIRTY;
			break;
#endif

		default:
			*err =  DE_INVLDACC;
			return ret_cnt;
		}

		/* update pointers and counters                         */
		ret_cnt += xfr_cnt;
		to_xfer -= xfr_cnt;
		fnp -> f_offset += xfr_cnt;
		buffer = add_far((VOID FAR *)buffer, (ULONG)xfr_cnt);
		if(mode == XFR_WRITE && (fnp -> f_offset > fnp -> f_highwater))
			fnp -> f_highwater = fnp -> f_offset;
	}
	*err = SUCCESS;
	return ret_cnt;
}

COUNT 
dos_read (COUNT fd, VOID FAR *buffer, UCOUNT count)
{
	COUNT err, xfr;

	xfr = rdwrblock(fd, buffer, count, XFR_READ, &err);
	return err != SUCCESS ? err : xfr;
}


#ifndef IPL
COUNT 
dos_write (COUNT fd, VOID FAR *buffer, UCOUNT count)
{
	REG struct f_node FAR *fnp;
	COUNT err, xfr;

	/* First test if we need to fill to new EOF.			*/

	/* 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)
	{
		return DE_INVLDHNDL;
	}

	/* Future note: for security purposes, this should be set to	*/
	/* blocks of 0.  This satisfies spec and guarantees no secure	*/
	/* info is written to disk.					*/
	/* Also, with real memory management, this may cause a page	*/
	/* fault.							*/
	if(fnp -> f_offset > fnp -> f_highwater)
	{
		ULONG lCount = fnp -> f_offset - fnp -> f_highwater;

		while(lCount > 0)
		{
			rdwrblock(fd, buffer,
				lCount > 512l ? 512 : (UCOUNT)lCount,
				XFR_WRITE, &err);
			lCount -= 512;
		}
	}
	
	xfr = rdwrblock(fd, buffer, count, XFR_WRITE, &err);
	return err != SUCCESS ? err : xfr;
}
#endif


/* Position the file pointer to the desired offset                      */
/* Returns a long current offset or a negative error code               */
LONG 
dos_lseek (COUNT fd, LONG foffset, COUNT origin)
{
	REG 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 (LONG)DE_INVLDHNDL;

	/* now do the actual lseek adjustment to the file poitner       */

	switch(origin)
	{
	/* offset from beginning of file                                */
	case 0:
		return fnp -> f_offset = (ULONG)foffset;

	/* offset from current location                                 */
	case 1:
		return fnp -> f_offset += foffset;

	/* offset from eof						*/
	case 2:
		return fnp -> f_offset = fnp -> f_highwater + foffset;

	/* default to an invalid function                               */
	default:
		return (LONG)DE_INVLDFUNC;
	}
}


UWORD 
dos_free (struct dpb *dpbp)
{
	/* There's an unwritten rule here. All fs       */
	/* cluster start at 2 and run to max_cluster+2  */
	REG UWORD i, cnt = 0;
	UWORD max_cluster = ((ULONG)dpbp -> dpb_size
			    * (ULONG)dpbp -> dpb_clssize - dpbp -> dpb_data + 1)
			    / dpbp -> dpb_clssize + 2; 
	
	if(dpbp -> dpb_nfreeclst != UNKNCLUSTER)
		return dpbp -> dpb_nfreeclst;
	else
	{
		for(i = 2; i < max_cluster; i++)
		{
			if(next_cluster(dpbp, i) == 0)
				++cnt;
		}
		dpbp -> dpb_nfreeclst = cnt;
		return cnt;
	}
}

VOID 
dos_pwd (struct dpb *dpbp, BYTE FAR *s)
{
	fsncopy((BYTE FAR *)&dpbp -> dpb_path[1], s, 64);
}

#ifndef IPL
COUNT 
dos_cd (struct dpb *dpbp, BYTE FAR *s)
{
	BYTE FAR *p;
	struct f_node FAR *fnp;

	/* Get the current directory so that we initialize all access   */
	/* relative to root.                                            */
	truename(s, PriPathName);

	/* now test for its existance. If it doesn't, return an error.  */
	/* If it does, copy the path to the current directory           */
	/* structure.                                                   */
	if((fnp = dir_open((BYTE FAR *)PriPathName)) == NULL)
		return DE_PATHNOTFND;
	else
	{
		dir_close(fnp);
		scopy(&PriPathName[2], dpbp -> dpb_path);
		return SUCCESS;
	}
}
#endif


struct f_node FAR *
get_f_node (void)
{
	REG i;
	
	for(i = 0; i < NFILES; i++)
	{
		if(f_nodes[i].f_count == 0)
		{
			++f_nodes[i].f_count;
			return &f_nodes[i];
		}
	}
	return (struct f_node FAR *)0;
}


VOID 
release_f_node (struct f_node FAR *fnp)
{
	if(fnp -> f_count > 0)
		--fnp -> f_count;
	else
		fnp -> f_count = 0;
}


#ifndef IPL
VOID 
dos_setdta (BYTE FAR *newdta)
{
	dta = newdta;
}


COUNT 
dos_getfattr (BYTE FAR *name, UWORD FAR *attrp)
{
	struct f_node FAR *fnp;
	COUNT fd;

	/* Translate the fd into an fnode pointer, since all internal   */
	/* operations are achieved through fnodes.                      */
	if((fd = dos_open(name, O_RDONLY)) < SUCCESS)
		return DE_FILENOTFND;
	/* note: an invalid fd is indicated by a 0 return               */
	if((fnp = xlt_fd(fd)) == (struct f_node FAR *)0)
		return DE_TOOMANY;

	/* If the fd was invalid because it was out of range or the     */
	/* requested file was not open, tell the caller and exit        */
	if(fnp -> f_count <= 0)
		return DE_FILENOTFND;

	/* Get the attribute from the fnode and return          */
	*attrp = fnp -> f_dir.dir_attrib;
	dos_close(fd);
	return SUCCESS;
}


COUNT 
dos_setfattr (BYTE FAR *name, UWORD FAR *attrp)
{
	struct f_node FAR *fnp;
	COUNT fd;

	/* Translate the fd into an fnode pointer, since all internal   */
	/* operations are achieved through fnodes.                      */
	if((fd = dos_open(name, O_RDONLY)) < SUCCESS)
		return DE_FILENOTFND;
	/* note: an invalid fd is indicated by a 0 return               */
	if((fnp = xlt_fd(fd)) == (struct f_node FAR *)0)
		return DE_TOOMANY;

	/* If the fd was invalid because it was out of range or the     */
	/* requested file was not open, tell the caller and exit        */
	if(fnp -> f_count <= 0)
		return DE_FILENOTFND;

	/* Set the attribute from the fnode and return          */
	fnp -> f_dir.dir_attrib = *attrp;
	fnp -> f_flags.f_dmod = TRUE;
	dos_close(fd);
	return SUCCESS;
}
#endif


COUNT 
media_check (REG struct dpb *dpbp)
{
	bpb FAR *bpbp;
	ULONG   size;
	REG     COUNT i;

	/* First test if anyone has changed the removable media         */
	FOREVER
	{
		MediaReqHdr.r_length = sizeof(request);
		MediaReqHdr.r_unit = dpbp -> dpb_subunit;
		MediaReqHdr.r_command = C_MEDIACHK;
		MediaReqHdr.r_mcmdesc = dpbp -> dpb_mdb;
		MediaReqHdr.r_status = 0;
		execrh((request FAR *)&MediaReqHdr, dpbp -> dpb_device);
		if(!(MediaReqHdr.r_status & S_ERROR) && (MediaReqHdr.r_status & S_DONE))
			break;
		else
		{
		loop1:
			switch(block_error(&MediaReqHdr, dpbp -> dpb_unit))
			{
			case ABORT:
			case FAIL:
				return DE_INVLDDRV;

			case RETRY:
				continue;

			case CONTINUE:
				break;

			default:
				goto loop1;
			}
		}
	}

	switch(MediaReqHdr.r_mcretcode | dpbp -> dpb_flags)
	{
	case M_NOT_CHANGED:
		/* It was definitely not changed, so ignore it          */
		return SUCCESS;

		/* If it is forced or the media may have changed,       */
		/* rebuild the bpb                                      */
	case M_DONT_KNOW:
		flush_buffers(dpbp -> dpb_unit);

		/* If it definitely changed, don't know (falls through) */
		/* or has been changed, rebuild the bpb.                */
	case M_CHANGED:
	default:
		setinvld(dpbp -> dpb_unit);
		FOREVER
		{
			MediaReqHdr.r_length = sizeof(request);
			MediaReqHdr.r_unit = dpbp -> dpb_subunit;
			MediaReqHdr.r_command = C_BLDBPB;
			MediaReqHdr.r_mcmdesc = dpbp -> dpb_mdb;
			MediaReqHdr.r_status = 0;
			execrh((request FAR *)&MediaReqHdr, dpbp -> dpb_device);
			if(!(MediaReqHdr.r_status & S_ERROR) && (MediaReqHdr.r_status & S_DONE))
				break;
			else
			{
			loop2:
				switch(block_error(&MediaReqHdr, dpbp -> dpb_unit))
				{
				case ABORT:
				case FAIL:
					return DE_INVLDDRV;

				case RETRY:
					continue;

				case CONTINUE:
					break;

				default:
					goto loop2;
				}
			}
		}
		bpbp = MediaReqHdr.r_bpptr;
		dpbp -> dpb_mdb = bpbp -> bpb_mdesc;
		dpbp -> dpb_secsize = bpbp -> bpb_nbyte;
		dpbp -> dpb_clssize = bpbp -> bpb_nsector;
		dpbp -> dpb_clsmask = bpbp -> bpb_nsector - 1;
		dpbp -> dpb_fatstrt = bpbp -> bpb_nreserved;
		dpbp -> dpb_fats = bpbp -> bpb_nfat;
		dpbp -> dpb_dirents = bpbp -> bpb_ndirent;
		size =  bpbp -> bpb_nsize == 0 ?
		 bpbp -> bpb_huge :
		 (ULONG)bpbp -> bpb_nsize;
		dpbp -> dpb_size = size / ((ULONG)bpbp -> bpb_nsector);
		dpbp -> dpb_fatsize = bpbp -> bpb_nfsect;
		dpbp -> dpb_dirstrt = dpbp -> dpb_fatstrt
			+ dpbp -> dpb_fats * dpbp -> dpb_fatsize + 1;
		dpbp -> dpb_data = dpbp -> dpb_dirstrt
			+ ((DIRENT_SIZE * dpbp -> dpb_dirents
			+ (dpbp -> dpb_secsize - 1))
			/ dpbp -> dpb_secsize);
		dpbp -> dpb_flags = 0;
		dpbp -> dpb_next = (struct dpb FAR *)-1;
		dpbp -> dpb_cluster = UNKNCLUSTER;
		dpbp -> dpb_nfreeclst = UNKNCLUSTER;
		for(i = 1, dpbp -> dpb_shftcnt = 0;
		 i < (sizeof(dpbp -> dpb_shftcnt) * 8); /* 8 bit bytes in C */
		 dpbp -> dpb_shftcnt++, i <<= 1)
		{
			if(i >= bpbp -> bpb_nsector)
				break;
		}
		return SUCCESS;
	}
}


/* translate the fd into an f_node pointer                              */

struct f_node FAR *
xlt_fd (COUNT fd)
{
	return fd > NFILES ? (struct f_node FAR *)0 : &f_nodes[fd];
}


COUNT 
xlt_fnp (struct f_node FAR *fnp)
{
	return fnp - f_nodes;
}


struct dhdr FAR *
select_unit (COUNT drive)
{
	/* Just get the header from the dhdr array                      */
	return blk_devices[drive].dpb_device;
}

⌨️ 快捷键说明

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