📄 fatfs.c
字号:
while (TRUE)
{
if (fnp->f_diroff == 0)
break;
fnp->f_diroff--;
if (dir_read(fnp) <= 0) {
dir_close(fnp);
return DE_BLKINVLD;
}
if (fnp->f_dir.dir_attrib != D_LFN)
break;
fnp->f_dir.dir_name[0] = DELETED;
fnp->f_flags |= F_DMOD;
if (!dir_write(fnp)) return DE_BLKINVLD;
}
fnp->f_diroff = original_diroff;
if (dir_read(fnp) <= 0) {
dir_close(fnp);
return DE_BLKINVLD;
}
return SUCCESS;
}
/* /// Added - Ron Cemer */
/* If more than one f_node has a file open, and a write
occurs, this function must be called to propagate the
results of that write to the other f_nodes which have
that file open. Note that this function only has an
effect if SHARE is installed. This is for compatibility
reasons, since DOS without SHARE does not share changes
between two or more open instances of the same file
unless these instances were generated by dup() or dup2(). */
STATIC void merge_file_changes(f_node_ptr fnp, int collect)
{
f_node_ptr fnp2;
int i, fd;
if (!IsShareInstalled())
return;
fd = xlt_fnp(fnp);
fnp2 = get_near_f_node();
for (i = 0; i < f_nodes_cnt; i++)
{
fmemcpy(fnp2, &f_nodes[i], sizeof(*fnp2));
if ((fnp != (f_node_ptr) 0)
&& (i != fd)
&& (fnp->f_count > 0) && (is_same_file(fnp, fnp2)))
{
if (collect)
{
/* We're collecting file changes from any other
f_node which refers to this file. */
if (fnp2->f_mode != RDONLY)
{
copy_file_changes(fnp2, fnp);
break;
}
}
else
{
/* We just made changes to this file, so we are
distributing these changes to the other f_nodes
which refer to this file. */
copy_file_changes(fnp, fnp2);
fmemcpy(&f_nodes[i], fnp2, sizeof(*fnp2));
}
}
}
release_near_f_node(fnp2);
}
/* /// Added - Ron Cemer */
STATIC int is_same_file(f_node_ptr fnp1, f_node_ptr fnp2)
{
return
(fnp1->f_dpb->dpb_unit == fnp2->f_dpb->dpb_unit)
&& (fnp1->f_dpb->dpb_subunit == fnp2->f_dpb->dpb_subunit)
&& (fcbmatch(fnp1->f_dir.dir_name, fnp2->f_dir.dir_name))
&& ((fnp1->f_dir.dir_attrib & D_VOLID) == 0)
&& ((fnp2->f_dir.dir_attrib & D_VOLID) == 0)
&& (fnp1->f_diroff == fnp2->f_diroff)
&& (fnp1->f_dirstart == fnp2->f_dirstart)
&& (fnp1->f_dpb == fnp2->f_dpb);
}
/* /// Added - Ron Cemer */
STATIC void copy_file_changes(f_node_ptr src, f_node_ptr dst)
{
dst->f_dir.dir_start = src->f_dir.dir_start;
#ifdef WITHFAT32
dst->f_dir.dir_start_high = src->f_dir.dir_start_high;
#endif
dst->f_dir.dir_size = src->f_dir.dir_size;
dst->f_dir.dir_date = src->f_dir.dir_date;
dst->f_dir.dir_time = src->f_dir.dir_time;
}
STATIC COUNT delete_dir_entry(f_node_ptr fnp)
{
COUNT rc;
/* Ok, so we can delete. Start out by */
/* clobbering all FAT entries for this file */
/* (or, in English, truncate the FAT). */
if ((rc = remove_lfn_entries(fnp)) < 0)
return rc;
wipe_out(fnp);
*(fnp->f_dir.dir_name) = DELETED;
/* The directory has been modified, so set the */
/* bit before closing it, allowing it to be */
/* updated */
fnp->f_flags |= F_DMOD;
dir_close(fnp);
/* SUCCESSful completion, return it */
return SUCCESS;
}
COUNT dos_delete(BYTE * path, int attrib)
{
REG f_node_ptr fnp;
char fcbname[FNAME_SIZE + FEXT_SIZE];
/* first split the passed dir into components (i.e. - */
/* path to new directory and name of new directory */
if ((fnp = split_path(path, fcbname)) == NULL)
{
return DE_PATHNOTFND;
}
/* Check that we don't have a duplicate name, so if we */
/* find one, it's an error. */
if (find_fname(fnp, fcbname, attrib))
{
/* Do not delete directories or r/o files */
/* lfn entries and volume labels are only found */
/* by find_fname() if attrib is set to a */
/* special value */
if (fnp->f_dir.dir_attrib & (D_RDONLY | D_DIR))
{
dir_close(fnp);
return DE_ACCESS;
}
return delete_dir_entry(fnp);
}
else
{
/* No such file, return the error */
dir_close(fnp);
return DE_FILENOTFND;
}
}
COUNT dos_rmdir(BYTE * path)
{
REG f_node_ptr fnp;
REG f_node_ptr fnp1;
BOOL found;
char fcbname[FNAME_SIZE + FEXT_SIZE];
/* first split the passed dir into comopnents (i.e. - */
/* path to new directory and name of new directory */
if ((fnp = split_path(path, fcbname)) == NULL)
{
return DE_PATHNOTFND;
}
/* Check that we're not trying to remove the root! */
if ((path[0] == '\\') && (path[1] == NULL))
{
dir_close(fnp);
return DE_ACCESS;
}
/* Check that we don't have a duplicate name, so if we */
/* find one, it's an error. */
if (find_fname(fnp, fcbname, D_ALL))
{
/* The only permissable attribute is directory, */
/* check for any other bit set. If it is, give */
/* an access error. */
/* if (fnp->f_dir.dir_attrib & ~D_DIR) */
/* directories may have attributes, too. at least my WinNT disk
has many 'archive' directories
we still don't allow RDONLY directories to be deleted TE */
/* if (fnp->f_dir.dir_attrib & ~(D_DIR |D_HIDDEN|D_ARCHIVE|D_SYSTEM))
{
dir_close(fnp);
return DE_ACCESS;
} */
/* Check that the directory is empty. Only the */
/* "." and ".." are permissable. */
fnp->f_flags &= ~F_DMOD;
fnp1 = dir_open(path);
if (fnp1 == NULL)
{
dir_close(fnp);
return DE_ACCESS;
}
dir_read(fnp1);
if (fnp1->f_dir.dir_name[0] != '.')
{
dir_close(fnp);
return DE_ACCESS;
}
fnp1->f_diroff++;
dir_read(fnp1);
if (fnp1->f_dir.dir_name[0] != '.')
{
dir_close(fnp);
return DE_ACCESS;
}
/* Now search through the directory and make certain */
/* that there are no entries. */
found = FALSE;
fnp1->f_diroff++;
while (dir_read(fnp1) == 1)
{
if (fnp1->f_dir.dir_name[0] == '\0')
break;
if (fnp1->f_dir.dir_name[0] != DELETED
&& fnp1->f_dir.dir_attrib != D_LFN)
{
found = TRUE;
break;
}
fnp1->f_diroff++;
}
dir_close(fnp1);
/* If anything was found, exit with an error. */
if (found)
{
dir_close(fnp);
return DE_ACCESS;
}
return delete_dir_entry(fnp);
}
else
{
/* No such file, return the error */
dir_close(fnp);
return DE_FILENOTFND;
}
}
COUNT dos_rename(BYTE * path1, BYTE * path2, int attrib)
{
REG f_node_ptr fnp1;
REG f_node_ptr fnp2;
COUNT ret;
char fcbname[FNAME_SIZE + FEXT_SIZE];
/* first split the passed target into compnents (i.e. - path to */
/* new file name and name of new file name */
if ((fnp2 = split_path(path2, fcbname)) == NULL)
{
return DE_PATHNOTFND;
}
/* Check that we don't have a duplicate name, so if we find */
/* one, it's an error. */
if (find_fname(fnp2, fcbname, attrib))
{
dir_close(fnp2);
return DE_ACCESS;
}
/* next split the passed source into compnents (i.e. - path to */
/* old file name and name of old file name */
if ((fnp1 = split_path(path1, fcbname)) == NULL)
{
dir_close(fnp2);
return DE_PATHNOTFND;
}
if (!find_fname(fnp1, fcbname, attrib))
{
/* No such file, return the error */
dir_close(fnp1);
dir_close(fnp2);
return DE_FILENOTFND;
}
ret = alloc_find_free(fnp2, path2, fcbname);
if (ret != SUCCESS) {
dir_close(fnp1);
return ret;
}
if ((ret = remove_lfn_entries(fnp1)) < 0)
return ret;
/* put the fnode's name into the directory. */
memcpy(fnp2->f_dir.dir_name, fcbname, FNAME_SIZE + FEXT_SIZE);
/* Set the fnode to the desired mode */
fnp2->f_dir.dir_size = fnp1->f_dir.dir_size;
fnp2->f_dir.dir_start = fnp1->f_dir.dir_start;
#ifdef WITHFAT32
fnp2->f_dir.dir_start_high = fnp1->f_dir.dir_start_high;
#endif
fnp2->f_dir.dir_attrib = fnp1->f_dir.dir_attrib;
fnp2->f_dir.dir_time = fnp1->f_dir.dir_time;
fnp2->f_dir.dir_date = fnp1->f_dir.dir_date;
/* The directory has been modified, so set the bit before */
/* closing it, allowing it to be updated. */
fnp1->f_flags = fnp2->f_flags = F_DMOD | F_DDIR;
/* Ok, so we can delete this one. Save the file info. */
*(fnp1->f_dir.dir_name) = DELETED;
dir_close(fnp1);
dir_close(fnp2);
/* SUCCESSful completion, return it */
return SUCCESS;
}
/* */
/* wipe out all FAT entries starting from st for create, delete, etc. */
/* */
STATIC VOID wipe_out_clusters(struct dpb FAR * dpbp, CLUSTER st)
{
REG CLUSTER next;
/* Loop from start until either a FREE entry is */
/* encountered (due to a fractured file system) of the */
/* last cluster is encountered. */
while (st != LONG_LAST_CLUSTER)
{
/* get the next cluster pointed to */
next = next_cluster(dpbp, st);
/* just exit if a damaged file system exists */
if (next == FREE || next == 1)
return;
/* zap the FAT pointed to */
link_fat(dpbp, st, FREE);
/* and the start of free space pointer */
#ifdef WITHFAT32
if (ISFAT32(dpbp))
{
if ((dpbp->dpb_xcluster == UNKNCLUSTER) || (dpbp->dpb_xcluster > st))
dpbp->dpb_xcluster = st;
}
else
#endif
if ((dpbp->dpb_cluster == UNKNCLUSTER) || (dpbp->dpb_cluster > st))
dpbp->dpb_cluster = (UWORD)st;
/* and just follow the linked list */
st = next;
}
#ifdef WITHFAT32
if (ISFAT32(dpbp))
write_fsinfo(dpbp);
#endif
}
/* */
/* wipe out all FAT entries for create, delete, etc. */
/* */
STATIC VOID wipe_out(f_node_ptr fnp)
{
/* if already free or not valid file, just exit */
if ((fnp == NULL) || checkdstart(fnp->f_dpb, &fnp->f_dir, FREE))
return;
wipe_out_clusters(fnp->f_dpb, getdstart(fnp->f_dpb, &fnp->f_dir));
}
STATIC BOOL find_free(f_node_ptr fnp)
{
COUNT rc;
while ((rc = dir_read(fnp)) == 1)
{
if (fnp->f_dir.dir_name[0] == DELETED)
return TRUE;
fnp->f_diroff++;
}
return rc >= 0;
}
/* alloc_find_free: resets the directory by a close followed by */
/* an open. Then finds a spare directory entry and if not */
/* available, tries to extend the directory. */
STATIC int alloc_find_free(f_node_ptr fnp, char *path, char *fcbname)
{
fnp->f_flags &= ~F_DMOD;
dir_close(fnp);
fnp = split_path(path, fcbname);
/* 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 (find_free(fnp) == 0)
{
if (fnp->f_dirstart == 0)
{
fnp->f_flags &= ~F_DMOD;
dir_close(fnp);
return DE_TOOMANY;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -