⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ff.c

📁 非常好用的嵌入式系统用的fat文件系统,支持fat12 fat16 fat32
💻 C
📖 第 1 页 / 共 5 页
字号:
    }
    if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != S_SIZ)    /* No valid FAT patition is found */
        return FR_NO_FILESYSTEM;

    /* Initialize the file system object */
    fatsize = LD_WORD(&fs->win[BPB_FATSz16]);            /* Number of sectors per FAT */
    if (!fatsize) fatsize = LD_DWORD(&fs->win[BPB_FATSz32]);
    fs->sects_fat = fatsize;
    fs->n_fats = fs->win[BPB_NumFATs];                    /* Number of FAT copies */
    fatsize *= fs->n_fats;                                /* (Number of sectors in FAT area) */
    fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */
    fs->sects_clust = fs->win[BPB_SecPerClus];            /* Number of sectors per cluster */
    fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]);    /* Nmuber of root directory entries */
    totalsect = LD_WORD(&fs->win[BPB_TotSec16]);        /* Number of sectors on the file system */
    if (!totalsect) totalsect = LD_DWORD(&fs->win[BPB_TotSec32]);
    fs->max_clust = maxclust = (totalsect                /* Last cluster# + 1 */
        - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (S_SIZ/32)
        ) / fs->sects_clust + 2;

    fmt = FS_FAT12;                                        /* Determine the FAT sub type */
    if (maxclust > 0xFF7) fmt = FS_FAT16;
    if (maxclust > 0xFFF7) fmt = FS_FAT32;
    fs->fs_type = fmt;

    if (fmt == FS_FAT32)
        fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]);    /* Root directory start cluster */
    else
        fs->dirbase = fs->fatbase + fatsize;            /* Root directory start sector (lba) */
    fs->database = fs->fatbase + fatsize + fs->n_rootdir / (S_SIZ/32);    /* Data start sector (lba) */

#if !_FS_READONLY
    fs->free_clust = 0xFFFFFFFF;
#if _USE_FSINFO
    /* Load fsinfo sector if needed */
    if (fmt == FS_FAT32) {
        fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]);
        if (disk_read(0, 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
#endif
    fs->id = ++fsid;                                    /* File system mount ID */
    return FR_OK;
}




/*-----------------------------------------------------------------------*/
/* Check if the file/dir object is valid or not                          */
/*-----------------------------------------------------------------------*/

static
FRESULT validate (        /* FR_OK(0): The object is valid, !=0: Not valid */
    const FATFS *fs,    /* Pointer to the file system object */
    WORD id                /* id member of the target object to be checked */
)
{
    if (!fs || fs->id != id)
        return FR_INVALID_OBJECT;
    if (disk_status(fs->drive) & STA_NOINIT)
        return FR_NOT_READY;

    return FR_OK;
}




/*--------------------------------------------------------------------------

   Public Functions

--------------------------------------------------------------------------*/



/*-----------------------------------------------------------------------*/
/* Mount/Unmount a Locical Drive                                         */
/*-----------------------------------------------------------------------*/

FRESULT f_mount (
    BYTE drv,        /* Logical drive number to be mounted/unmounted */
    FATFS *fs        /* Pointer to new file system object (NULL for unmount)*/
)
{
    FATFS *fsobj;


    if (drv >= _DRIVES) return FR_INVALID_DRIVE;
    fsobj = FatFs[drv];
    FatFs[drv] = fs;
    if (fsobj) memset(fsobj, 0, sizeof(FATFS));
    if (fs) memset(fs, 0, sizeof(FATFS));

    return FR_OK;
}




/*-----------------------------------------------------------------------*/
/* Open or Create a File                                                 */
/*-----------------------------------------------------------------------*/

FRESULT f_open (
    FIL *fp,            /* Pointer to the blank file object */
    const char *path,    /* Pointer to the file name */
    BYTE mode            /* Access mode and file open mode flags */
)
{
    FRESULT res;
    BYTE *dir;
    DIR dirobj;
    char fn[8+3+1];
    FATFS *fs;


    fp->fs = NULL;
#if !_FS_READONLY
    mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
    res = auto_mount(&path, &fs, (BYTE)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
#else
    mode &= FA_READ;
    res = auto_mount(&path, &fs, 0);
#endif
    if (res != FR_OK) return res;
    dirobj.fs = fs;

    /* Trace the file path */
    res = trace_path(&dirobj, fn, path, &dir);
#if !_FS_READONLY
    /* Create or Open a file */
    if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
        DWORD ps, rs;
        if (res != FR_OK) {        /* No file, create new */
            if (res != FR_NO_FILE) return res;
            res = reserve_direntry(&dirobj, &dir);
            if (res != FR_OK) return res;
            memset(dir, 0, 32);                        /* Initialize the new entry with open name */
            memcpy(&dir[DIR_Name], fn, 8+3);
            dir[DIR_NTres] = fn[11];
            mode |= FA_CREATE_ALWAYS;
        }
        else {                    /* Any object is already existing */
            if (mode & FA_CREATE_NEW)            /* Cannot create new */
                return FR_EXIST;
            if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR)))    /* Cannot overwrite it (R/O or DIR) */
                return FR_DENIED;
            if (mode & FA_CREATE_ALWAYS) {        /* Resize it to zero if needed */
                rs = ((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);
                ST_DWORD(&dir[DIR_FileSize], 0);    /* size = 0 */
                fs->winflag = 1;
                ps = fs->winsect;                /* Remove the cluster chain */
                if (!remove_chain(fs, rs) || !move_window(fs, ps))
                    return FR_RW_ERROR;
                fs->last_clust = rs - 1;        /* Reuse the cluster hole */
            }
        }
        if (mode & FA_CREATE_ALWAYS) {
            dir[DIR_Attr] = AM_ARC;                /* New attribute */
            ps = get_fattime();
            ST_DWORD(&dir[DIR_WrtTime], ps);    /* Updated time */
            ST_DWORD(&dir[DIR_CrtTime], ps);    /* Created time */
            fs->winflag = 1;
        }
    }
    /* Open an existing file */
    else {
#endif /* !_FS_READONLY */
        if (res != FR_OK) return res;        /* Trace failed */
        if (dir == NULL || (dir[DIR_Attr] & AM_DIR))    /* It is a directory */
            return FR_NO_FILE;
#if !_FS_READONLY
        if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
            return FR_DENIED;
    }

    fp->dir_sect = fs->winsect;            /* Pointer to the directory entry */
    fp->dir_ptr = dir;
#endif
    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 ptr */
    fp->sect_clust = 1;                    /* Sector counter */
    fp->fs = fs; fp->id = fs->id;        /* Owner file system object of the file */

    return FR_OK;
}




/*-----------------------------------------------------------------------*/
/* Read File                                                             */
/*-----------------------------------------------------------------------*/

FRESULT f_read (
    FIL *fp,         /* Pointer to the file object */
    void *buff,        /* Pointer to data buffer */
    WORD btr,        /* Number of bytes to read */
    WORD *br        /* Pointer to number of bytes read */
)
{
    DWORD clust, sect, remain;
    WORD rcnt;
    BYTE cc, *rbuff = buff;
    FRESULT res;
    FATFS *fs = fp->fs;


    *br = 0;
    res = validate(fs, fp->id);                        /* Check validity of the object */
    if (res) return res;
    if (fp->flag & FA__ERROR) return FR_RW_ERROR;    /* Check error flag */
    if (!(fp->flag & FA_READ)) return FR_DENIED;    /* Check access mode */
    remain = fp->fsize - fp->fptr;
    if (btr > remain) btr = (WORD)remain;            /* Truncate read count by number of bytes left */

    for ( ;  btr;                                    /* Repeat until all data transferred */
        rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
        if ((fp->fptr & (S_SIZ - 1)) == 0) {        /* On the sector boundary */
            if (--fp->sect_clust) {                    /* Decrement left sector counter */
                sect = fp->curr_sect + 1;            /* Get current sector */
            } else {                                /* On the cluster boundary, get next cluster */
                clust = (fp->fptr == 0) ?
                    fp->org_clust : get_cluster(fs, fp->curr_clust);
                if (clust < 2 || clust >= fs->max_clust)
                    goto fr_error;
                fp->curr_clust = clust;                /* Current cluster */
                sect = clust2sect(fs, clust);        /* Get current sector */
                fp->sect_clust = fs->sects_clust;    /* Re-initialize the left sector counter */
            }
#if !_FS_READONLY
            if (fp->flag & FA__DIRTY) {                /* Flush file I/O buffer if needed */
                if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
                    goto fr_error;
                fp->flag &= ~FA__DIRTY;
            }
#endif
            fp->curr_sect = sect;                    /* Update current sector */
            cc = btr / S_SIZ;                        /* When left bytes >= S_SIZ, */
            if (cc) {                                /* Read maximum contiguous sectors directly */
                if (cc > fp->sect_clust) cc = fp->sect_clust;
                if (disk_read(fs->drive, rbuff, sect, cc) != RES_OK)
                    goto fr_error;
                fp->sect_clust -= cc - 1;
                fp->curr_sect += cc - 1;
                rcnt = cc * S_SIZ; continue;
            }
            if (disk_read(fs->drive, fp->buffer, sect, 1) != RES_OK)    /* Load the sector into file I/O buffer */
                goto fr_error;
        }
        rcnt = S_SIZ - ((WORD)fp->fptr & (S_SIZ - 1));                /* Copy fractional bytes from file I/O buffer */
        if (rcnt > btr) rcnt = btr;
        memcpy(rbuff, &fp->buffer[fp->fptr & (S_SIZ - 1)], rcnt);
    }

    return FR_OK;

fr_error:    /* Abort this file due to an unrecoverable error */
    fp->flag |= FA__ERROR;
    return FR_RW_ERROR;
}




#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* Write File                                                            */
/*-----------------------------------------------------------------------*/

FRESULT f_write (
    FIL *fp,            /* Pointer to the file object */
    const void *buff,    /* Pointer to the data to be written */
    WORD btw,            /* Number of bytes to write */
    WORD *bw            /* Pointer to number of bytes written */
)
{
    DWORD clust, sect;
    WORD wcnt;
    BYTE cc;
    FRESULT res;
    const BYTE *wbuff = buff;
    FATFS *fs = fp->fs;


    *bw = 0;
    res = validate(fs, fp->id);                        /* Check validity of the object */
    if (res) return res;
    if (fp->flag & FA__ERROR) return FR_RW_ERROR;    /* Check error flag */
    if (!(fp->flag & FA_WRITE)) return FR_DENIED;    /* Check access mode */
    if (fp->fsize + btw < fp->fsize) return FR_OK;    /* File size cannot reach 4GB */

    for ( ;  btw;                                    /* Repeat until all data transferred */
        wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
        if ((fp->fptr & (S_SIZ - 1)) == 0) {        /* On the sector boundary */
            if (--fp->sect_clust) {                    /* Decrement left sector counter */
                sect = fp->curr_sect + 1;            /* Get current sector */
            } else {                                /* On the cluster boundary, get next cluster */
                if (fp->fptr == 0) {                /* Is top of the file */
                    clust = fp->org_clust;
                    if (clust == 0)                    /* No cluster is created yet */
                        fp->org_clust = clust = create_chain(fs, 0);    /* Create a new cluster chain */
                } else {                            /* Middle or end of file */
                    clust = create_chain(fs, fp->curr_clust);            /* Trace or streach cluster chain */
                }
                if (clust == 0) break;                /* Disk full */
                if (clust == 1 || clust >= fs->max_clust) goto fw_error;
                fp->curr_clust = clust;                /* Current cluster */
                sect = clust2sect(fs, clust);        /* Get current sector */
                fp->sect_clust = fs->sects_clust;    /* Re-initialize the left sector counter */
            }
            if (fp->flag & FA__DIRTY) {                /* Flush file I/O buffer if needed */
                if (disk_write(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
                    goto fw_error;
                fp->flag &= ~FA__DIRTY;
            }
            fp->curr_sect = sect;                    /* Update current sector */
            cc = btw / S_SIZ;                        /* When left bytes >= S_SIZ, */
            if (cc) {                                /* Write maximum contiguous sectors directly */
                if (cc > fp->sect_clust) cc = fp->sect_clust;
                if (disk_write(fs->drive, wbuff, sect, cc) != RES_OK)
                    goto fw_error;
                fp->sect_clust -= cc - 1;
                fp->curr_sect += cc - 1;
                wcnt = cc * S_SIZ; continue;
            }
            if (fp->fptr < fp->fsize &&              /* Fill sector buffer with file data if needed */
                disk_read(fs->drive, fp->buffer, sect, 1) != RES_OK)
                    goto fw_error;
        }
        wcnt = S_SIZ - ((WORD)fp->fptr & (S_SIZ - 1));    /* Copy fractional bytes to file I/O buffer */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -