📄 fat.c
字号:
/**
* @file $RCSfile: fat.c,v $
*
* Copyright (c) 2006 XXXXX INC., All Rights Reserved
*
* @author YongJian Guo <XXX@XXX>
*
* @version $Revision: 1.2.0.00 $
* @date $Date: 2006/10/13 06:46:18 $
* @update $Date: 2007/01/24 14:06:17 $
* $Header: $
**/
#include "sdshare.h"
#include <string.h>
#include "fat.h" /* FatFs declarations */
#include "diskio.h" /* Include file for user provided disk functions */
FATFS *FatFs; /* Pointer to the file system object */
static uint32 FatDateTime;
/*-------------------------------------------------------------------------
Module Private Functions
-------------------------------------------------------------------------*/
void set_fattime(uint32 dt)
{
FatDateTime = dt;
}
uint32 get_fattime(void)
{
return FatDateTime;
}
/*----------------------*/
/* Change Window Offset */
static BOOL move_window (
uint32 sector /* Sector number to make apperance in the FatFs->win */
) /* Move to zero only writes back dirty window */
{
uint32 wsect;
FATFS *fs = FatFs;
wsect = fs->winsect;
if (wsect != sector) { /* Changed current window */
uint8 n;
if (fs->winflag) { /* Write back dirty window if needed */
if (disk_write(fs->win, wsect, 1) != RES_OK) return FALSE;
fs->winflag = 0;
if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */
for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to all FAT copies */
wsect += fs->sects_fat;
if (disk_write(fs->win, wsect, 1) != RES_OK) break;
}
}
}
if (sector) {
if (disk_read(fs->win, sector, 1) != RES_OK) return FALSE;
fs->winsect = sector;
}
}
return TRUE;
}
/*----------------------*/
/* Get a Cluster Status */
static uint32 get_cluster (
uint32 clust /* Cluster# to get the link information */
)
{
uint16 wc, bc;
uint32 fatsect;
FATFS *fs = FatFs;
if ((clust >= 2) && (clust < fs->max_clust)) { /* Valid cluster# */
fatsect = fs->fatbase;
switch (fs->fs_type) {
case FS_FAT12 :
bc = (uint16)clust * 3 / 2;
if (!move_window(fatsect + bc / 512)) break;
wc = fs->win[bc % 512]; bc++;
if (!move_window(fatsect + bc / 512)) break;
wc |= (uint16)fs->win[bc % 512] << 8;
return (clust & 1) ? (wc >> 4) : (wc & 0xFFF);
case FS_FAT16 :
if (!move_window(fatsect + clust / 256)) break;
return LDF_WORD(&(fs->win[((uint16)clust * 2) % 512]));
case FS_FAT32 :
if (!move_window(fatsect + clust / 128)) break;
return LDF_DWORD(&(fs->win[((uint16)clust * 4) % 512])) & 0x0FFFFFFF;
}
}
return 1; /* There is no cluster information, or an error occured */
}
/*--------------------------*/
/* Change a Cluster Status */
static BOOL put_cluster (
uint32 clust, /* Cluster# to change */
uint32 val /* New value to mark the cluster */
)
{
uint16 bc;
uint8 *p;
uint32 fatsect;
FATFS *fs = FatFs;
fatsect = fs->fatbase;
switch (fs->fs_type) {
case FS_FAT12 :
bc = (uint16)clust * 3 / 2;
if (!move_window(fatsect + bc / 512)) return FALSE;
p = &fs->win[bc % 512];
*p = (clust & 1) ? ((*p & 0x0F) | ((uint8)val << 4)) : (uint8)val;
bc++;
fs->winflag = 1;
if (!move_window(fatsect + bc / 512)) return FALSE;
p = &fs->win[bc % 512];
*p = (clust & 1) ? (uint8)(val >> 4) : ((*p & 0xF0) | ((uint8)(val >> 8) & 0x0F));
break;
case FS_FAT16 :
if (!move_window(fatsect + clust / 256)) return FALSE;
ST_WORD(&(fs->win[((uint16)clust * 2) % 512]), (uint16)val);
break;
case FS_FAT32 :
if (!move_window(fatsect + clust / 128)) return FALSE;
ST_DWORD(&(fs->win[((uint16)clust * 4) % 512]), val);
break;
default :
return FALSE;
}
fs->winflag = 1;
return TRUE;
}
/*------------------------*/
/* Remove a Cluster Chain */
static BOOL remove_chain (
uint32 clust /* Cluster# to remove chain from */
)
{
uint32 nxt;
if (clust) {
while ((nxt = get_cluster(clust)) >= 2) {
if (!put_cluster(clust, 0)) return FALSE;
clust = nxt;
}
}
return TRUE;
}
/*-----------------------------------*/
/* Stretch or Create a Cluster Chain */
static uint32 create_chain (
uint32 clust /* Cluster# to stretch, 0 means create new */
)
{
uint32 cstat, ncl, scl, mcl;
FATFS *fs = FatFs;
mcl = fs->max_clust;
if (clust == 0) { /* Create new chain */
scl = fs->last_clust; /* Get last allocated cluster */
if (scl < 2 || scl >= mcl) scl = 1;
}
else { /* Stretch existing chain */
cstat = get_cluster(clust); /* Check the cluster status */
if (cstat < 2) return 0; /* It is an invalid cluster */
if (cstat < mcl) return cstat; /* It is already followed by next cluster */
scl = clust;
}
ncl = scl; /* Scan start cluster */
do {
ncl++; /* Next cluster */
if (ncl >= mcl) { /* Wrap around */
ncl = 2;
if (scl == 1) return 0; /* No free custer was found */
}
if (ncl == scl) return 0; /* No free custer was found */
cstat = get_cluster(ncl); /* Get the cluster status */
if (cstat == 1) return 0; /* Any error occured */
} while (cstat); /* Repeat until find a free cluster */
if (!put_cluster(ncl, 0x0FFFFFFF)) return 0; /* Mark the new cluster "in use" */
if (clust && !put_cluster(clust, ncl)) return 0; /* Link it to previous one if needed */
fs->last_clust = ncl;
return ncl; /* Return new cluster number */
}
/*----------------------------*/
/* Get Sector# from Cluster# */
static uint32 clust2sect (
uint32 clust /* Cluster# to be converted */
)
{
FATFS *fs = FatFs;
clust -= 2;
if (clust >= fs->max_clust) return 0; /* Invalid cluster# */
return clust * fs->sects_clust + fs->database;
}
/*------------------------*/
/* Check File System Type */
static uint8 check_fs (
uint32 sect /* Sector# to check if it is a FAT boot record or not */
)
{
static const sint8 fatsign[] = "FAT12FAT16FAT32";
FATFS *fs = FatFs;
/* Determines FAT type by signature string but this is not correct.
For further information, refer to fatgen103.doc from Microsoft. */
memset(fs->win, 0, 512);
if (disk_read(fs->win, sect, 1) == RES_OK) { /* Load boot record */
if (LDF_WORD(&(fs->win[510])) == 0xAA55) { /* Is it valid? */
if (!memcmp(&(fs->win[0x36]), &fatsign[0], 5))
return FS_FAT12;
if (!memcmp(&(fs->win[0x36]), &fatsign[5], 5))
return FS_FAT16;
if (!memcmp(&(fs->win[0x52]), &fatsign[10], 5) && (fs->win[0x28] == 0))
return FS_FAT32;
}
}
return 0;
}
/*--------------------------------*/
/* Move Directory Pointer to Next */
static BOOL next_dir_entry (
DIR *scan /* Pointer to directory object */
)
{
uint32 clust;
uint16 idx;
FATFS *fs = FatFs;
idx = scan->index + 1;
if ((idx & 15) == 0) { /* Table sector changed? */
scan->sect++; /* Next sector */
if (!scan->clust) { /* In static table */
if (idx >= fs->n_rootdir) return FALSE; /* Reached to end of table */
} else { /* In dynamic table */
if (((idx / 16) & (fs->sects_clust - 1)) == 0) { /* Cluster changed? */
clust = get_cluster(scan->clust); /* Get next cluster */
if ((clust >= fs->max_clust) || (clust < 2)) /* Reached to end of table */
return FALSE;
scan->clust = clust; /* Initialize for new cluster */
scan->sect = clust2sect(clust);
}
}
}
scan->index = idx; /* Lower 4 bit of scan->index indicates offset in scan->sect */
return TRUE;
}
/*--------------------------------------*/
/* Get File Status from Directory Entry */
#if _FS_MINIMIZE <= 1
static void get_fileinfo (
FILINFO *finfo, /* Ptr to store the file information */
const uint8 *dir /* Ptr to the directory entry */
)
{
uint8 n, c, a;
sint8 *p;
p = &(finfo->fname[0]);
a = *(dir+12); /* NT flag */
for (n = 0; n < 8; n++) { /* Convert file name (body) */
c = *(dir+n);
if (c == ' ') break;
if (c == 0x05) c = 0xE5;
if ((a & 0x08) && (c >= 'A') && (c <= 'Z')) c += 0x20;
*p++ = c;
}
if (*(dir+8) != ' ') { /* Convert file name (extension) */
*p++ = '.';
for (n = 8; n < 11; n++) {
c = *(dir+n);
if (c == ' ') break;
if ((a & 0x10) && (c >= 'A') && (c <= 'Z')) c += 0x20;
*p++ = c;
}
}
*p = '\0';
finfo->fattrib = *(dir+11); /* Attribute */
finfo->fsize = LDF_DWORD(dir+28); /* Size */
finfo->fdate = LDF_WORD(dir+24); /* Date */
finfo->ftime = LDF_WORD(dir+22); /* Time */
}
#endif /* _FS_MINIMIZE <= 1 */
/*-------------------------------------------------------------------*/
/* Pick a Paragraph and Create the Name in Format of Directory Entry */
static sint8 make_dirfile (
const sint8 **path, /* Pointer to the file path pointer */
sint8 *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */
)
{
uint8 n, t, c, a, b;
memset(dirname, ' ', 8+3); /* Fill buffer with spaces */
a = 0; b = 0x18; /* NT flag */
n = 0; t = 8;
for (;;) {
c = *(*path)++;
if (c <= ' ') c = 0;
if ((c == 0) || (c == '/')) { /* Reached to end of str or directory separator */
if (n == 0) break;
dirname[11] = a & b; return c;
}
if (c == '.') {
if(!(a & 1) && (n >= 1) && (n <= 8)) { /* Enter extension part */
n = 8; t = 11; continue;
}
break;
}
#ifdef _USE_SJIS
if (((c >= 0x81) && (c <= 0x9F)) || /* Accept S-JIS code */
((c >= 0xE0) && (c <= 0xFC))) {
if ((n == 0) && (c == 0xE5)) /* Change heading \xE5 to \x05 */
c = 0x05;
a ^= 1; goto md_l2;
}
if ((c >= 0x7F) && (c <= 0x80)) break; /* Reject \x7F \x80 */
#else
if (c >= 0x7F) goto md_l1; /* Accept \x7F-0xFF */
#endif
if (c == '"') break; /* Reject " */
if (c <= ')') goto md_l1; /* Accept ! # $ % & ' ( ) */
if (c <= ',') break; /* Reject * + , */
if (c <= '9') goto md_l1; /* Accept - 0-9 */
if (c <= '?') break; /* Reject : ; < = > ? */
if (!(a & 1)) { /* These checks are not applied to S-JIS 2nd byte */
if (c == '|') break; /* Reject | */
if ((c >= '[') && (c <= ']')) break;/* Reject [ \ ] */
if ((c >= 'A') && (c <= 'Z'))
(t == 8) ? (b &= ~0x08) : (b &= ~0x10);
if ((c >= 'a') && (c <= 'z')) { /* Convert to upper case */
c -= 0x20;
(t == 8) ? (a |= 0x08) : (a |= 0x10);
}
}
md_l1:
a &= ~1;
md_l2:
if (n >= t) break;
dirname[n++] = c;
}
return 1;
}
/*-------------------*/
/* Trace a File Path */
static uint16 trace_path (
DIR *scan, /* Pointer to directory object to return last directory */
sint8 *fn, /* Pointer to last segment name to return */
const sint8 *path, /* Full-path string to trace a file or directory */
uint8 **dir /* Directory pointer in Win[] to retutn */
)
{
uint32 clust;
sint8 ds;
uint8 *dptr = NULL;
FATFS *fs = FatFs;
/* Initialize directory object */
clust = fs->dirbase;
if (fs->fs_type == FS_FAT32) {
scan->clust = scan->sclust = clust;
scan->sect = clust2sect(clust);
} else {
scan->clust = scan->sclust = 0;
scan->sect = clust;
}
scan->index = 0;
while ((*path == ' ') || (*path == '/')) path++; /* Skip leading spaces */
if ((uint8)*path < ' ') { /* Null path means the root directory */
*dir = NULL; return FR_OK;
}
for (;;) {
ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */
if (ds == 1) return FR_INVALID_NAME;
for (;;) {
if (!move_window(scan->sect)) return FR_RW_ERROR;
dptr = &(fs->win[(scan->index & 15) * 32]); /* Pointer to the directory entry */
if (*dptr == 0) /* Has it reached to end of dir? */
return !ds ? FR_NO_FILE : FR_NO_PATH;
if ( (*dptr != 0xE5) /* Matched? */
&& !(*(dptr+11) & AM_VOL)
&& !memcmp(dptr, fn, 8+3) ) break;
if (!next_dir_entry(scan)) /* Next directory pointer */
return !ds ? FR_NO_FILE : FR_NO_PATH;
}
if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */
if (!(*(dptr+11) & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */
clust = ((uint32)LDF_WORD(dptr+20) << 16) | LDF_WORD(dptr+26); /* Get cluster# of the directory */
scan->clust = scan->sclust = clust; /* Restart scan with the new directory */
scan->sect = clust2sect(clust);
scan->index = 0;
}
}
/*---------------------------*/
/* Reserve a Directory Entry */
static uint8* reserve_direntry (
DIR *scan /* Target directory to create new entry */
)
{
uint32 clust, sector;
uint8 c, n, *dptr;
FATFS *fs = FatFs;
/* Re-initialize directory object */
clust = scan->sclust;
if (clust) { /* Dyanmic directory table */
scan->clust = clust;
scan->sect = clust2sect(clust);
} else { /* Static directory table */
scan->sect = fs->dirbase;
}
scan->index = 0;
do {
if (!move_window(scan->sect)) return NULL;
dptr = &(fs->win[(scan->index & 15) * 32]); /* Pointer to the directory entry */
c = *dptr;
if ((c == 0) || (c == 0xE5)) return dptr; /* Found an empty entry! */
} while (next_dir_entry(scan)); /* Next directory pointer */
/* Reached to end of the directory table */
/* Abort when static table or could not stretch dynamic table */
if ((!clust) || !(clust = create_chain(scan->clust))) return NULL;
if (!move_window(0)) return 0;
fs->winsect = sector = clust2sect(clust); /* Cleanup the expanded table */
memset(fs->win, 0, 512);
for (n = fs->sects_clust; n; n--) {
if (disk_write(fs->win, sector, 1) != RES_OK) return NULL;
sector++;
}
fs->winflag = 1;
return fs->win;
}
/*-----------------------------------------*/
/* Make Sure that the File System is Valid */
static uint16 check_mounted (void)
{
FATFS *fs = FatFs;
if (!fs) return FR_NOT_ENABLED; /* Has the FatFs been enabled? */
if (disk_status() & STA_NOINIT) { /* The drive has not been initialized */
if (fs->files) /* Drive was uninitialized with any file left opend */
return FR_INCORRECT_DISK_CHANGE;
else
return f_mountdrv(); /* Initialize file system and return resulut */
} else { /* The drive has been initialized */
if (!fs->fs_type) /* But the file system has not been initialized */
return f_mountdrv(); /* Initialize file system and return resulut */
}
return FR_OK; /* File system is valid */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -