📄 fatfs.c
字号:
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 + -