📄 ff.c
字号:
FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
FATFS **rfs, /* Pointer to pointer to the found file system object */
BYTE chk_wp /* !=0: Check media write protection for write access */
)
{
BYTE fmt, b, *tbl;
UINT vol;
DSTATUS stat;
DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
WORD nrsv;
const TCHAR *p = *path;
FATFS *fs;
/* Get logical drive number from the path name */
vol = p[0] - '0'; /* Is there a drive number? */
if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */
p += 2; *path = p; /* Return pointer to the path name */
} else { /* No drive number is given */
#if _FS_RPATH
vol = Drive; /* Use current drive */
#else
vol = 0; /* Use drive 0 */
#endif
}
/* Check if the logical drive is valid or not */
if (vol >= _DRIVES) /* Is the drive number valid? */
return FR_INVALID_DRIVE;
*rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */
if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */
ENTER_FF(fs); /* Lock file system */
if (fs->fs_type) { /* If the logical drive has been mounted */
stat = disk_status(fs->drv);
if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */
#if !_FS_READONLY
if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
return FR_WRITE_PROTECTED;
#endif
return FR_OK; /* The file system object is valid */
}
}
/* The logical drive must be mounted. Following code attempts to mount the volume (initialize the file system object) */
fs->fs_type = 0; /* Clear the file system object */
fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */
if (stat & STA_NOINIT) /* Check if the drive is ready */
return FR_NOT_READY;
#if _MAX_SS != 512 /* Get disk sector size if needed */
if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS)
return FR_NO_FILESYSTEM;
#endif
#if !_FS_READONLY
if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */
return FR_WRITE_PROTECTED;
#endif
/* Search FAT partition on the drive (Supports only generic partitionings, FDISK and SFD) */
fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
if (fmt == 1) { /* Not an FAT-VBR, the disk may be partitioned */
/* Check the partition listed in top of the partition table */
tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */
if (tbl[4]) { /* Is the partition existing? */
bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */
fmt = check_fs(fs, bsect); /* Check the partition */
}
}
if (fmt == 3) return FR_DISK_ERR;
if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */
/* Following code initializes the file system object */
if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
return FR_NO_FILESYSTEM;
fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */
if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
fs->fsize = fasize;
fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */
if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */
fasize *= b; /* Number of sectors for FAT area */
fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be 1,2,4...128) */
fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */
if (fs->n_rootdir % (SS(fs) / 32)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */
tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */
if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */
if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */
/* Determine the FAT sub type */
sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / 32); /* RSV+FAT+DIR */
if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
fmt = FS_FAT12;
if (nclst >= MIN_FAT16) fmt = FS_FAT16;
if (nclst >= MIN_FAT32) fmt = FS_FAT32;
/* Boundaries and Limits */
fs->n_fatent = nclst + 2; /* Number of FAT entries */
fs->database = bsect + sysect; /* Data start sector */
fs->fatbase = bsect + nrsv; /* FAT start sector */
if (fmt == FS_FAT32) {
if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */
fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */
szbfat = fs->n_fatent * 4; /* (Required FAT size) */
} else {
if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */
fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */
fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
}
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (FAT size must not be less than FAT sectors */
return FR_NO_FILESYSTEM;
#if !_FS_READONLY
/* Initialize cluster allocation information */
fs->free_clust = 0xFFFFFFFF;
fs->last_clust = 0;
/* Get fsinfo if available */
if (fmt == FS_FAT32) {
fs->fsi_flag = 0;
fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK &&
LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
}
}
#endif
fs->fs_type = fmt; /* FAT sub-type */
fs->id = ++Fsid; /* File system mount ID */
fs->winsect = 0; /* Invalidate sector cache */
fs->wflag = 0;
#if _FS_RPATH
fs->cdir = 0; /* Current directory (root dir) */
#endif
#if _FS_SHARE /* Clear file lock semaphores */
for (vol = 0; vol < _FS_SHARE; vol++)
fs->flsem[vol].ctr = 0;
#endif
return FR_OK;
}
/*-----------------------------------------------------------------------*/
/* Check if the file/dir object is valid or not */
/*-----------------------------------------------------------------------*/
static
FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
FATFS *fs, /* Pointer to the file system object */
WORD id /* Member id of the target object to be checked */
)
{
if (!fs || !fs->fs_type || fs->id != id)
return FR_INVALID_OBJECT;
ENTER_FF(fs); /* Lock file system */
if (disk_status(fs->drv) & STA_NOINIT)
return FR_NOT_READY;
return FR_OK;
}
/*--------------------------------------------------------------------------
Public Functions
--------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Mount/Unmount a Logical Drive */
/*-----------------------------------------------------------------------*/
FRESULT f_mount (
BYTE vol, /* Logical drive number to be mounted/unmounted-----result = f_mount(0, &fs); */
FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
)
{
FATFS *rfs;
DSTATUS rds;
if (vol >= _DRIVES) /* Check if the drive number is valid */
return FR_INVALID_DRIVE;
rfs = FatFs[vol]; /* Get current fs object */
if (rfs) {
#if _FS_REENTRANT /* Discard sync object of the current volume */
if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR;
#endif
rfs->fs_type = 0; /* Clear old fs object */
}
if (fs) {
fs->fs_type = 0; /* Clear new fs object */
#if _FS_REENTRANT /* Create sync object for the new volume */
if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR;
#endif
}
FatFs[vol] = fs; /* Register new fs object */
rds = disk_initialize(0); ///sd io initialize
if (rds == RES_OK) {
return FR_OK;
} else {
return FR_DISK_ERR;
}
}
/*-----------------------------------------------------------------------*/
/* Open or Create a File */
/*-----------------------------------------------------------------------*/
FRESULT f_open (
FIL *fp, /* Pointer to the blank file object */
const TCHAR *path, /* Pointer to the file name */
BYTE mode /* Access mode and file open mode flags */
)
{
FRESULT res;
DIR dj;
BYTE *dir;
DEF_NAMEBUF;
fp->fs = 0; /* Clear file object */
#if !_FS_READONLY
mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ));
#else
mode &= FA_READ;
res = chk_mounted(&path, &dj.fs, 0);
#endif
INIT_BUF(dj);
if (res == FR_OK)
res = follow_path(&dj, path); /* Follow the file path */
dir = dj.dir;
#if !_FS_READONLY /* R/W configuration */
if (res == FR_OK) {
if (!dir) /* Current dir itself */
res = FR_INVALID_NAME;
#if _FS_SHARE
else
res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
#endif
}
/* Create or Open a file */
if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
DWORD dw, cl;
if (res != FR_OK) { /* No file, create new */
if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
#if _FS_SHARE
res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
#else
res = dir_register(&dj);
#endif
mode |= FA_CREATE_ALWAYS;
dir = dj.dir; /* New entry */
}
else { /* Any object is already existing */
if (mode & FA_CREATE_NEW) { /* Cannot create new */
res = FR_EXIST;
} else {
if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) /* Cannot overwrite it (R/O or DIR) */
res = FR_DENIED;
}
}
if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
dw = get_fattime(); /* Created time */
ST_DWORD(dir+DIR_CrtTime, dw);
dir[DIR_Attr] = 0; /* Reset attribute */
ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
cl = ((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO); /* Get start cluster */
ST_WORD(dir+DIR_FstClusHI, 0); /* cluster = 0 */
ST_WORD(dir+DIR_FstClusLO, 0);
dj.fs->wflag = 1;
if (cl) { /* Remove the cluster chain if exist */
dw = dj.fs->winsect;
res = remove_chain(dj.fs, cl);
if (res == FR_OK) {
dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
res = move_window(dj.fs, dw);
}
}
}
}
else { /* Open an existing file */
if (res == FR_OK) { /* Follow succeeded */
if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
res = FR_NO_FILE;
} else {
if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
res = FR_DENIED;
}
}
}
if (res == FR_OK) {
if (mode & (FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW))
mode |= FA__WRITTEN; /* Set file changed flag */
fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
fp->dir_ptr = dir;
#if _FS_SHARE
fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
if (!fp->lockid) res = FR_INT_ERR;
#endif
}
#else /* R/O configuration */
if (res == FR_OK) { /* Follow succeeded */
if (!dir) { /* Current dir itself */
res = FR_INVALID_NAME;
} else {
if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
res = FR_NO_FILE;
}
}
#endif
FREE_BUF();
if (res == FR_OK) {
fp->flag = mode; /* File access mode */
fp->org_clust = /* File start cluster */
((DWORD)LD_WORD(dir+DIR_FstClusHI) << 16) | LD_WORD(dir+DIR_FstClusLO);
fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
fp->fptr = 0; /* File pointer */
fp->dsect = 0;
#if _USE_FASTSEEK
fp->cltbl = 0; /* No cluster link map table */
#endif
fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */
}
LEAVE_FF(dj.fs, res);
}
/*-----------------------------------------------------------------------*/
/* Read File */
/*-----------------------------------------------------------------------*/
FRESULT f_read (
FIL *fp, /* Pointer to the file object */
void *buff, /* Pointer to data buffer */
UINT btr, /* Number of bytes to read */
UINT *br /* Pointer to number of bytes read */
)
{
FRESULT res;
DWORD clst, sect, remain;
UINT rcnt, cc;
BYTE csect, *rbuff = buff;
*br = 0; /* Initialize byte counter */
res = validate(fp->fs, fp->id); /* Check validity of the object */
if (res != FR_OK) LEAVE_FF(fp->fs, res);
if (fp->flag & FA__ERROR) /* Check abort flag */
LEAVE_FF(fp->fs, FR_INT_ERR);
if (!(fp->flag & FA_READ)) /* Check access mode */
LEAVE_FF(fp->fs, FR_DENIED);
remain = fp->fsize - fp->fptr;
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
for ( ; btr; /* Repeat until all data transferred */
rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
if (!csect) { /* On the cluster boundary? */
clst = (fp->fptr == 0) ? /* On the top of the file? */
fp->org_clust : get_fat(fp->fs, fp->curr_clust);
if (clst <= 1) ABORT(fp->fs, FR_INT_ERR);
if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR);
fp->curr_clust = clst; /* Update current cluster */
}
sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */
if (!sect) ABORT(fp->fs, FR_INT_ERR);
sect += csect;
cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
if (cc) { /* Read maximum contigu
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -