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