📄 fatfs.c
字号:
/* avoid caching trouble */
DeleteBlockInBufferCache(currentblock,
currentblock + sectors_to_xfer - 1,
fnp->f_dpb->dpb_unit, mode);
if (dskxfer(fnp->f_dpb->dpb_unit,
currentblock,
(VOID FAR *) buffer, sectors_to_xfer,
mode == XFR_READ ? DSKREAD : DSKWRITE))
{
fnp->f_offset = startoffset;
save_far_f_node(fnp);
return DE_ACCESS;
}
goto update_pointers;
}
/* normal read: just the old, buffer = sector based read */
normal_xfer:
#ifdef DSK_DEBUG
printf("r/w %d links; dir offset %d, cluster %d, mode %x\n",
fnp->f_count, fnp->f_diroff, fnp->f_cluster, mode);
#endif
/* Get the block we need from cache */
bp = getblock(currentblock
/*clus2phys(fnp->f_cluster, fnp->f_dpb) + fnp->f_sector */
, fnp->f_dpb->dpb_unit);
#ifdef DISPLAY_GETBLOCK
printf("DATA (rwblock)\n");
#endif
if (bp == NULL) /* (struct buffer *)0 --> DS:0 !! */
{
save_far_f_node(fnp);
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. */
xfr_cnt = min(to_xfer, secsize - boff);
if (!(fnp->f_flags & F_DDIR) && mode == XFR_READ)
xfr_cnt = (UWORD) min(xfr_cnt, fnp->f_dir.dir_size - fnp->f_offset);
/* 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. */
if (mode == XFR_WRITE)
{
fmemcpy(&bp->b_buffer[boff], buffer, xfr_cnt);
bp->b_flag |= BFR_DIRTY | BFR_VALID;
}
else
{
fmemcpy(buffer, &bp->b_buffer[boff], xfr_cnt);
}
/* complete buffer transferred ?
probably not reused later
*/
if (xfr_cnt == sizeof(bp->b_buffer) ||
(mode == XFR_READ && fnp->f_offset + xfr_cnt == fnp->f_dir.dir_size))
{
bp->b_flag |= BFR_UNCACHE;
}
/* update pointers and counters */
fnp->f_offset += xfr_cnt;
update_pointers:
ret_cnt += xfr_cnt;
to_xfer -= xfr_cnt;
buffer = adjust_far((char FAR *)buffer + xfr_cnt);
if (mode == XFR_WRITE)
{
if (fnp->f_offset > fnp->f_dir.dir_size)
{
fnp->f_dir.dir_size = fnp->f_offset;
}
merge_file_changes(fnp, FALSE); /* /// Added - Ron Cemer */
}
}
save_far_f_node(fnp);
return ret_cnt;
}
/* 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 f_node_ptr 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 == (f_node_ptr) 0)
return (LONG) DE_INVLDHNDL;
/* now do the actual lseek adjustment to the file poitner */
switch (origin)
{
/* offset from beginning of file */
case 0:
fnp->f_offset = (ULONG) foffset;
break;
/* offset from current location */
case 1:
fnp->f_offset += foffset;
break;
/* offset from eof */
case 2:
fnp->f_offset = fnp->f_dir.dir_size + foffset;
break;
/* default to an invalid function */
default:
release_near_f_node(fnp);
return (LONG) DE_INVLDFUNC;
}
save_far_f_node(fnp);
return fnp->f_offset;
}
/* returns the number of unused clusters */
CLUSTER dos_free(struct dpb FAR * dpbp)
{
/* There's an unwritten rule here. All fs */
/* cluster start at 2 and run to max_cluster+2 */
REG CLUSTER i;
REG CLUSTER cnt = 0;
CLUSTER max_cluster = dpbp->dpb_size;
#ifdef WITHFAT32
if (ISFAT32(dpbp))
{
if (dpbp->dpb_xnfreeclst != XUNKNCLSTFREE)
return dpbp->dpb_xnfreeclst;
max_cluster = dpbp->dpb_xsize;
}
else
#endif
if (dpbp->dpb_nfreeclst != UNKNCLSTFREE)
return dpbp->dpb_nfreeclst;
for (i = 2; i <= max_cluster; i++)
{
if (next_cluster(dpbp, i) == 0)
++cnt;
}
#ifdef WITHFAT32
if (ISFAT32(dpbp))
{
dpbp->dpb_xnfreeclst = cnt;
write_fsinfo(dpbp);
return cnt;
}
#endif
dpbp->dpb_nfreeclst = (UWORD)cnt;
return cnt;
}
#ifndef IPL
int dos_cd(char * PathName)
{
f_node_ptr fnp;
struct cds FAR *cdsp = get_cds(PathName[0] - 'A');
if ((media_check(cdsp->cdsDpb) < 0))
return DE_INVLDDRV;
/* now test for its existance. If it doesn't, return an error. */
if ((fnp = dir_open(PathName)) == NULL)
return DE_PATHNOTFND;
/* problem: RBIL table 01643 does not give a FAT32 field for the
CDS start cluster. But we are not using this field ourselves */
cdsp->cdsStrtClst = (UWORD)fnp->f_dirstart;
dir_close(fnp);
return SUCCESS;
}
#endif
/* try to allocate a near f_node */
/* (there are just two of them, in the SDA) */
f_node_ptr get_near_f_node(void)
{
f_node_ptr fnp = fnode;
if (fnp->f_count == 0)
fnp->f_count++;
else
{
fnp++;
if (fnp->f_count == 0)
fnp->f_count++;
else
{
fnp = (f_node_ptr) 0;
panic("more than two near fnodes requested at the same time!\n");
}
}
return fnp;
}
/* Try to allocate an f_node from the available files array */
f_node_ptr get_f_node(void)
{
REG int i;
f_node_ptr fnp = get_near_f_node();
if (fnp != (f_node_ptr)0)
{
for (i = 0; i < f_nodes_cnt; i++)
{
if (f_nodes[i].f_count == 0)
{
++f_nodes[i].f_count;
fnode_fd[fnp - fnode] = i;
return fnp;
}
}
release_near_f_node(fnp);
}
return (f_node_ptr) 0;
}
VOID release_f_node(f_node_ptr fnp)
{
struct f_node FAR *fp = &f_nodes[xlt_fnp(fnp)];
if (fp->f_count > 0)
--fp->f_count;
else
fp->f_count = 0;
release_near_f_node(fnp);
}
#ifndef IPL
COUNT dos_getfattr_fd(COUNT fd)
{
f_node_ptr 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 == (f_node_ptr) 0)
return DE_TOOMANY;
release_near_f_node(fnp);
return fnp->f_dir.dir_attrib;
}
COUNT dos_getfattr(BYTE * name)
{
COUNT result, fd;
fd = (short)dos_open(name, O_RDONLY | O_OPEN, 0);
if (fd < SUCCESS)
return fd;
result = dos_getfattr_fd(fd);
dos_close(fd);
return result;
}
COUNT dos_setfattr(BYTE * name, UWORD attrp)
{
COUNT fd;
f_node_ptr fnp;
/* JPP-If user tries to set VOLID or DIR bits, return error */
if ((attrp & (D_VOLID | D_DIR | 0xC0)) != 0)
return DE_ACCESS;
fd = (short)dos_open(name, O_RDONLY | O_OPEN, 0);
if (fd < SUCCESS)
return fd;
fnp = xlt_fd(fd);
/* Set the attribute from the fnode and return */
/* clear all attributes but DIR and VOLID */
fnp->f_dir.dir_attrib &= (D_VOLID | D_DIR); /* JPP */
/* set attributes that user requested */
fnp->f_dir.dir_attrib |= attrp; /* JPP */
fnp->f_flags |= F_DMOD | F_DDATE;
save_far_f_node(fnp);
dos_close(fd);
return SUCCESS;
}
#endif
#ifdef WITHFAT32
VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp, BOOL extended)
#else
VOID bpb_to_dpb(bpb FAR * bpbp, REG struct dpb FAR * dpbp)
#endif
{
ULONG size;
REG UWORD shftcnt;
bpb sbpb;
fmemcpy(&sbpb, bpbp, sizeof(sbpb));
for (shftcnt = 0; (sbpb.bpb_nsector >> shftcnt) > 1; shftcnt++)
;
dpbp->dpb_shftcnt = shftcnt;
dpbp->dpb_mdb = sbpb.bpb_mdesc;
dpbp->dpb_secsize = sbpb.bpb_nbyte;
dpbp->dpb_clsmask = sbpb.bpb_nsector - 1;
dpbp->dpb_fatstrt = sbpb.bpb_nreserved;
dpbp->dpb_fats = sbpb.bpb_nfat;
dpbp->dpb_dirents = sbpb.bpb_ndirent;
size = sbpb.bpb_nsize == 0 ? sbpb.bpb_huge : (ULONG) sbpb.bpb_nsize;
dpbp->dpb_fatsize = sbpb.bpb_nfsect;
dpbp->dpb_dirstrt = dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_fatsize;
dpbp->dpb_data = dpbp->dpb_dirstrt
+ (dpbp->dpb_dirents + dpbp->dpb_secsize/DIRENT_SIZE - 1) /
(dpbp->dpb_secsize/DIRENT_SIZE);
dpbp->dpb_size = (UWORD)((size - dpbp->dpb_data) >> shftcnt) + 1;
{ /* Make sure the number of FAT sectors is actually enough to hold that */
/* many clusters. Otherwise back the number of clusters down (LG & AB) */
unsigned fatsiz;
ULONG tmp = dpbp->dpb_fatsize * (ULONG)(dpbp->dpb_secsize / 2);/* entries/2 */
if (tmp >= 0x10000UL)
goto ckok;
fatsiz = (unsigned) tmp;
if (dpbp->dpb_size > FAT_MAGIC) {/* FAT16 */
if (fatsiz <= FAT_MAGIC) /* FAT12 - let it pass through rather */
goto ckok; /* than lose data correcting FAT type */
} else { /* FAT12 */
if (fatsiz >= 0x4000)
goto ckok;
fatsiz = fatsiz * 4 / 3;
}
if (dpbp->dpb_size >= fatsiz) /* FAT too short */
dpbp->dpb_size = fatsiz - 1; /* - 2 reserved entries + 1 */
ckok:;
}
dpbp->dpb_flags = 0;
dpbp->dpb_cluster = UNKNCLUSTER;
/* number of free clusters */
dpbp->dpb_nfreeclst = UNKNCLSTFREE;
#ifdef WITHFAT32
if (extended)
{
dpbp->dpb_xfatsize = sbpb.bpb_nfsect == 0 ? sbpb.bpb_xnfsect
: sbpb.bpb_nfsect;
dpbp->dpb_xcluster = UNKNCLUSTER;
dpbp->dpb_xnfreeclst = XUNKNCLSTFREE; /* number of free clusters */
dpbp->dpb_xflags = 0;
dpbp->dpb_xfsinfosec = 0xffff;
dpbp->dpb_xbackupsec = 0xffff;
dpbp->dpb_xrootclst = 0;
dpbp->dpb_xdata = dpbp->dpb_data;
dpbp->dpb_xsize = dpbp->dpb_size;
if (ISFAT32(dpbp))
{
dpbp->dpb_xflags = sbpb.bpb_xflags;
dpbp->dpb_xfsinfosec = sbpb.bpb_xfsinfosec;
dpbp->dpb_xbackupsec = sbpb.bpb_xbackupsec;
dpbp->dpb_dirents = 0;
dpbp->dpb_dirstrt = 0xffff;
dpbp->dpb_size = 0;
dpbp->dpb_xdata =
dpbp->dpb_fatstrt + dpbp->dpb_fats * dpbp->dpb_xfatsize;
dpbp->dpb_xsize = ((size - dpbp->dpb_xdata) >> shftcnt) + 1;
dpbp->dpb_xrootclst = sbpb.bpb_xrootclst;
read_fsinfo(dpbp);
}
}
#endif
}
STATIC int rqblockio(unsigned char command, struct dpb FAR * dpbp)
{
retry:
MediaReqHdr.r_length = sizeof(request);
MediaReqHdr.r_unit = dpbp->dpb_subunit;
MediaReqHdr.r_command = command;
MediaReqHdr.r_mcmdesc = dpbp->dpb_mdb;
MediaReqHdr.r_status = 0;
if (command == C_BLDBPB) /* help USBASPI.SYS & DI1000DD.SYS (TE) */
MediaReqHdr.r_bpfat = (boot FAR *)DiskTransferBuffer;
execrh((request FAR *) & MediaReqHdr, dpbp->dpb_device);
if ((MediaReqHdr.r_status & S_ERROR) || !(MediaReqHdr.r_status & S_DONE))
{
FOREVER
{
switch (block_error(&MediaReqHdr, dpbp->dpb_unit, dpbp->dpb_device, 0))
{
case ABORT:
case FAIL:
return DE_INVLDDRV;
case RETRY:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -