Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ff.cpp
00001 /*----------------------------------------------------------------------------/ 00002 / FatFs - Generic FAT Filesystem Module R0.13a / 00003 /-----------------------------------------------------------------------------/ 00004 / 00005 / Copyright (C) 2017, ChaN, all right reserved. 00006 / 00007 / FatFs module is an open source software. Redistribution and use of FatFs in 00008 / source and binary forms, with or without modification, are permitted provided 00009 / that the following condition is met: 00010 / 00011 / 1. Redistributions of source code must retain the above copyright notice, 00012 / this condition and the following disclaimer. 00013 / 00014 / This software is provided by the copyright holder and contributors "AS IS" 00015 / and any warranties related to this software are DISCLAIMED. 00016 / The copyright owner or contributors be NOT LIABLE for any damages caused 00017 / by use of this software. 00018 / 00019 /----------------------------------------------------------------------------*/ 00020 00021 00022 #include "ff.h" /* Declarations of FatFs API */ 00023 #include "diskio.h" /* Declarations of device I/O functions */ 00024 00025 00026 /*-------------------------------------------------------------------------- 00027 00028 Module Private Definitions 00029 00030 ---------------------------------------------------------------------------*/ 00031 00032 #if FF_DEFINED != 89352 /* Revision ID */ 00033 #error Wrong include file (ff.h). 00034 #endif 00035 00036 00037 /* Character code support macros */ 00038 #define IsUpper(c) ((c) >= 'A' && (c) <= 'Z') 00039 #define IsLower(c) ((c) >= 'a' && (c) <= 'z') 00040 #define IsDigit(c) ((c) >= '0' && (c) <= '9') 00041 #define IsSurrogate(c) ((c) >= 0xD800 && (c) <= 0xDFFF) 00042 #define IsSurrogateH(c) ((c) >= 0xD800 && (c) <= 0xDBFF) 00043 #define IsSurrogateL(c) ((c) >= 0xDC00 && (c) <= 0xDFFF) 00044 00045 00046 /* Additional file attribute bits for internal use */ 00047 #define AM_VOL 0x08 /* Volume label */ 00048 #define AM_LFN 0x0F /* LFN entry */ 00049 #define AM_MASK 0x3F /* Mask of defined bits */ 00050 00051 00052 /* Additional file access control and file status flags for internal use */ 00053 #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ 00054 #define FA_MODIFIED 0x40 /* File has been modified */ 00055 #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ 00056 00057 00058 /* Name status flags in fn[11] */ 00059 #define NSFLAG 11 /* Index of the name status byte */ 00060 #define NS_LOSS 0x01 /* Out of 8.3 format */ 00061 #define NS_LFN 0x02 /* Force to create LFN entry */ 00062 #define NS_LAST 0x04 /* Last segment */ 00063 #define NS_BODY 0x08 /* Lower case flag (body) */ 00064 #define NS_EXT 0x10 /* Lower case flag (ext) */ 00065 #define NS_DOT 0x20 /* Dot entry */ 00066 #define NS_NOLFN 0x40 /* Do not find LFN */ 00067 #define NS_NONAME 0x80 /* Not followed */ 00068 00069 00070 /* Limits and boundaries */ 00071 #define MAX_DIR 0x200000 /* Max size of FAT directory */ 00072 #define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ 00073 #define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but right for real DOS/Windows behavior) */ 00074 #define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but right for real DOS/Windows behavior) */ 00075 #define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ 00076 #define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ 00077 00078 00079 /* FatFs refers the FAT structure as simple byte array instead of structure member 00080 / because the C structure is not binary compatible between different platforms */ 00081 00082 #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ 00083 #define BS_OEMName 3 /* OEM name (8-byte) */ 00084 #define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ 00085 #define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ 00086 #define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ 00087 #define BPB_NumFATs 16 /* Number of FATs (BYTE) */ 00088 #define BPB_RootEntCnt 17 /* Size of root directory area for FAT [entry] (WORD) */ 00089 #define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ 00090 #define BPB_Media 21 /* Media descriptor byte (BYTE) */ 00091 #define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ 00092 #define BPB_SecPerTrk 24 /* Number of sectors per track for int13h [sector] (WORD) */ 00093 #define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ 00094 #define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ 00095 #define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ 00096 #define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ 00097 #define BS_NTres 37 /* WindowsNT error flag (BYTE) */ 00098 #define BS_BootSig 38 /* Extended boot signature (BYTE) */ 00099 #define BS_VolID 39 /* Volume serial number (DWORD) */ 00100 #define BS_VolLab 43 /* Volume label string (8-byte) */ 00101 #define BS_FilSysType 54 /* Filesystem type string (8-byte) */ 00102 #define BS_BootCode 62 /* Boot code (448-byte) */ 00103 #define BS_55AA 510 /* Signature word (WORD) */ 00104 00105 #define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ 00106 #define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ 00107 #define BPB_FSVer32 42 /* FAT32: Filesystem version (WORD) */ 00108 #define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ 00109 #define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ 00110 #define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ 00111 #define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ 00112 #define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ 00113 #define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ 00114 #define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ 00115 #define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ 00116 #define BS_FilSysType32 82 /* FAT32: Filesystem type string (8-byte) */ 00117 #define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ 00118 00119 #define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ 00120 #define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ 00121 #define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ 00122 #define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ 00123 #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ 00124 #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ 00125 #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ 00126 #define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ 00127 #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ 00128 #define BPB_FSVerEx 104 /* exFAT: Filesystem version (WORD) */ 00129 #define BPB_VolFlagEx 106 /* exFAT: Volume flags (WORD) */ 00130 #define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ 00131 #define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ 00132 #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ 00133 #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ 00134 #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ 00135 #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ 00136 #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ 00137 00138 #define DIR_Name 0 /* Short file name (11-byte) */ 00139 #define DIR_Attr 11 /* Attribute (BYTE) */ 00140 #define DIR_NTres 12 /* Lower case flag (BYTE) */ 00141 #define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ 00142 #define DIR_CrtTime 14 /* Created time (DWORD) */ 00143 #define DIR_LstAccDate 18 /* Last accessed date (WORD) */ 00144 #define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ 00145 #define DIR_ModTime 22 /* Modified time (DWORD) */ 00146 #define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ 00147 #define DIR_FileSize 28 /* File size (DWORD) */ 00148 #define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ 00149 #define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ 00150 #define LDIR_Type 12 /* LFN: Entry type (BYTE) */ 00151 #define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ 00152 #define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ 00153 #define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ 00154 #define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ 00155 #define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ 00156 #define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ 00157 #define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ 00158 #define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ 00159 #define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ 00160 #define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ 00161 #define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ 00162 #define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ 00163 #define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ 00164 #define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ 00165 #define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ 00166 #define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ 00167 #define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ 00168 #define XDIR_GenFlags 33 /* exFAT: General secondary flags (BYTE) */ 00169 #define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ 00170 #define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ 00171 #define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ 00172 #define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ 00173 #define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ 00174 00175 #define SZDIRE 32 /* Size of a directory entry */ 00176 #define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ 00177 #define RDDEM 0x05 /* Replacement of the character collides with DDEM */ 00178 #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ 00179 00180 #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ 00181 #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ 00182 #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ 00183 #define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ 00184 00185 #define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ 00186 #define SZ_PTE 16 /* MBR: Size of a partition table entry */ 00187 #define PTE_Boot 0 /* MBR PTE: Boot indicator */ 00188 #define PTE_StHead 1 /* MBR PTE: Start head */ 00189 #define PTE_StSec 2 /* MBR PTE: Start sector */ 00190 #define PTE_StCyl 3 /* MBR PTE: Start cylinder */ 00191 #define PTE_System 4 /* MBR PTE: System ID */ 00192 #define PTE_EdHead 5 /* MBR PTE: End head */ 00193 #define PTE_EdSec 6 /* MBR PTE: End sector */ 00194 #define PTE_EdCyl 7 /* MBR PTE: End cylinder */ 00195 #define PTE_StLba 8 /* MBR PTE: Start in LBA */ 00196 #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ 00197 00198 00199 /* Post process on fatal error in the file operations */ 00200 #define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } 00201 00202 00203 /* Re-entrancy related */ 00204 #if FF_FS_REENTRANT 00205 #if FF_USE_LFN == 1 00206 #error Static LFN work area cannot be used at thread-safe configuration 00207 #endif 00208 #define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } 00209 #else 00210 #define LEAVE_FF(fs, res) return res 00211 #endif 00212 00213 00214 /* Definitions of volume - physical location conversion */ 00215 #if FF_MULTI_PARTITION 00216 #define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ 00217 #define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ 00218 #else 00219 #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ 00220 #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ 00221 #endif 00222 00223 00224 /* Definitions of sector size */ 00225 #if (FF_MAX_SS < FF_MIN_SS) || (FF_MAX_SS != 512 && FF_MAX_SS != 1024 && FF_MAX_SS != 2048 && FF_MAX_SS != 4096) || (FF_MIN_SS != 512 && FF_MIN_SS != 1024 && FF_MIN_SS != 2048 && FF_MIN_SS != 4096) 00226 #error Wrong sector size configuration 00227 #endif 00228 #if FF_MAX_SS == FF_MIN_SS 00229 #define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */ 00230 #else 00231 #define SS(fs) ((fs)->ssize) /* Variable sector size */ 00232 #endif 00233 00234 00235 /* Timestamp */ 00236 #if FF_FS_NORTC == 1 00237 #if FF_NORTC_YEAR < 1980 || FF_NORTC_YEAR > 2107 || FF_NORTC_MON < 1 || FF_NORTC_MON > 12 || FF_NORTC_MDAY < 1 || FF_NORTC_MDAY > 31 00238 #error Invalid FF_FS_NORTC settings 00239 #endif 00240 #define GET_FATTIME() ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16) 00241 #else 00242 #define GET_FATTIME() get_fattime() 00243 #endif 00244 00245 00246 /* File lock controls */ 00247 #if FF_FS_LOCK != 0 00248 #if FF_FS_READONLY 00249 #error FF_FS_LOCK must be 0 at read-only configuration 00250 #endif 00251 typedef struct { 00252 FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ 00253 DWORD clu; /* Object ID 2, containing directory (0:root) */ 00254 DWORD ofs; /* Object ID 3, offset in the directory */ 00255 WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ 00256 } FILESEM; 00257 #endif 00258 00259 00260 /* SBCS up-case tables (\x80-\xFF) */ 00261 #define TBL_CT437 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 00262 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00263 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00264 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00265 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00266 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00267 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00268 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00269 #define TBL_CT720 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00270 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00271 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00272 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00273 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00274 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00275 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00276 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00277 #define TBL_CT737 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00278 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ 00279 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ 00280 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00281 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00282 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00283 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00284 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00285 #define TBL_CT771 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00286 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00287 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00288 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00289 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00290 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ 00291 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00292 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} 00293 #define TBL_CT775 {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ 00294 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 00295 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00296 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00297 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00298 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00299 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ 00300 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00301 #define TBL_CT850 {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ 00302 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ 00303 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00304 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00305 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00306 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ 00307 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ 00308 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00309 #define TBL_CT852 {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ 00310 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ 00311 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ 00312 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 00313 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00314 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00315 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ 00316 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} 00317 #define TBL_CT855 {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ 00318 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ 00319 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ 00320 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 00321 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00322 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 00323 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ 00324 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} 00325 #define TBL_CT857 {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ 00326 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ 00327 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00328 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00329 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00330 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00331 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ 00332 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00333 #define TBL_CT860 {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ 00334 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00335 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00336 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00337 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00338 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00339 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00340 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00341 #define TBL_CT861 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ 00342 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 00343 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00344 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00345 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00346 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00347 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00348 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00349 #define TBL_CT862 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00350 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00351 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00352 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00353 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00354 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00355 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00356 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00357 #define TBL_CT863 {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ 00358 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ 00359 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00360 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00361 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00362 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00363 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00364 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00365 #define TBL_CT864 {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 00366 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00367 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00368 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00369 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00370 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00371 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00372 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00373 #define TBL_CT865 {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ 00374 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00375 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00376 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00377 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00378 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00379 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ 00380 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00381 #define TBL_CT866 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00382 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00383 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00384 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00385 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00386 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 00387 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 00388 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 00389 #define TBL_CT869 {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ 00390 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ 00391 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ 00392 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 00393 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ 00394 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ 00395 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ 00396 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} 00397 00398 00399 /* DBCS code range |----- 1st byte -----| |----------- 2nd byte -----------| */ 00400 #define TBL_DC932 {0x81, 0x9F, 0xE0, 0xFC, 0x40, 0x7E, 0x80, 0xFC, 0x00, 0x00} 00401 #define TBL_DC936 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0x80, 0xFE, 0x00, 0x00} 00402 #define TBL_DC949 {0x81, 0xFE, 0x00, 0x00, 0x41, 0x5A, 0x61, 0x7A, 0x81, 0xFE} 00403 #define TBL_DC950 {0x81, 0xFE, 0x00, 0x00, 0x40, 0x7E, 0xA1, 0xFE, 0x00, 0x00} 00404 00405 00406 /* Macros for table definitions */ 00407 #define MERGE_2STR(a, b) a ## b 00408 #define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) 00409 00410 00411 00412 00413 /*-------------------------------------------------------------------------- 00414 00415 Module Private Work Area 00416 00417 ---------------------------------------------------------------------------*/ 00418 /* Remark: Variables defined here without initial value shall be guaranteed 00419 / zero/null at start-up. If not, the linker option or start-up routine is 00420 / not compliance with C standard. */ 00421 00422 /*--------------------------------*/ 00423 /* File/Volume controls */ 00424 /*--------------------------------*/ 00425 00426 #if FF_VOLUMES < 1 || FF_VOLUMES > 10 00427 #error Wrong FF_VOLUMES setting 00428 #endif 00429 static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ 00430 static WORD Fsid; /* File system mount ID */ 00431 00432 #if FF_FS_RPATH != 0 && FF_VOLUMES >= 2 00433 static BYTE CurrVol; /* Current drive */ 00434 #endif 00435 00436 #if FF_FS_LOCK != 0 00437 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ 00438 #endif 00439 00440 00441 00442 /*--------------------------------*/ 00443 /* LFN/Directory working buffer */ 00444 /*--------------------------------*/ 00445 00446 #if FF_USE_LFN == 0 /* Non-LFN configuration */ 00447 #if FF_FS_EXFAT 00448 #error LFN must be enabled when enable exFAT 00449 #endif 00450 #define DEF_NAMBUF 00451 #define INIT_NAMBUF(fs) 00452 #define FREE_NAMBUF() 00453 #define LEAVE_MKFS(res) return res 00454 00455 #else /* LFN configurations */ 00456 #if FF_MAX_LFN < 12 || FF_MAX_LFN > 255 00457 #error Wrong setting of FF_MAX_LFN 00458 #endif 00459 #if FF_LFN_BUF < 12 || FF_SFN_BUF < 12 || FF_LFN_BUF < FF_SFN_BUF 00460 #error Wrong setting of FF_LFN_BUF or FF_SFN_BUF 00461 #endif 00462 #if FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2 00463 #error Wrong setting of FF_LFN_UNICODE 00464 #endif 00465 static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* FAT: Offset of LFN characters in the directory entry */ 00466 #define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) /* exFAT: Size of directory entry block scratchpad buffer needed for the name length */ 00467 00468 #if FF_USE_LFN == 1 /* LFN enabled with static working buffer */ 00469 #if FF_FS_EXFAT 00470 static BYTE DirBuf[MAXDIRB(FF_MAX_LFN)]; /* Directory entry block scratchpad buffer */ 00471 #endif 00472 static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ 00473 #define DEF_NAMBUF 00474 #define INIT_NAMBUF(fs) 00475 #define FREE_NAMBUF() 00476 #define LEAVE_MKFS(res) return res 00477 00478 #elif FF_USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ 00479 #if FF_FS_EXFAT 00480 #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; BYTE dbuf[MAXDIRB(FF_MAX_LFN)]; /* LFN working buffer and directory entry block scratchpad buffer */ 00481 #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } 00482 #define FREE_NAMBUF() 00483 #else 00484 #define DEF_NAMBUF WCHAR lbuf[FF_MAX_LFN+1]; /* LFN working buffer */ 00485 #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } 00486 #define FREE_NAMBUF() 00487 #endif 00488 #define LEAVE_MKFS(res) return res 00489 00490 #elif FF_USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ 00491 #if FF_FS_EXFAT 00492 #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer and directory entry block scratchpad buffer */ 00493 #define INIT_NAMBUF(fs) { lfn = ff_memalloc((FF_MAX_LFN+1)*2 + MAXDIRB(FF_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+FF_MAX_LFN+1); } 00494 #define FREE_NAMBUF() ff_memfree(lfn) 00495 #else 00496 #define DEF_NAMBUF WCHAR *lfn; /* Pointer to LFN working buffer */ 00497 #define INIT_NAMBUF(fs) { lfn = (WCHAR *)ff_memalloc((FF_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } 00498 #define FREE_NAMBUF() ff_memfree(lfn) 00499 #endif 00500 #define LEAVE_MKFS(res) { if (!work) ff_memfree(buf); return res; } 00501 #define MAX_MALLOC 0x8000 00502 00503 #else 00504 #error Wrong setting of FF_USE_LFN 00505 00506 #endif /* FF_USE_LFN == 1 */ 00507 #endif /* FF_USE_LFN == 0 */ 00508 00509 00510 00511 /*--------------------------------*/ 00512 /* Code conversion tables */ 00513 /*--------------------------------*/ 00514 00515 #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ 00516 #define CODEPAGE CodePage 00517 static WORD CodePage; /* Current code page */ 00518 static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ 00519 static const BYTE Ct437[] = TBL_CT437; 00520 static const BYTE Ct720[] = TBL_CT720; 00521 static const BYTE Ct737[] = TBL_CT737; 00522 static const BYTE Ct771[] = TBL_CT771; 00523 static const BYTE Ct775[] = TBL_CT775; 00524 static const BYTE Ct850[] = TBL_CT850; 00525 static const BYTE Ct852[] = TBL_CT852; 00526 static const BYTE Ct855[] = TBL_CT855; 00527 static const BYTE Ct857[] = TBL_CT857; 00528 static const BYTE Ct860[] = TBL_CT860; 00529 static const BYTE Ct861[] = TBL_CT861; 00530 static const BYTE Ct862[] = TBL_CT862; 00531 static const BYTE Ct863[] = TBL_CT863; 00532 static const BYTE Ct864[] = TBL_CT864; 00533 static const BYTE Ct865[] = TBL_CT865; 00534 static const BYTE Ct866[] = TBL_CT866; 00535 static const BYTE Ct869[] = TBL_CT869; 00536 static const BYTE Dc932[] = TBL_DC932; 00537 static const BYTE Dc936[] = TBL_DC936; 00538 static const BYTE Dc949[] = TBL_DC949; 00539 static const BYTE Dc950[] = TBL_DC950; 00540 00541 #elif FF_CODE_PAGE < 900 /* Static code page configuration (SBCS) */ 00542 #define CODEPAGE FF_CODE_PAGE 00543 static const BYTE ExCvt[] = MKCVTBL(TBL_CT, FF_CODE_PAGE); 00544 00545 #else /* Static code page configuration (DBCS) */ 00546 #define CODEPAGE FF_CODE_PAGE 00547 static const BYTE DbcTbl[] = MKCVTBL(TBL_DC, FF_CODE_PAGE); 00548 00549 #endif 00550 00551 00552 00553 00554 /*-------------------------------------------------------------------------- 00555 00556 Module Private Functions 00557 00558 ---------------------------------------------------------------------------*/ 00559 00560 00561 /*-----------------------------------------------------------------------*/ 00562 /* Load/Store multi-byte word in the FAT structure */ 00563 /*-----------------------------------------------------------------------*/ 00564 00565 static 00566 WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ 00567 { 00568 WORD rv; 00569 00570 rv = ptr[1]; 00571 rv = rv << 8 | ptr[0]; 00572 return rv; 00573 } 00574 00575 static 00576 DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ 00577 { 00578 DWORD rv; 00579 00580 rv = ptr[3]; 00581 rv = rv << 8 | ptr[2]; 00582 rv = rv << 8 | ptr[1]; 00583 rv = rv << 8 | ptr[0]; 00584 return rv; 00585 } 00586 00587 #if FF_FS_EXFAT 00588 static 00589 QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ 00590 { 00591 QWORD rv; 00592 00593 rv = ptr[7]; 00594 rv = rv << 8 | ptr[6]; 00595 rv = rv << 8 | ptr[5]; 00596 rv = rv << 8 | ptr[4]; 00597 rv = rv << 8 | ptr[3]; 00598 rv = rv << 8 | ptr[2]; 00599 rv = rv << 8 | ptr[1]; 00600 rv = rv << 8 | ptr[0]; 00601 return rv; 00602 } 00603 #endif 00604 00605 #if !FF_FS_READONLY 00606 static 00607 void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ 00608 { 00609 *ptr++ = (BYTE)val; val >>= 8; 00610 *ptr++ = (BYTE)val; 00611 } 00612 00613 static 00614 void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ 00615 { 00616 *ptr++ = (BYTE)val; val >>= 8; 00617 *ptr++ = (BYTE)val; val >>= 8; 00618 *ptr++ = (BYTE)val; val >>= 8; 00619 *ptr++ = (BYTE)val; 00620 } 00621 00622 #if FF_FS_EXFAT 00623 static 00624 void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ 00625 { 00626 *ptr++ = (BYTE)val; val >>= 8; 00627 *ptr++ = (BYTE)val; val >>= 8; 00628 *ptr++ = (BYTE)val; val >>= 8; 00629 *ptr++ = (BYTE)val; val >>= 8; 00630 *ptr++ = (BYTE)val; val >>= 8; 00631 *ptr++ = (BYTE)val; val >>= 8; 00632 *ptr++ = (BYTE)val; val >>= 8; 00633 *ptr++ = (BYTE)val; 00634 } 00635 #endif 00636 #endif /* !FF_FS_READONLY */ 00637 00638 00639 00640 /*-----------------------------------------------------------------------*/ 00641 /* String functions */ 00642 /*-----------------------------------------------------------------------*/ 00643 00644 /* Copy memory to memory */ 00645 static 00646 void mem_cpy (void* dst, const void* src, UINT cnt) 00647 { 00648 BYTE *d = (BYTE*)dst; 00649 const BYTE *s = (const BYTE*)src; 00650 00651 if (cnt != 0) { 00652 do { 00653 *d++ = *s++; 00654 } while (--cnt); 00655 } 00656 } 00657 00658 00659 /* Fill memory block */ 00660 static 00661 void mem_set (void* dst, int val, UINT cnt) 00662 { 00663 BYTE *d = (BYTE*)dst; 00664 00665 do { 00666 *d++ = (BYTE)val; 00667 } while (--cnt); 00668 } 00669 00670 00671 /* Compare memory block */ 00672 static 00673 int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ 00674 { 00675 const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; 00676 int r = 0; 00677 00678 do { 00679 r = *d++ - *s++; 00680 } while (--cnt && r == 0); 00681 00682 return r; 00683 } 00684 00685 00686 /* Check if chr is contained in the string */ 00687 static 00688 int chk_chr (const char* str, int chr) /* NZ:contained, ZR:not contained */ 00689 { 00690 while (*str && *str != chr) str++; 00691 return *str; 00692 } 00693 00694 00695 /* Test if the character is DBC 1st byte */ 00696 static 00697 int dbc_1st (BYTE c) 00698 { 00699 #if FF_CODE_PAGE == 0 /* Variable code page */ 00700 if (DbcTbl && c >= DbcTbl[0]) { 00701 if (c <= DbcTbl[1]) return 1; /* 1st byte range 1 */ 00702 if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; /* 1st byte range 2 */ 00703 } 00704 #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ 00705 if (c >= DbcTbl[0]) { 00706 if (c <= DbcTbl[1]) return 1; 00707 if (c >= DbcTbl[2] && c <= DbcTbl[3]) return 1; 00708 } 00709 #else /* SBCS fixed code page */ 00710 if (c != 0) return 0; /* Always false */ 00711 #endif 00712 return 0; 00713 } 00714 00715 00716 /* Test if the character is DBC 2nd byte */ 00717 static 00718 int dbc_2nd (BYTE c) 00719 { 00720 #if FF_CODE_PAGE == 0 /* Variable code page */ 00721 if (DbcTbl && c >= DbcTbl[4]) { 00722 if (c <= DbcTbl[5]) return 1; /* 2nd byte range 1 */ 00723 if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; /* 2nd byte range 2 */ 00724 if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; /* 2nd byte range 3 */ 00725 } 00726 #elif FF_CODE_PAGE >= 900 /* DBCS fixed code page */ 00727 if (c >= DbcTbl[4]) { 00728 if (c <= DbcTbl[5]) return 1; 00729 if (c >= DbcTbl[6] && c <= DbcTbl[7]) return 1; 00730 if (c >= DbcTbl[8] && c <= DbcTbl[9]) return 1; 00731 } 00732 #else /* SBCS fixed code page */ 00733 if (c != 0) return 0; /* Always false */ 00734 #endif 00735 return 0; 00736 } 00737 00738 00739 #if FF_USE_LFN 00740 00741 /* Get a character from TCHAR string in defined API encodeing */ 00742 static 00743 DWORD tchar2uni ( /* Returns character in UTF-16 encoding (>=0x10000 on double encoding unit, 0xFFFFFFFF on decode error) */ 00744 const TCHAR** str /* Pointer to pointer to TCHAR string in configured encoding */ 00745 ) 00746 { 00747 DWORD uc; 00748 const TCHAR *p = *str; 00749 00750 #if FF_LFN_UNICODE == 1 /* UTF-16 input */ 00751 WCHAR wc; 00752 00753 uc = *p++; 00754 if (IsSurrogate(uc)) { /* Surrogate? */ 00755 wc = *p++; /* Get low surrogate */ 00756 if (!IsSurrogateH(uc) || !IsSurrogateL(wc)) return 0xFFFFFFFF; /* Wrong surrogate? */ 00757 uc = uc << 16 | wc; 00758 } 00759 00760 #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ 00761 BYTE b; 00762 int nf; 00763 00764 uc = (BYTE)*p++; /* Get a byte */ 00765 if (uc & 0x80) { /* Multiple byte code? */ 00766 if ((uc & 0xE0) == 0xC0) { /* 2-byte sequence? */ 00767 uc &= 0x1F; nf = 1; 00768 } else { 00769 if ((uc & 0xF0) == 0xE0) { /* 3-byte sequence? */ 00770 uc &= 0x0F; nf = 2; 00771 } else { 00772 if ((uc & 0xF8) == 0xF0) { /* 4-byte sequence? */ 00773 uc &= 0x07; nf = 3; 00774 } else { /* Wrong sequence */ 00775 return 0xFFFFFFFF; 00776 } 00777 } 00778 } 00779 do { /* Get trailing bytes */ 00780 b = (BYTE)*p++; 00781 if ((b & 0xC0) != 0x80) return 0xFFFFFFFF; /* Wrong sequence? */ 00782 uc = uc << 6 | (b & 0x3F); 00783 } while (--nf != 0); 00784 if (uc < 0x80 || IsSurrogate(uc) || uc >= 0x110000) return 0xFFFFFFFF; /* Wrong code? */ 00785 if (uc >= 0x10000) uc = 0xD800DC00 | ((uc - 0x10000) << 6 & 0x3FF0000) | (uc & 0x3FF); /* Make a surrogate pair if needed */ 00786 } 00787 00788 #else /* ANSI/OEM input */ 00789 BYTE b; 00790 WCHAR wc; 00791 00792 wc = (BYTE)*p++; /* Get a byte */ 00793 if (dbc_1st((BYTE)wc)) { /* Is it a DBC 1st byte? */ 00794 b = (BYTE)*p++; /* Get 2nd byte */ 00795 if (!dbc_2nd(b)) return 0xFFFFFFFF; /* Invalid code? */ 00796 wc = (wc << 8) + b; /* Make a DBC */ 00797 } 00798 if (wc != 0) { 00799 wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM ==> Unicode */ 00800 if (wc == 0) return 0xFFFFFFFF; /* Invalid code? */ 00801 } 00802 uc = wc; 00803 00804 #endif 00805 *str = p; /* Next read pointer */ 00806 return uc; 00807 } 00808 00809 00810 /* Output a TCHAR string in defined API encoding */ 00811 static 00812 BYTE put_utf ( /* Returns number of encoding units written (0:buffer overflow or wrong encoding) */ 00813 DWORD chr, /* UTF-16 encoded character (Double encoding unit char if >=0x10000) */ 00814 TCHAR* buf, /* Output buffer */ 00815 UINT szb /* Size of the buffer */ 00816 ) 00817 { 00818 #if FF_LFN_UNICODE == 1 /* UTF-16 output */ 00819 WCHAR hs, wc; 00820 00821 hs = (WCHAR)(chr >> 16); 00822 wc = (WCHAR)chr; 00823 if (hs == 0) { /* Single encoding unit? */ 00824 if (szb < 1 || IsSurrogate(wc)) return 0; /* Buffer overflow or wrong code? */ 00825 *buf = wc; 00826 return 1; 00827 } 00828 if (szb < 2 || !IsSurrogateH(hs) || !IsSurrogateL(wc)) return 0; /* Buffer overflow or wrong surrogate? */ 00829 *buf++ = hs; 00830 *buf++ = wc; 00831 return 2; 00832 00833 #elif FF_LFN_UNICODE == 2 /* UTF-8 output */ 00834 DWORD hc; 00835 00836 if (chr < 0x80) { /* Single byte code? */ 00837 if (szb < 1) return 0; /* Buffer overflow? */ 00838 *buf = (TCHAR)chr; 00839 return 1; 00840 } 00841 if (chr < 0x800) { /* 2-byte sequence? */ 00842 if (szb < 2) return 0; /* Buffer overflow? */ 00843 *buf++ = (TCHAR)(0xC0 | (chr >> 6 & 0x1F)); 00844 *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); 00845 return 2; 00846 } 00847 if (chr < 0x10000) { /* 3-byte sequence? */ 00848 if (szb < 3 || IsSurrogate(chr)) return 0; /* Buffer overflow or wrong code? */ 00849 *buf++ = (TCHAR)(0xE0 | (chr >> 12 & 0x0F)); 00850 *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); 00851 *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); 00852 return 3; 00853 } 00854 /* 4-byte sequence */ 00855 if (szb < 4) return 0; /* Buffer overflow? */ 00856 hc = ((chr & 0xFFFF0000) - 0xD8000000) >> 6; /* Get high 10 bits */ 00857 chr = (chr & 0xFFFF) - 0xDC00; /* Get low 10 bits */ 00858 if (hc >= 0x100000 || chr >= 0x400) return 0; /* Wrong surrogate? */ 00859 chr = (hc | chr) + 0x10000; 00860 *buf++ = (TCHAR)(0xF0 | (chr >> 18 & 0x07)); 00861 *buf++ = (TCHAR)(0x80 | (chr >> 12 & 0x3F)); 00862 *buf++ = (TCHAR)(0x80 | (chr >> 6 & 0x3F)); 00863 *buf++ = (TCHAR)(0x80 | (chr >> 0 & 0x3F)); 00864 return 4; 00865 00866 #else /* ANSI/OEM output */ 00867 WCHAR wc; 00868 00869 wc = ff_uni2oem(chr, CODEPAGE); 00870 if (wc >= 0x100) { /* Is this a DBC? */ 00871 if (szb < 2) return 0; 00872 *buf++ = (char)(wc >> 8); /* Store DBC 1st byte */ 00873 *buf++ = (TCHAR)wc; /* Store DBC 2nd byte */ 00874 return 2; 00875 } 00876 if (wc == 0 || szb < 1) return 0; /* Invalid char or buffer overflow? */ 00877 *buf++ = (TCHAR)wc; /* Store the character */ 00878 return 1; 00879 #endif 00880 } 00881 #endif /* FF_USE_LFN */ 00882 00883 00884 #if FF_FS_REENTRANT 00885 /*-----------------------------------------------------------------------*/ 00886 /* Request/Release grant to access the volume */ 00887 /*-----------------------------------------------------------------------*/ 00888 static 00889 int lock_fs ( /* 1:Ok, 0:timeout */ 00890 FATFS* fs /* Filesystem object */ 00891 ) 00892 { 00893 return ff_req_grant(fs->sobj); 00894 } 00895 00896 00897 static 00898 void unlock_fs ( 00899 FATFS* fs, /* Filesystem object */ 00900 FRESULT res /* Result code to be returned */ 00901 ) 00902 { 00903 if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { 00904 ff_rel_grant(fs->sobj); 00905 } 00906 } 00907 00908 #endif 00909 00910 00911 00912 #if FF_FS_LOCK != 0 00913 /*-----------------------------------------------------------------------*/ 00914 /* File lock control functions */ 00915 /*-----------------------------------------------------------------------*/ 00916 00917 static 00918 FRESULT chk_lock ( /* Check if the file can be accessed */ 00919 FATFS_DIR* dp, /* Directory object pointing the file to be checked */ 00920 int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ 00921 ) 00922 { 00923 UINT i, be; 00924 00925 /* Search open object table for the object */ 00926 be = 0; 00927 for (i = 0; i < FF_FS_LOCK; i++) { 00928 if (Files[i].fs) { /* Existing entry */ 00929 if (Files[i].fs == dp->obj.fs && /* Check if the object matches with an open object */ 00930 Files[i].clu == dp->obj.sclust && 00931 Files[i].ofs == dp->dptr) break; 00932 } else { /* Blank entry */ 00933 be = 1; 00934 } 00935 } 00936 if (i == FF_FS_LOCK) { /* The object has not been opened */ 00937 return (!be && acc != 2) ? FR_TOO_MANY_OPEN_FILES : FR_OK; /* Is there a blank entry for new object? */ 00938 } 00939 00940 /* The object was opened. Reject any open against writing file and all write mode open */ 00941 return (acc != 0 || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; 00942 } 00943 00944 00945 static 00946 int enq_lock (void) /* Check if an entry is available for a new object */ 00947 { 00948 UINT i; 00949 00950 for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; 00951 return (i == FF_FS_LOCK) ? 0 : 1; 00952 } 00953 00954 00955 static 00956 UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ 00957 FATFS_DIR* dp,/* Directory object pointing the file to register or increment */ 00958 int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ 00959 ) 00960 { 00961 UINT i; 00962 00963 00964 for (i = 0; i < FF_FS_LOCK; i++) { /* Find the object */ 00965 if (Files[i].fs == dp->obj.fs && 00966 Files[i].clu == dp->obj.sclust && 00967 Files[i].ofs == dp->dptr) break; 00968 } 00969 00970 if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ 00971 for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; 00972 if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ 00973 Files[i].fs = dp->obj.fs; 00974 Files[i].clu = dp->obj.sclust; 00975 Files[i].ofs = dp->dptr; 00976 Files[i].ctr = 0; 00977 } 00978 00979 if (acc >= 1 && Files[i].ctr) return 0; /* Access violation (int err) */ 00980 00981 Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ 00982 00983 return i + 1; /* Index number origin from 1 */ 00984 } 00985 00986 00987 static 00988 FRESULT dec_lock ( /* Decrement object open counter */ 00989 UINT i /* Semaphore index (1..) */ 00990 ) 00991 { 00992 WORD n; 00993 FRESULT res; 00994 00995 00996 if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ 00997 n = Files[i].ctr; 00998 if (n == 0x100) n = 0; /* If write mode open, delete the entry */ 00999 if (n > 0) n--; /* Decrement read mode open count */ 01000 Files[i].ctr = n; 01001 if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ 01002 res = FR_OK; 01003 } else { 01004 res = FR_INT_ERR; /* Invalid index nunber */ 01005 } 01006 return res; 01007 } 01008 01009 01010 static 01011 void clear_lock ( /* Clear lock entries of the volume */ 01012 FATFS *fs 01013 ) 01014 { 01015 UINT i; 01016 01017 for (i = 0; i < FF_FS_LOCK; i++) { 01018 if (Files[i].fs == fs) Files[i].fs = 0; 01019 } 01020 } 01021 01022 #endif /* FF_FS_LOCK != 0 */ 01023 01024 01025 01026 /*-----------------------------------------------------------------------*/ 01027 /* Move/Flush disk access window in the filesystem object */ 01028 /*-----------------------------------------------------------------------*/ 01029 #if !FF_FS_READONLY 01030 static 01031 FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ 01032 FATFS* fs /* Filesystem object */ 01033 ) 01034 { 01035 FRESULT res = FR_OK; 01036 01037 01038 if (fs->wflag) { /* Is the disk access window dirty */ 01039 if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ 01040 fs->wflag = 0; /* Clear window dirty flag */ 01041 if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ 01042 if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ 01043 } 01044 } else { 01045 res = FR_DISK_ERR; 01046 } 01047 } 01048 return res; 01049 } 01050 #endif 01051 01052 01053 static 01054 FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ 01055 FATFS* fs, /* Filesystem object */ 01056 DWORD sector /* Sector number to make appearance in the fs->win[] */ 01057 ) 01058 { 01059 FRESULT res = FR_OK; 01060 01061 01062 if (sector != fs->winsect) { /* Window offset changed? */ 01063 #if !FF_FS_READONLY 01064 res = sync_window(fs); /* Write-back changes */ 01065 #endif 01066 if (res == FR_OK) { /* Fill sector window with new data */ 01067 if (disk_read(fs->pdrv, fs->win, sector, 1) != RES_OK) { 01068 sector = 0xFFFFFFFF; /* Invalidate window if read data is not valid */ 01069 res = FR_DISK_ERR; 01070 } 01071 fs->winsect = sector; 01072 } 01073 } 01074 return res; 01075 } 01076 01077 01078 01079 01080 #if !FF_FS_READONLY 01081 /*-----------------------------------------------------------------------*/ 01082 /* Synchronize filesystem and data on the storage */ 01083 /*-----------------------------------------------------------------------*/ 01084 01085 static 01086 FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ 01087 FATFS* fs /* Filesystem object */ 01088 ) 01089 { 01090 FRESULT res; 01091 01092 01093 res = sync_window(fs); 01094 if (res == FR_OK) { 01095 if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { /* FAT32: Update FSInfo sector if needed */ 01096 /* Create FSInfo structure */ 01097 mem_set(fs->win, 0, SS(fs)); 01098 st_word(fs->win + BS_55AA, 0xAA55); 01099 st_dword(fs->win + FSI_LeadSig, 0x41615252); 01100 st_dword(fs->win + FSI_StrucSig, 0x61417272); 01101 st_dword(fs->win + FSI_Free_Count, fs->free_clst); 01102 st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); 01103 /* Write it into the FSInfo sector */ 01104 fs->winsect = fs->volbase + 1; 01105 disk_write(fs->pdrv, fs->win, fs->winsect, 1); 01106 fs->fsi_flag = 0; 01107 } 01108 /* Make sure that no pending write process in the lower layer */ 01109 if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; 01110 } 01111 01112 return res; 01113 } 01114 01115 #endif 01116 01117 01118 01119 /*-----------------------------------------------------------------------*/ 01120 /* Get physical sector number from cluster number */ 01121 /*-----------------------------------------------------------------------*/ 01122 01123 static 01124 DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ 01125 FATFS* fs, /* Filesystem object */ 01126 DWORD clst /* Cluster# to be converted */ 01127 ) 01128 { 01129 clst -= 2; /* Cluster number is origin from 2 */ 01130 if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */ 01131 return fs->database + fs->csize * clst; /* Start sector number of the cluster */ 01132 } 01133 01134 01135 01136 01137 /*-----------------------------------------------------------------------*/ 01138 /* FAT access - Read value of a FAT entry */ 01139 /*-----------------------------------------------------------------------*/ 01140 01141 static 01142 DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ 01143 FFOBJID* obj, /* Corresponding object */ 01144 DWORD clst /* Cluster number to get the value */ 01145 ) 01146 { 01147 UINT wc, bc; 01148 DWORD val; 01149 FATFS *fs = obj->fs; 01150 01151 01152 if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ 01153 val = 1; /* Internal error */ 01154 01155 } else { 01156 val = 0xFFFFFFFF; /* Default value falls on disk error */ 01157 01158 switch (fs->fs_type) { 01159 case FS_FAT12 : 01160 bc = (UINT)clst; bc += bc / 2; 01161 if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; 01162 wc = fs->win[bc++ % SS(fs)]; /* Get 1st byte of the entry */ 01163 if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; 01164 wc |= fs->win[bc % SS(fs)] << 8; /* Merge 2nd byte of the entry */ 01165 val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); /* Adjust bit position */ 01166 break; 01167 01168 case FS_FAT16 : 01169 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; 01170 val = ld_word(fs->win + clst * 2 % SS(fs)); /* Simple WORD array */ 01171 break; 01172 01173 case FS_FAT32 : 01174 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; 01175 val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; /* Simple DWORD array but mask out upper 4 bits */ 01176 break; 01177 #if FF_FS_EXFAT 01178 case FS_EXFAT : 01179 if (obj->objsize != 0) { 01180 DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ 01181 DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ 01182 01183 if (obj->stat == 2 && cofs <= clen) { /* Is it a contiguous chain? */ 01184 val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* No data on the FAT, generate the value */ 01185 break; 01186 } 01187 if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ 01188 val = clst + 1; /* Generate the value */ 01189 break; 01190 } 01191 if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ 01192 if (obj->n_frag != 0) { /* Is it on the growing edge? */ 01193 val = 0x7FFFFFFF; /* Generate EOC */ 01194 } else { 01195 if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; 01196 val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; 01197 } 01198 break; 01199 } 01200 } 01201 /* go to default */ 01202 #endif 01203 default: 01204 val = 1; /* Internal error */ 01205 } 01206 } 01207 01208 return val; 01209 } 01210 01211 01212 01213 01214 #if !FF_FS_READONLY 01215 /*-----------------------------------------------------------------------*/ 01216 /* FAT access - Change value of a FAT entry */ 01217 /*-----------------------------------------------------------------------*/ 01218 01219 static 01220 FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ 01221 FATFS* fs, /* Corresponding filesystem object */ 01222 DWORD clst, /* FAT index number (cluster number) to be changed */ 01223 DWORD val /* New value to be set to the entry */ 01224 ) 01225 { 01226 UINT bc; 01227 BYTE *p; 01228 FRESULT res = FR_INT_ERR; 01229 01230 01231 if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ 01232 switch (fs->fs_type) { 01233 case FS_FAT12 : 01234 bc = (UINT)clst; bc += bc / 2; /* bc: byte offset of the entry */ 01235 res = move_window(fs, fs->fatbase + (bc / SS(fs))); 01236 if (res != FR_OK) break; 01237 p = fs->win + bc++ % SS(fs); 01238 *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; /* Put 1st byte */ 01239 fs->wflag = 1; 01240 res = move_window(fs, fs->fatbase + (bc / SS(fs))); 01241 if (res != FR_OK) break; 01242 p = fs->win + bc % SS(fs); 01243 *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); /* Put 2nd byte */ 01244 fs->wflag = 1; 01245 break; 01246 01247 case FS_FAT16 : 01248 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); 01249 if (res != FR_OK) break; 01250 st_word(fs->win + clst * 2 % SS(fs), (WORD)val); /* Simple WORD array */ 01251 fs->wflag = 1; 01252 break; 01253 01254 case FS_FAT32 : 01255 #if FF_FS_EXFAT 01256 case FS_EXFAT : 01257 #endif 01258 res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); 01259 if (res != FR_OK) break; 01260 if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { 01261 val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); 01262 } 01263 st_dword(fs->win + clst * 4 % SS(fs), val); 01264 fs->wflag = 1; 01265 break; 01266 } 01267 } 01268 return res; 01269 } 01270 01271 #endif /* !FF_FS_READONLY */ 01272 01273 01274 01275 01276 #if FF_FS_EXFAT && !FF_FS_READONLY 01277 /*-----------------------------------------------------------------------*/ 01278 /* exFAT: Accessing FAT and Allocation Bitmap */ 01279 /*-----------------------------------------------------------------------*/ 01280 01281 /*--------------------------------------*/ 01282 /* Find a contiguous free cluster block */ 01283 /*--------------------------------------*/ 01284 01285 static 01286 DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ 01287 FATFS* fs, /* Filesystem object */ 01288 DWORD clst, /* Cluster number to scan from */ 01289 DWORD ncl /* Number of contiguous clusters to find (1..) */ 01290 ) 01291 { 01292 BYTE bm, bv; 01293 UINT i; 01294 DWORD val, scl, ctr; 01295 01296 01297 clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ 01298 if (clst >= fs->n_fatent - 2) clst = 0; 01299 scl = val = clst; ctr = 0; 01300 for (;;) { 01301 if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ 01302 i = val / 8 % SS(fs); bm = 1 << (val % 8); 01303 do { 01304 do { 01305 bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ 01306 if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ 01307 val = 0; bm = 0; i = SS(fs); 01308 } 01309 if (bv == 0) { /* Is it a free cluster? */ 01310 if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ 01311 } else { 01312 scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ 01313 } 01314 if (val == clst) return 0; /* All cluster scanned? */ 01315 } while (bm != 0); 01316 bm = 1; 01317 } while (++i < SS(fs)); 01318 } 01319 } 01320 01321 01322 /*----------------------------------------*/ 01323 /* Set/Clear a block of allocation bitmap */ 01324 /*----------------------------------------*/ 01325 01326 static 01327 FRESULT change_bitmap ( 01328 FATFS* fs, /* Filesystem object */ 01329 DWORD clst, /* Cluster number to change from */ 01330 DWORD ncl, /* Number of clusters to be changed */ 01331 int bv /* bit value to be set (0 or 1) */ 01332 ) 01333 { 01334 BYTE bm; 01335 UINT i; 01336 DWORD sect; 01337 01338 01339 clst -= 2; /* The first bit corresponds to cluster #2 */ 01340 sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ 01341 i = clst / 8 % SS(fs); /* Byte offset in the sector */ 01342 bm = 1 << (clst % 8); /* Bit mask in the byte */ 01343 for (;;) { 01344 if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; 01345 do { 01346 do { 01347 if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ 01348 fs->win[i] ^= bm; /* Flip the bit */ 01349 fs->wflag = 1; 01350 if (--ncl == 0) return FR_OK; /* All bits processed? */ 01351 } while (bm <<= 1); /* Next bit */ 01352 bm = 1; 01353 } while (++i < SS(fs)); /* Next byte */ 01354 i = 0; 01355 } 01356 } 01357 01358 01359 /*---------------------------------------------*/ 01360 /* Fill the first fragment of the FAT chain */ 01361 /*---------------------------------------------*/ 01362 01363 static 01364 FRESULT fill_first_frag ( 01365 FFOBJID* obj /* Pointer to the corresponding object */ 01366 ) 01367 { 01368 FRESULT res; 01369 DWORD cl, n; 01370 01371 01372 if (obj->stat == 3) { /* Has the object been changed 'fragmented' in this session? */ 01373 for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ 01374 res = put_fat(obj->fs, cl, cl + 1); 01375 if (res != FR_OK) return res; 01376 } 01377 obj->stat = 0; /* Change status 'FAT chain is valid' */ 01378 } 01379 return FR_OK; 01380 } 01381 01382 01383 /*---------------------------------------------*/ 01384 /* Fill the last fragment of the FAT chain */ 01385 /*---------------------------------------------*/ 01386 01387 static 01388 FRESULT fill_last_frag ( 01389 FFOBJID* obj, /* Pointer to the corresponding object */ 01390 DWORD lcl, /* Last cluster of the fragment */ 01391 DWORD term /* Value to set the last FAT entry */ 01392 ) 01393 { 01394 FRESULT res; 01395 01396 01397 while (obj->n_frag > 0) { /* Create the chain of last fragment */ 01398 res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); 01399 if (res != FR_OK) return res; 01400 obj->n_frag--; 01401 } 01402 return FR_OK; 01403 } 01404 01405 #endif /* FF_FS_EXFAT && !FF_FS_READONLY */ 01406 01407 01408 01409 #if !FF_FS_READONLY 01410 /*-----------------------------------------------------------------------*/ 01411 /* FAT handling - Remove a cluster chain */ 01412 /*-----------------------------------------------------------------------*/ 01413 static 01414 FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ 01415 FFOBJID* obj, /* Corresponding object */ 01416 DWORD clst, /* Cluster to remove a chain from */ 01417 DWORD pclst /* Previous cluster of clst (0:entire chain) */ 01418 ) 01419 { 01420 FRESULT res = FR_OK; 01421 DWORD nxt; 01422 FATFS *fs = obj->fs; 01423 #if FF_FS_EXFAT || FF_USE_TRIM 01424 DWORD scl = clst, ecl = clst; 01425 #endif 01426 #if FF_USE_TRIM 01427 DWORD rt[2]; 01428 #endif 01429 01430 if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ 01431 01432 /* Mark the previous cluster 'EOC' on the FAT if it exists */ 01433 if (pclst != 0 && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { 01434 res = put_fat(fs, pclst, 0xFFFFFFFF); 01435 if (res != FR_OK) return res; 01436 } 01437 01438 /* Remove the chain */ 01439 do { 01440 nxt = get_fat(obj, clst); /* Get cluster status */ 01441 if (nxt == 0) break; /* Empty cluster? */ 01442 if (nxt == 1) return FR_INT_ERR; /* Internal error? */ 01443 if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ 01444 if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { 01445 res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ 01446 if (res != FR_OK) return res; 01447 } 01448 if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ 01449 fs->free_clst++; 01450 fs->fsi_flag |= 1; 01451 } 01452 #if FF_FS_EXFAT || FF_USE_TRIM 01453 if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ 01454 ecl = nxt; 01455 } else { /* End of contiguous cluster block */ 01456 #if FF_FS_EXFAT 01457 if (fs->fs_type == FS_EXFAT) { 01458 res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ 01459 if (res != FR_OK) return res; 01460 } 01461 #endif 01462 #if FF_USE_TRIM 01463 rt[0] = clst2sect(fs, scl); /* Start of data area freed */ 01464 rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area freed */ 01465 disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ 01466 #endif 01467 scl = ecl = nxt; 01468 } 01469 #endif 01470 clst = nxt; /* Next cluster */ 01471 } while (clst < fs->n_fatent); /* Repeat while not the last link */ 01472 01473 #if FF_FS_EXFAT 01474 /* Some post processes for chain status */ 01475 if (fs->fs_type == FS_EXFAT) { 01476 if (pclst == 0) { /* Has the entire chain been removed? */ 01477 obj->stat = 0; /* Change the chain status 'initial' */ 01478 } else { 01479 if (obj->stat == 0) { /* Is it a fragmented chain from the beginning of this session? */ 01480 clst = obj->sclust; /* Follow the chain to check if it gets contiguous */ 01481 while (clst != pclst) { 01482 nxt = get_fat(obj, clst); 01483 if (nxt < 2) return FR_INT_ERR; 01484 if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; 01485 if (nxt != clst + 1) break; /* Not contiguous? */ 01486 clst++; 01487 } 01488 if (clst == pclst) { /* Has the chain got contiguous again? */ 01489 obj->stat = 2; /* Change the chain status 'contiguous' */ 01490 } 01491 } else { 01492 if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Was the chain fragmented in this session and got contiguous again? */ 01493 obj->stat = 2; /* Change the chain status 'contiguous' */ 01494 } 01495 } 01496 } 01497 } 01498 #endif 01499 return FR_OK; 01500 } 01501 01502 01503 01504 01505 /*-----------------------------------------------------------------------*/ 01506 /* FAT handling - Stretch a chain or Create a new chain */ 01507 /*-----------------------------------------------------------------------*/ 01508 static 01509 DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ 01510 FFOBJID* obj, /* Corresponding object */ 01511 DWORD clst /* Cluster# to stretch, 0:Create a new chain */ 01512 ) 01513 { 01514 DWORD cs, ncl, scl; 01515 FRESULT res; 01516 FATFS *fs = obj->fs; 01517 01518 01519 if (clst == 0) { /* Create a new chain */ 01520 scl = fs->last_clst; /* Suggested cluster to start to find */ 01521 if (scl == 0 || scl >= fs->n_fatent) scl = 1; 01522 } 01523 else { /* Stretch a chain */ 01524 cs = get_fat(obj, clst); /* Check the cluster status */ 01525 if (cs < 2) return 1; /* Test for insanity */ 01526 if (cs == 0xFFFFFFFF) return cs; /* Test for disk error */ 01527 if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ 01528 scl = clst; /* Cluster to start to find */ 01529 } 01530 if (fs->free_clst == 0) return 0; /* No free cluster */ 01531 01532 #if FF_FS_EXFAT 01533 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 01534 ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ 01535 if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ 01536 res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ 01537 if (res == FR_INT_ERR) return 1; 01538 if (res == FR_DISK_ERR) return 0xFFFFFFFF; 01539 if (clst == 0) { /* Is it a new chain? */ 01540 obj->stat = 2; /* Set status 'contiguous' */ 01541 } else { /* It is a stretched chain */ 01542 if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ 01543 obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ 01544 obj->stat = 3; /* Change status 'just fragmented' */ 01545 } 01546 } 01547 if (obj->stat != 2) { /* Is the file non-contiguous? */ 01548 if (ncl == clst + 1) { /* Is the cluster next to previous one? */ 01549 obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ 01550 } else { /* New fragment */ 01551 if (obj->n_frag == 0) obj->n_frag = 1; 01552 res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ 01553 if (res == FR_OK) obj->n_frag = 1; 01554 } 01555 } 01556 } else 01557 #endif 01558 { /* On the FAT/FAT32 volume */ 01559 ncl = 0; 01560 if (scl == clst) { /* Stretching an existing chain? */ 01561 ncl = scl + 1; /* Test if next cluster is free */ 01562 if (ncl >= fs->n_fatent) ncl = 2; 01563 cs = get_fat(obj, ncl); /* Get next cluster status */ 01564 if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ 01565 if (cs != 0) { /* Not free? */ 01566 cs = fs->last_clst; /* Start at suggested cluster if it is valid */ 01567 if (cs >= 2 && cs < fs->n_fatent) scl = cs; 01568 ncl = 0; 01569 } 01570 } 01571 if (ncl == 0) { /* The new cluster cannot be contiguous and find another fragment */ 01572 ncl = scl; /* Start cluster */ 01573 for (;;) { 01574 ncl++; /* Next cluster */ 01575 if (ncl >= fs->n_fatent) { /* Check wrap-around */ 01576 ncl = 2; 01577 if (ncl > scl) return 0; /* No free cluster found? */ 01578 } 01579 cs = get_fat(obj, ncl); /* Get the cluster status */ 01580 if (cs == 0) break; /* Found a free cluster? */ 01581 if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* Test for error */ 01582 if (ncl == scl) return 0; /* No free cluster found? */ 01583 } 01584 } 01585 res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ 01586 if (res == FR_OK && clst != 0) { 01587 res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ 01588 } 01589 } 01590 01591 if (res == FR_OK) { /* Update FSINFO if function succeeded. */ 01592 fs->last_clst = ncl; 01593 if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; 01594 fs->fsi_flag |= 1; 01595 } else { 01596 ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ 01597 } 01598 01599 return ncl; /* Return new cluster number or error status */ 01600 } 01601 01602 #endif /* !FF_FS_READONLY */ 01603 01604 01605 01606 01607 #if FF_USE_FASTSEEK 01608 /*-----------------------------------------------------------------------*/ 01609 /* FAT handling - Convert offset into cluster with link map table */ 01610 /*-----------------------------------------------------------------------*/ 01611 01612 static 01613 DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ 01614 FIL* fp, /* Pointer to the file object */ 01615 FSIZE_t ofs /* File offset to be converted to cluster# */ 01616 ) 01617 { 01618 DWORD cl, ncl, *tbl; 01619 FATFS *fs = fp->obj.fs; 01620 01621 01622 tbl = fp->cltbl + 1; /* Top of CLMT */ 01623 cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ 01624 for (;;) { 01625 ncl = *tbl++; /* Number of cluters in the fragment */ 01626 if (ncl == 0) return 0; /* End of table? (error) */ 01627 if (cl < ncl) break; /* In this fragment? */ 01628 cl -= ncl; tbl++; /* Next fragment */ 01629 } 01630 return cl + *tbl; /* Return the cluster number */ 01631 } 01632 01633 #endif /* FF_USE_FASTSEEK */ 01634 01635 01636 01637 01638 /*-----------------------------------------------------------------------*/ 01639 /* Directory handling - Fill a cluster with zeros */ 01640 /*-----------------------------------------------------------------------*/ 01641 01642 #if !FF_FS_READONLY 01643 static 01644 FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ 01645 FATFS *fs, /* Filesystem object */ 01646 DWORD clst /* Directory table to clear */ 01647 ) 01648 { 01649 DWORD sect; 01650 UINT n, szb; 01651 BYTE *ibuf; 01652 01653 01654 if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ 01655 sect = clst2sect(fs, clst); /* Top of the cluster */ 01656 fs->winsect = sect; /* Set window to top of the cluster */ 01657 mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ 01658 #if FF_USE_LFN == 3 /* Quick table clear by using multi-secter write */ 01659 /* Allocate a temporary buffer */ 01660 for (szb = ((DWORD)fs->csize * SS(fs) >= MAX_MALLOC) ? MAX_MALLOC : fs->csize * SS(fs); szb > SS(fs) && !(ibuf = (BYTE *)ff_memalloc(szb)); szb /= 2) ; 01661 if (szb > SS(fs)) { /* Buffer allocated? */ 01662 mem_set(ibuf, 0, szb); 01663 szb /= SS(fs); /* Bytes -> Sectors */ 01664 for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ 01665 ff_memfree(ibuf); 01666 } else 01667 #endif 01668 { 01669 ibuf = fs->win; szb = 1; /* Use window buffer (single-sector writes may take a time) */ 01670 for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ 01671 } 01672 return (n == fs->csize) ? FR_OK : FR_DISK_ERR; 01673 } 01674 #endif /* !FF_FS_READONLY */ 01675 01676 01677 01678 01679 /*-----------------------------------------------------------------------*/ 01680 /* Directory handling - Set directory index */ 01681 /*-----------------------------------------------------------------------*/ 01682 01683 static 01684 FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ 01685 FATFS_DIR* dp, /* Pointer to directory object */ 01686 DWORD ofs /* Offset of directory table */ 01687 ) 01688 { 01689 DWORD csz, clst; 01690 FATFS *fs = dp->obj.fs; 01691 01692 01693 if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ 01694 return FR_INT_ERR; 01695 } 01696 dp->dptr = ofs; /* Set current offset */ 01697 clst = dp->obj.sclust; /* Table start cluster (0:root) */ 01698 if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ 01699 clst = fs->dirbase; 01700 if (FF_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ 01701 } 01702 01703 if (clst == 0) { /* Static table (root-directory on the FAT volume) */ 01704 if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ 01705 dp->sect = fs->dirbase; 01706 01707 } else { /* Dynamic table (sub-directory or root-directory on the FAT32/exFAT volume) */ 01708 csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ 01709 while (ofs >= csz) { /* Follow cluster chain */ 01710 clst = get_fat(&dp->obj, clst); /* Get next cluster */ 01711 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ 01712 if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ 01713 ofs -= csz; 01714 } 01715 dp->sect = clst2sect(fs, clst); 01716 } 01717 dp->clust = clst; /* Current cluster# */ 01718 if (dp->sect == 0) return FR_INT_ERR; 01719 dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ 01720 dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ 01721 01722 return FR_OK; 01723 } 01724 01725 01726 01727 01728 /*-----------------------------------------------------------------------*/ 01729 /* Directory handling - Move directory table index next */ 01730 /*-----------------------------------------------------------------------*/ 01731 01732 static 01733 FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ 01734 FATFS_DIR* dp, /* Pointer to the directory object */ 01735 int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ 01736 ) 01737 { 01738 DWORD ofs, clst; 01739 FATFS *fs = dp->obj.fs; 01740 01741 01742 ofs = dp->dptr + SZDIRE; /* Next entry */ 01743 if (ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) dp->sect = 0; /* Disable it if the offset reached the max value */ 01744 if (dp->sect == 0) return FR_NO_FILE; /* Report EOT if it has been disabled */ 01745 01746 if (ofs % SS(fs) == 0) { /* Sector changed? */ 01747 dp->sect++; /* Next sector */ 01748 01749 if (dp->clust == 0) { /* Static table */ 01750 if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ 01751 dp->sect = 0; return FR_NO_FILE; 01752 } 01753 } 01754 else { /* Dynamic table */ 01755 if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ 01756 clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ 01757 if (clst <= 1) return FR_INT_ERR; /* Internal error */ 01758 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ 01759 if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ 01760 #if !FF_FS_READONLY 01761 if (!stretch) { /* If no stretch, report EOT */ 01762 dp->sect = 0; return FR_NO_FILE; 01763 } 01764 clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ 01765 if (clst == 0) return FR_DENIED; /* No free cluster */ 01766 if (clst == 1) return FR_INT_ERR; /* Internal error */ 01767 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ 01768 if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ 01769 if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ 01770 #else 01771 if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ 01772 dp->sect = 0; return FR_NO_FILE; /* Report EOT */ 01773 #endif 01774 } 01775 dp->clust = clst; /* Initialize data for new cluster */ 01776 dp->sect = clst2sect(fs, clst); 01777 } 01778 } 01779 } 01780 dp->dptr = ofs; /* Current entry */ 01781 dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ 01782 01783 return FR_OK; 01784 } 01785 01786 01787 01788 01789 #if !FF_FS_READONLY 01790 /*-----------------------------------------------------------------------*/ 01791 /* Directory handling - Reserve a block of directory entries */ 01792 /*-----------------------------------------------------------------------*/ 01793 01794 static 01795 FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ 01796 FATFS_DIR* dp, /* Pointer to the directory object */ 01797 UINT nent /* Number of contiguous entries to allocate */ 01798 ) 01799 { 01800 FRESULT res; 01801 UINT n; 01802 FATFS *fs = dp->obj.fs; 01803 01804 01805 res = dir_sdi(dp, 0); 01806 if (res == FR_OK) { 01807 n = 0; 01808 do { 01809 res = move_window(fs, dp->sect); 01810 if (res != FR_OK) break; 01811 #if FF_FS_EXFAT 01812 if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { 01813 #else 01814 if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { 01815 #endif 01816 if (++n == nent) break; /* A block of contiguous free entries is found */ 01817 } else { 01818 n = 0; /* Not a blank entry. Restart to search */ 01819 } 01820 res = dir_next(dp, 1); 01821 } while (res == FR_OK); /* Next entry with table stretch enabled */ 01822 } 01823 01824 if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ 01825 return res; 01826 } 01827 01828 #endif /* !FF_FS_READONLY */ 01829 01830 01831 01832 01833 /*-----------------------------------------------------------------------*/ 01834 /* FAT: Directory handling - Load/Store start cluster number */ 01835 /*-----------------------------------------------------------------------*/ 01836 01837 static 01838 DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ 01839 FATFS* fs, /* Pointer to the fs object */ 01840 const BYTE* dir /* Pointer to the key entry */ 01841 ) 01842 { 01843 DWORD cl; 01844 01845 cl = ld_word(dir + DIR_FstClusLO); 01846 if (fs->fs_type == FS_FAT32) { 01847 cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; 01848 } 01849 01850 return cl; 01851 } 01852 01853 01854 #if !FF_FS_READONLY 01855 static 01856 void st_clust ( 01857 FATFS* fs, /* Pointer to the fs object */ 01858 BYTE* dir, /* Pointer to the key entry */ 01859 DWORD cl /* Value to be set */ 01860 ) 01861 { 01862 st_word(dir + DIR_FstClusLO, (WORD)cl); 01863 if (fs->fs_type == FS_FAT32) { 01864 st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); 01865 } 01866 } 01867 #endif 01868 01869 01870 01871 #if FF_USE_LFN 01872 /*--------------------------------------------------------*/ 01873 /* FAT-LFN: Compare a part of file name with an LFN entry */ 01874 /*--------------------------------------------------------*/ 01875 static 01876 int cmp_lfn ( /* 1:matched, 0:not matched */ 01877 const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ 01878 BYTE* dir /* Pointer to the directory entry containing the part of LFN */ 01879 ) 01880 { 01881 UINT i, s; 01882 WCHAR wc, uc; 01883 01884 01885 if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ 01886 01887 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ 01888 01889 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ 01890 uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ 01891 if (wc != 0) { 01892 if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ 01893 return 0; /* Not matched */ 01894 } 01895 wc = uc; 01896 } else { 01897 if (uc != 0xFFFF) return 0; /* Check filler */ 01898 } 01899 } 01900 01901 if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ 01902 01903 return 1; /* The part of LFN matched */ 01904 } 01905 01906 01907 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT 01908 /*-----------------------------------------------------*/ 01909 /* FAT-LFN: Pick a part of file name from an LFN entry */ 01910 /*-----------------------------------------------------*/ 01911 static 01912 int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ 01913 WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ 01914 BYTE* dir /* Pointer to the LFN entry */ 01915 ) 01916 { 01917 UINT i, s; 01918 WCHAR wc, uc; 01919 01920 01921 if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ 01922 01923 i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ 01924 01925 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ 01926 uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ 01927 if (wc != 0) { 01928 if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ 01929 lfnbuf[i++] = wc = uc; /* Store it */ 01930 } else { 01931 if (uc != 0xFFFF) return 0; /* Check filler */ 01932 } 01933 } 01934 01935 if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ 01936 if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ 01937 lfnbuf[i] = 0; 01938 } 01939 01940 return 1; /* The part of LFN is valid */ 01941 } 01942 #endif 01943 01944 01945 #if !FF_FS_READONLY 01946 /*-----------------------------------------*/ 01947 /* FAT-LFN: Create an entry of LFN entries */ 01948 /*-----------------------------------------*/ 01949 static 01950 void put_lfn ( 01951 const WCHAR* lfn, /* Pointer to the LFN */ 01952 BYTE* dir, /* Pointer to the LFN entry to be created */ 01953 BYTE ord, /* LFN order (1-20) */ 01954 BYTE sum /* Checksum of the corresponding SFN */ 01955 ) 01956 { 01957 UINT i, s; 01958 WCHAR wc; 01959 01960 01961 dir[LDIR_Chksum] = sum; /* Set checksum */ 01962 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ 01963 dir[LDIR_Type] = 0; 01964 st_word(dir + LDIR_FstClusLO, 0); 01965 01966 i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ 01967 s = wc = 0; 01968 do { 01969 if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ 01970 st_word(dir + LfnOfs[s], wc); /* Put it */ 01971 if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ 01972 } while (++s < 13); 01973 if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ 01974 dir[LDIR_Ord] = ord; /* Set the LFN order */ 01975 } 01976 01977 #endif /* !FF_FS_READONLY */ 01978 #endif /* FF_USE_LFN */ 01979 01980 01981 01982 #if FF_USE_LFN && !FF_FS_READONLY 01983 /*-----------------------------------------------------------------------*/ 01984 /* FAT-LFN: Create a Numbered SFN */ 01985 /*-----------------------------------------------------------------------*/ 01986 01987 static 01988 void gen_numname ( 01989 BYTE* dst, /* Pointer to the buffer to store numbered SFN */ 01990 const BYTE* src, /* Pointer to SFN */ 01991 const WCHAR* lfn, /* Pointer to LFN */ 01992 UINT seq /* Sequence number */ 01993 ) 01994 { 01995 BYTE ns[8], c; 01996 UINT i, j; 01997 WCHAR wc; 01998 DWORD sr; 01999 02000 02001 mem_cpy(dst, src, 11); 02002 02003 if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ 02004 sr = seq; 02005 while (*lfn) { /* Create a CRC */ 02006 wc = *lfn++; 02007 for (i = 0; i < 16; i++) { 02008 sr = (sr << 1) + (wc & 1); 02009 wc >>= 1; 02010 if (sr & 0x10000) sr ^= 0x11021; 02011 } 02012 } 02013 seq = (UINT)sr; 02014 } 02015 02016 /* itoa (hexdecimal) */ 02017 i = 7; 02018 do { 02019 c = (BYTE)((seq % 16) + '0'); 02020 if (c > '9') c += 7; 02021 ns[i--] = c; 02022 seq /= 16; 02023 } while (seq); 02024 ns[i] = '~'; 02025 02026 /* Append the number to the SFN body */ 02027 for (j = 0; j < i && dst[j] != ' '; j++) { 02028 if (dbc_1st(dst[j])) { 02029 if (j == i - 1) break; 02030 j++; 02031 } 02032 } 02033 do { 02034 dst[j++] = (i < 8) ? ns[i++] : ' '; 02035 } while (j < 8); 02036 } 02037 #endif /* FF_USE_LFN && !FF_FS_READONLY */ 02038 02039 02040 02041 #if FF_USE_LFN 02042 /*-----------------------------------------------------------------------*/ 02043 /* FAT-LFN: Calculate checksum of an SFN entry */ 02044 /*-----------------------------------------------------------------------*/ 02045 02046 static 02047 BYTE sum_sfn ( 02048 const BYTE* dir /* Pointer to the SFN entry */ 02049 ) 02050 { 02051 BYTE sum = 0; 02052 UINT n = 11; 02053 02054 do { 02055 sum = (sum >> 1) + (sum << 7) + *dir++; 02056 } while (--n); 02057 return sum; 02058 } 02059 02060 #endif /* FF_USE_LFN */ 02061 02062 02063 02064 #if FF_FS_EXFAT 02065 /*-----------------------------------------------------------------------*/ 02066 /* exFAT: Checksum */ 02067 /*-----------------------------------------------------------------------*/ 02068 02069 static 02070 WORD xdir_sum ( /* Get checksum of the directoly entry block */ 02071 const BYTE* dir /* Directory entry block to be calculated */ 02072 ) 02073 { 02074 UINT i, szblk; 02075 WORD sum; 02076 02077 02078 szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; 02079 for (i = sum = 0; i < szblk; i++) { 02080 if (i == XDIR_SetSum) { /* Skip sum field */ 02081 i++; 02082 } else { 02083 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; 02084 } 02085 } 02086 return sum; 02087 } 02088 02089 02090 02091 static 02092 WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ 02093 const WCHAR* name /* File name to be calculated */ 02094 ) 02095 { 02096 WCHAR chr; 02097 WORD sum = 0; 02098 02099 02100 while ((chr = *name++) != 0) { 02101 chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be upper-case converted */ 02102 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); 02103 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); 02104 } 02105 return sum; 02106 } 02107 02108 02109 #if !FF_FS_READONLY && FF_USE_MKFS 02110 static 02111 DWORD xsum32 ( 02112 BYTE dat, /* Byte to be calculated */ 02113 DWORD sum /* Previous sum */ 02114 ) 02115 { 02116 sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; 02117 return sum; 02118 } 02119 #endif 02120 02121 02122 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 02123 /*------------------------------------------------------*/ 02124 /* exFAT: Get object information from a directory block */ 02125 /*------------------------------------------------------*/ 02126 02127 static 02128 void get_xfileinfo ( 02129 BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ 02130 FILINFO* fno /* Buffer to store the extracted file information */ 02131 ) 02132 { 02133 WCHAR wc, hs; 02134 UINT di, si, nc; 02135 02136 /* Get file name from the entry block */ 02137 si = SZDIRE * 2; /* 1st C1 entry */ 02138 nc = hs = di = 0; 02139 while (nc < dirb[XDIR_NumName]) { 02140 if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ 02141 if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ 02142 wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ 02143 if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ 02144 hs = wc; continue; /* Get low surrogate */ 02145 } 02146 wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ 02147 if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ 02148 di += wc; 02149 hs = 0; 02150 } 02151 if (hs != 0) di = 0; /* Broken surrogate pair? */ 02152 if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ 02153 fno->fname[di] = 0; /* Terminate the name */ 02154 fno->altname[0] = 0; /* exFAT does not have SFN */ 02155 02156 fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ 02157 fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ 02158 fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ 02159 fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ 02160 } 02161 02162 #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ 02163 02164 02165 /*-----------------------------------*/ 02166 /* exFAT: Get a directry entry block */ 02167 /*-----------------------------------*/ 02168 02169 static 02170 FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ 02171 FATFS_DIR* dp /* Reading direcotry object pointing top of the entry block to load */ 02172 ) 02173 { 02174 FRESULT res; 02175 UINT i, sz_ent; 02176 BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ 02177 02178 02179 /* Load 85 entry */ 02180 res = move_window(dp->obj.fs, dp->sect); 02181 if (res != FR_OK) return res; 02182 if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */ 02183 mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); 02184 sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; 02185 if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; 02186 02187 /* Load C0 entry */ 02188 res = dir_next(dp, 0); 02189 if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ 02190 if (res != FR_OK) return res; 02191 res = move_window(dp->obj.fs, dp->sect); 02192 if (res != FR_OK) return res; 02193 if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */ 02194 mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); 02195 if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; 02196 02197 /* Load C1 entries */ 02198 i = 2 * SZDIRE; /* C1 offset to load */ 02199 do { 02200 res = dir_next(dp, 0); 02201 if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ 02202 if (res != FR_OK) return res; 02203 res = move_window(dp->obj.fs, dp->sect); 02204 if (res != FR_OK) return res; 02205 if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */ 02206 if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); 02207 } while ((i += SZDIRE) < sz_ent); 02208 02209 /* Sanity check (do it for only accessible object) */ 02210 if (i <= MAXDIRB(FF_MAX_LFN)) { 02211 if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; 02212 } 02213 return FR_OK; 02214 } 02215 02216 02217 /*------------------------------------------------------------------*/ 02218 /* exFAT: Initialize object allocation info with loaded entry block */ 02219 /*------------------------------------------------------------------*/ 02220 02221 static 02222 void init_alloc_info ( 02223 FATFS* fs, /* Filesystem object */ 02224 FFOBJID* obj /* Object allocation information to be initialized */ 02225 ) 02226 { 02227 obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ 02228 obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ 02229 obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ 02230 obj->n_frag = 0; /* No last fragment info */ 02231 } 02232 02233 02234 02235 #if !FF_FS_READONLY || FF_FS_RPATH != 0 02236 /*------------------------------------------------*/ 02237 /* exFAT: Load the object's directory entry block */ 02238 /*------------------------------------------------*/ 02239 static 02240 FRESULT load_obj_xdir ( 02241 FATFS_DIR* dp, /* Blank directory object to be used to access containing direcotry */ 02242 const FFOBJID* obj /* Object with its containing directory information */ 02243 ) 02244 { 02245 FRESULT res; 02246 02247 /* Open object containing directory */ 02248 dp->obj.fs = obj->fs; 02249 dp->obj.sclust = obj->c_scl; 02250 dp->obj.stat = (BYTE)obj->c_size; 02251 dp->obj.objsize = obj->c_size & 0xFFFFFF00; 02252 dp->obj.n_frag = 0; 02253 dp->blk_ofs = obj->c_ofs; 02254 02255 res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ 02256 if (res == FR_OK) { 02257 res = load_xdir(dp); /* Load the object's entry block */ 02258 } 02259 return res; 02260 } 02261 #endif 02262 02263 02264 #if !FF_FS_READONLY 02265 /*----------------------------------------*/ 02266 /* exFAT: Store the directory entry block */ 02267 /*----------------------------------------*/ 02268 static 02269 FRESULT store_xdir ( 02270 FATFS_DIR* dp /* Pointer to the direcotry object */ 02271 ) 02272 { 02273 FRESULT res; 02274 UINT nent; 02275 BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ 02276 02277 /* Create set sum */ 02278 st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); 02279 nent = dirb[XDIR_NumSec] + 1; 02280 02281 /* Store the direcotry entry block to the directory */ 02282 res = dir_sdi(dp, dp->blk_ofs); 02283 while (res == FR_OK) { 02284 res = move_window(dp->obj.fs, dp->sect); 02285 if (res != FR_OK) break; 02286 mem_cpy(dp->dir, dirb, SZDIRE); 02287 dp->obj.fs->wflag = 1; 02288 if (--nent == 0) break; 02289 dirb += SZDIRE; 02290 res = dir_next(dp, 0); 02291 } 02292 return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; 02293 } 02294 02295 02296 02297 /*-------------------------------------------*/ 02298 /* exFAT: Create a new directory enrty block */ 02299 /*-------------------------------------------*/ 02300 02301 static 02302 void create_xdir ( 02303 BYTE* dirb, /* Pointer to the direcotry entry block buffer */ 02304 const WCHAR* lfn /* Pointer to the object name */ 02305 ) 02306 { 02307 UINT i; 02308 BYTE nc1, nlen; 02309 WCHAR wc; 02310 02311 02312 /* Create 85,C0 entry */ 02313 mem_set(dirb, 0, 2 * SZDIRE); 02314 dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */ 02315 dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */ 02316 02317 /* Create C1 entries */ 02318 i = SZDIRE * 2; /* Top of C1 entries */ 02319 nlen = nc1 = 0; wc = 1; 02320 do { 02321 dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ 02322 do { /* Fill name field */ 02323 if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ 02324 st_word(dirb + i, wc); /* Store it */ 02325 i += 2; 02326 } while (i % SZDIRE != 0); 02327 nc1++; 02328 } while (lfn[nlen]); /* Fill next entry if any char follows */ 02329 02330 dirb[XDIR_NumName] = nlen; /* Set name length */ 02331 dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ 02332 st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ 02333 } 02334 02335 #endif /* !FF_FS_READONLY */ 02336 #endif /* FF_FS_EXFAT */ 02337 02338 02339 02340 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT 02341 /*-----------------------------------------------------------------------*/ 02342 /* Read an object from the directory */ 02343 /*-----------------------------------------------------------------------*/ 02344 02345 #define dir_read_file(dp) dir_read(dp, 0) 02346 #define dir_read_label(dp) dir_read(dp, 1) 02347 02348 static 02349 FRESULT dir_read ( 02350 FATFS_DIR* dp, /* Pointer to the directory object */ 02351 int vol /* Filtered by 0:file/directory or 1:volume label */ 02352 ) 02353 { 02354 FRESULT res = FR_NO_FILE; 02355 FATFS *fs = dp->obj.fs; 02356 BYTE a, c; 02357 #if FF_USE_LFN 02358 BYTE ord = 0xFF, sum = 0xFF; 02359 #endif 02360 02361 while (dp->sect) { 02362 res = move_window(fs, dp->sect); 02363 if (res != FR_OK) break; 02364 c = dp->dir[DIR_Name]; /* Test for the entry type */ 02365 if (c == 0) { 02366 res = FR_NO_FILE; break; /* Reached to end of the directory */ 02367 } 02368 #if FF_FS_EXFAT 02369 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02370 if (FF_USE_LABEL && vol) { 02371 if (c == 0x83) break; /* Volume label entry? */ 02372 } else { 02373 if (c == 0x85) { /* Start of the file entry block? */ 02374 dp->blk_ofs = dp->dptr; /* Get location of the block */ 02375 res = load_xdir(dp); /* Load the entry block */ 02376 if (res == FR_OK) { 02377 dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ 02378 } 02379 break; 02380 } 02381 } 02382 } else 02383 #endif 02384 { /* On the FAT/FAT32 volume */ 02385 dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ 02386 #if FF_USE_LFN /* LFN configuration */ 02387 if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ 02388 ord = 0xFF; 02389 } else { 02390 if (a == AM_LFN) { /* An LFN entry is found */ 02391 if (c & LLEF) { /* Is it start of an LFN sequence? */ 02392 sum = dp->dir[LDIR_Chksum]; 02393 c &= (BYTE)~LLEF; ord = c; 02394 dp->blk_ofs = dp->dptr; 02395 } 02396 /* Check LFN validity and capture it */ 02397 ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; 02398 } else { /* An SFN entry is found */ 02399 if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ 02400 dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ 02401 } 02402 break; 02403 } 02404 } 02405 #else /* Non LFN configuration */ 02406 if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ 02407 break; 02408 } 02409 #endif 02410 } 02411 res = dir_next(dp, 0); /* Next entry */ 02412 if (res != FR_OK) break; 02413 } 02414 02415 if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ 02416 return res; 02417 } 02418 02419 #endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ 02420 02421 02422 02423 /*-----------------------------------------------------------------------*/ 02424 /* Directory handling - Find an object in the directory */ 02425 /*-----------------------------------------------------------------------*/ 02426 02427 static 02428 FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ 02429 FATFS_DIR* dp /* Pointer to the directory object with the file name */ 02430 ) 02431 { 02432 FRESULT res; 02433 FATFS *fs = dp->obj.fs; 02434 BYTE c; 02435 #if FF_USE_LFN 02436 BYTE a, ord, sum; 02437 #endif 02438 02439 res = dir_sdi(dp, 0); /* Rewind directory object */ 02440 if (res != FR_OK) return res; 02441 #if FF_FS_EXFAT 02442 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02443 BYTE nc; 02444 UINT di, ni; 02445 WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ 02446 02447 while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */ 02448 #if FF_MAX_LFN < 255 02449 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ 02450 #endif 02451 if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ 02452 for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ 02453 if ((di % SZDIRE) == 0) di += 2; 02454 if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; 02455 } 02456 if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ 02457 } 02458 return res; 02459 } 02460 #endif 02461 /* On the FAT/FAT32 volume */ 02462 #if FF_USE_LFN 02463 ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ 02464 #endif 02465 do { 02466 res = move_window(fs, dp->sect); 02467 if (res != FR_OK) break; 02468 c = dp->dir[DIR_Name]; 02469 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ 02470 #if FF_USE_LFN /* LFN configuration */ 02471 dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; 02472 if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ 02473 ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ 02474 } else { 02475 if (a == AM_LFN) { /* An LFN entry is found */ 02476 if (!(dp->fn[NSFLAG] & NS_NOLFN)) { 02477 if (c & LLEF) { /* Is it start of LFN sequence? */ 02478 sum = dp->dir[LDIR_Chksum]; 02479 c &= (BYTE)~LLEF; ord = c; /* LFN start order */ 02480 dp->blk_ofs = dp->dptr; /* Start offset of LFN */ 02481 } 02482 /* Check validity of the LFN entry and compare it with given name */ 02483 ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; 02484 } 02485 } else { /* An SFN entry is found */ 02486 if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ 02487 if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ 02488 ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ 02489 } 02490 } 02491 #else /* Non LFN configuration */ 02492 dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; 02493 if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ 02494 #endif 02495 res = dir_next(dp, 0); /* Next entry */ 02496 } while (res == FR_OK); 02497 02498 return res; 02499 } 02500 02501 02502 02503 02504 #if !FF_FS_READONLY 02505 /*-----------------------------------------------------------------------*/ 02506 /* Register an object to the directory */ 02507 /*-----------------------------------------------------------------------*/ 02508 02509 static 02510 FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ 02511 FATFS_DIR* dp /* Target directory with object name to be created */ 02512 ) 02513 { 02514 FRESULT res; 02515 FATFS *fs = dp->obj.fs; 02516 #if FF_USE_LFN /* LFN configuration */ 02517 UINT n, nlen, nent; 02518 BYTE sn[12], sum; 02519 02520 02521 if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ 02522 for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ 02523 02524 #if FF_FS_EXFAT 02525 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02526 nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ 02527 res = dir_alloc(dp, nent); /* Allocate entries */ 02528 if (res != FR_OK) return res; 02529 dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ 02530 02531 if (dp->obj.stat & 4) { /* Has the directory been stretched? */ 02532 dp->obj.stat &= ~4; 02533 res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ 02534 if (res != FR_OK) return res; 02535 res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ 02536 if (res != FR_OK) return res; 02537 if (dp->obj.sclust != 0) { /* Is it a sub directory? */ 02538 FATFS_DIR dj; 02539 02540 res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ 02541 if (res != FR_OK) return res; 02542 dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ 02543 st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ 02544 st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); 02545 fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; 02546 res = store_xdir(&dj); /* Store the object status */ 02547 if (res != FR_OK) return res; 02548 } 02549 } 02550 02551 create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ 02552 return FR_OK; 02553 } 02554 #endif 02555 /* On the FAT/FAT32 volume */ 02556 mem_cpy(sn, dp->fn, 12); 02557 if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ 02558 dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ 02559 for (n = 1; n < 100; n++) { 02560 gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ 02561 res = dir_find(dp); /* Check if the name collides with existing SFN */ 02562 if (res != FR_OK) break; 02563 } 02564 if (n == 100) return FR_DENIED; /* Abort if too many collisions */ 02565 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ 02566 dp->fn[NSFLAG] = sn[NSFLAG]; 02567 } 02568 02569 /* Create an SFN with/without LFNs. */ 02570 nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ 02571 res = dir_alloc(dp, nent); /* Allocate entries */ 02572 if (res == FR_OK && --nent) { /* Set LFN entry if needed */ 02573 res = dir_sdi(dp, dp->dptr - nent * SZDIRE); 02574 if (res == FR_OK) { 02575 sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ 02576 do { /* Store LFN entries in bottom first */ 02577 res = move_window(fs, dp->sect); 02578 if (res != FR_OK) break; 02579 put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); 02580 fs->wflag = 1; 02581 res = dir_next(dp, 0); /* Next entry */ 02582 } while (res == FR_OK && --nent); 02583 } 02584 } 02585 02586 #else /* Non LFN configuration */ 02587 res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ 02588 02589 #endif 02590 02591 /* Set SFN entry */ 02592 if (res == FR_OK) { 02593 res = move_window(fs, dp->sect); 02594 if (res == FR_OK) { 02595 mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ 02596 mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ 02597 #if FF_USE_LFN 02598 dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ 02599 #endif 02600 fs->wflag = 1; 02601 } 02602 } 02603 02604 return res; 02605 } 02606 02607 #endif /* !FF_FS_READONLY */ 02608 02609 02610 02611 #if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 02612 /*-----------------------------------------------------------------------*/ 02613 /* Remove an object from the directory */ 02614 /*-----------------------------------------------------------------------*/ 02615 02616 static 02617 FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ 02618 FATFS_DIR* dp /* Directory object pointing the entry to be removed */ 02619 ) 02620 { 02621 FRESULT res; 02622 FATFS *fs = dp->obj.fs; 02623 #if FF_USE_LFN /* LFN configuration */ 02624 DWORD last = dp->dptr; 02625 02626 res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ 02627 if (res == FR_OK) { 02628 do { 02629 res = move_window(fs, dp->sect); 02630 if (res != FR_OK) break; 02631 if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02632 dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ 02633 } else { /* On the FAT/FAT32 volume */ 02634 dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ 02635 } 02636 fs->wflag = 1; 02637 if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ 02638 res = dir_next(dp, 0); /* Next entry */ 02639 } while (res == FR_OK); 02640 if (res == FR_NO_FILE) res = FR_INT_ERR; 02641 } 02642 #else /* Non LFN configuration */ 02643 02644 res = move_window(fs, dp->sect); 02645 if (res == FR_OK) { 02646 dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ 02647 fs->wflag = 1; 02648 } 02649 #endif 02650 02651 return res; 02652 } 02653 02654 #endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ 02655 02656 02657 02658 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 02659 /*-----------------------------------------------------------------------*/ 02660 /* Get file information from directory entry */ 02661 /*-----------------------------------------------------------------------*/ 02662 02663 static 02664 void get_fileinfo ( 02665 FATFS_DIR* dp, /* Pointer to the directory object */ 02666 FILINFO* fno /* Pointer to the file information to be filled */ 02667 ) 02668 { 02669 UINT si, di; 02670 #if FF_USE_LFN 02671 WCHAR wc, hs; 02672 FATFS *fs = dp->obj.fs; 02673 #else 02674 TCHAR c; 02675 #endif 02676 02677 02678 fno->fname[0] = 0; /* Invaidate file info */ 02679 if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ 02680 02681 #if FF_USE_LFN /* LFN configuration */ 02682 #if FF_FS_EXFAT 02683 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02684 get_xfileinfo(fs->dirbuf, fno); 02685 return; 02686 } else 02687 #endif 02688 { /* On the FAT/FAT32 volume */ 02689 if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ 02690 si = di = hs = 0; 02691 while (fs->lfnbuf[si] != 0) { 02692 wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ 02693 if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ 02694 hs = wc; continue; /* Get low surrogate */ 02695 } 02696 wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ 02697 if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ 02698 di += wc; 02699 hs = 0; 02700 } 02701 if (hs != 0) di = 0; /* Broken surrogate pair? */ 02702 fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ 02703 } 02704 } 02705 02706 si = di = 0; 02707 while (si < 11) { /* Get SFN from SFN entry */ 02708 wc = dp->dir[si++]; /* Get a char */ 02709 if (wc == ' ') continue; /* Skip padding spaces */ 02710 if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ 02711 if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ 02712 #if FF_LFN_UNICODE >= 1 /* Unicode output */ 02713 if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ 02714 wc = wc << 8 | dp->dir[si++]; 02715 } 02716 wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ 02717 if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ 02718 wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in UTF-16 or UTF-8 */ 02719 if (wc == 0) { di = 0; break; } /* Buffer overflow? */ 02720 di += wc; 02721 #else /* ANSI/OEM output */ 02722 fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ 02723 #endif 02724 } 02725 fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ 02726 02727 if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ 02728 if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ 02729 fno->fname[di++] = '?'; 02730 } else { 02731 for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ 02732 wc = (WCHAR)fno->altname[si]; 02733 if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; 02734 fno->fname[di] = (TCHAR)wc; 02735 } 02736 } 02737 fno->fname[di] = 0; /* Terminate the LFN */ 02738 if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ 02739 } 02740 02741 #else /* Non-LFN configuration */ 02742 si = di = 0; 02743 while (si < 11) { /* Copy name body and extension */ 02744 c = (TCHAR)dp->dir[si++]; 02745 if (c == ' ') continue; /* Skip padding spaces */ 02746 if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ 02747 if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ 02748 fno->fname[di++] = c; 02749 } 02750 fno->fname[di] = 0; 02751 #endif 02752 02753 fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ 02754 fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ 02755 fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ 02756 fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ 02757 } 02758 02759 #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ 02760 02761 02762 02763 #if FF_USE_FIND && FF_FS_MINIMIZE <= 1 02764 /*-----------------------------------------------------------------------*/ 02765 /* Pattern matching */ 02766 /*-----------------------------------------------------------------------*/ 02767 02768 static 02769 DWORD get_achar ( /* Get a character and advances ptr */ 02770 const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ 02771 ) 02772 { 02773 DWORD chr; 02774 02775 02776 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ 02777 chr = tchar2uni(ptr); 02778 if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ 02779 chr = ff_wtoupper(chr); 02780 02781 #else /* ANSI/OEM input */ 02782 chr = (BYTE)*(*ptr)++; /* Get a byte */ 02783 if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ 02784 #if FF_CODE_PAGE == 0 02785 if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ 02786 #elif FF_CODE_PAGE < 900 02787 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ 02788 #endif 02789 #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 02790 if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ 02791 chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; 02792 } 02793 #endif 02794 02795 #endif 02796 return chr; 02797 } 02798 02799 02800 static 02801 int pattern_matching ( /* 0:not matched, 1:matched */ 02802 const TCHAR* pat, /* Matching pattern */ 02803 const TCHAR* nam, /* String to be tested */ 02804 int skip, /* Number of pre-skip chars (number of ?s) */ 02805 int inf /* Infinite search (* specified) */ 02806 ) 02807 { 02808 const TCHAR *pp, *np; 02809 DWORD pc, nc; 02810 int nm, nx; 02811 02812 02813 while (skip--) { /* Pre-skip name chars */ 02814 if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ 02815 } 02816 if (*pat == 0 && inf) return 1; /* (short circuit) */ 02817 02818 do { 02819 pp = pat; np = nam; /* Top of pattern and name to match */ 02820 for (;;) { 02821 if (*pp == '?' || *pp == '*') { /* Wildcard? */ 02822 nm = nx = 0; 02823 do { /* Analyze the wildcard block */ 02824 if (*pp++ == '?') nm++; else nx = 1; 02825 } while (*pp == '?' || *pp == '*'); 02826 if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ 02827 nc = *np; break; /* Branch mismatched */ 02828 } 02829 pc = get_achar(&pp); /* Get a pattern char */ 02830 nc = get_achar(&np); /* Get a name char */ 02831 if (pc != nc) break; /* Branch mismatched? */ 02832 if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ 02833 } 02834 get_achar(&nam); /* nam++ */ 02835 } while (inf && nc); /* Retry until end of name if infinite search is specified */ 02836 02837 return 0; 02838 } 02839 02840 #endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ 02841 02842 02843 02844 /*-----------------------------------------------------------------------*/ 02845 /* Pick a top segment and create the object name in directory form */ 02846 /*-----------------------------------------------------------------------*/ 02847 02848 static 02849 FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ 02850 FATFS_DIR* dp, /* Pointer to the directory object */ 02851 const TCHAR** path /* Pointer to pointer to the segment in the path string */ 02852 ) 02853 { 02854 #if FF_USE_LFN /* LFN configuration */ 02855 BYTE b, cf; 02856 WCHAR wc, *lfn; 02857 DWORD uc; 02858 UINT i, ni, si, di; 02859 const TCHAR *p; 02860 02861 02862 /* Create LFN into LFN working buffer */ 02863 p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; 02864 for (;;) { 02865 uc = tchar2uni(&p); /* Get a character */ 02866 if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ 02867 if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ 02868 wc = (WCHAR)uc; 02869 if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ 02870 if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ 02871 if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ 02872 lfn[di++] = wc; /* Store the Unicode character */ 02873 } 02874 while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ 02875 *path = p; /* Return pointer to the next segment */ 02876 cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ 02877 02878 #if FF_FS_RPATH != 0 02879 if ((di == 1 && lfn[di - 1] == '.') || 02880 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ 02881 lfn[di] = 0; 02882 for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ 02883 dp->fn[i] = (i < di) ? '.' : ' '; 02884 } 02885 dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ 02886 return FR_OK; 02887 } 02888 #endif 02889 while (di) { /* Snip off trailing spaces and dots if exist */ 02890 wc = lfn[di - 1]; 02891 if (wc != ' ' && wc != '.') break; 02892 di--; 02893 } 02894 lfn[di] = 0; /* LFN is created into the working buffer */ 02895 if (di == 0) return FR_INVALID_NAME; /* Reject null name */ 02896 02897 /* Create SFN in directory form */ 02898 for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ 02899 if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ 02900 while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ 02901 02902 mem_set(dp->fn, ' ', 11); 02903 i = b = 0; ni = 8; 02904 for (;;) { 02905 wc = lfn[si++]; /* Get an LFN character */ 02906 if (wc == 0) break; /* Break on end of the LFN */ 02907 if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ 02908 cf |= NS_LOSS | NS_LFN; 02909 continue; 02910 } 02911 02912 if (i >= ni || si == di) { /* End of field? */ 02913 if (ni == 11) { /* Name extension overflow? */ 02914 cf |= NS_LOSS | NS_LFN; 02915 break; 02916 } 02917 if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ 02918 if (si > di) break; /* No name extension? */ 02919 si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ 02920 continue; 02921 } 02922 02923 if (wc >= 0x80) { /* Is this a non-ASCII character? */ 02924 cf |= NS_LFN; /* LFN entry needs to be created */ 02925 #if FF_CODE_PAGE == 0 02926 if (ExCvt) { /* At SBCS */ 02927 wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ 02928 if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ 02929 } else { /* At DBCS */ 02930 wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ 02931 } 02932 #elif FF_CODE_PAGE < 900 /* SBCS cfg */ 02933 wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ 02934 if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ 02935 #else /* DBCS cfg */ 02936 wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ 02937 #endif 02938 } 02939 02940 if (wc >= 0x100) { /* Is this a DBC? */ 02941 if (i >= ni - 1) { /* Field overflow? */ 02942 cf |= NS_LOSS | NS_LFN; 02943 i = ni; continue; /* Next field */ 02944 } 02945 dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ 02946 } else { /* SBC */ 02947 if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ 02948 wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ 02949 } else { 02950 if (IsUpper(wc)) { /* ASCII upper case? */ 02951 b |= 2; 02952 } 02953 if (IsLower(wc)) { /* ASCII lower case? */ 02954 b |= 1; wc -= 0x20; 02955 } 02956 } 02957 } 02958 dp->fn[i++] = (BYTE)wc; 02959 } 02960 02961 if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ 02962 02963 if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ 02964 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ 02965 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ 02966 if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ 02967 if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ 02968 } 02969 02970 dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ 02971 02972 return FR_OK; 02973 02974 02975 #else /* FF_USE_LFN : Non-LFN configuration */ 02976 BYTE c, d, *sfn; 02977 UINT ni, si, i; 02978 const char *p; 02979 02980 /* Create file name in directory form */ 02981 p = *path; sfn = dp->fn; 02982 mem_set(sfn, ' ', 11); 02983 si = i = 0; ni = 8; 02984 #if FF_FS_RPATH != 0 02985 if (p[si] == '.') { /* Is this a dot entry? */ 02986 for (;;) { 02987 c = (BYTE)p[si++]; 02988 if (c != '.' || si >= 3) break; 02989 sfn[i++] = c; 02990 } 02991 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; 02992 *path = p + si; /* Return pointer to the next segment */ 02993 sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ 02994 return FR_OK; 02995 } 02996 #endif 02997 for (;;) { 02998 c = (BYTE)p[si++]; /* Get a byte */ 02999 if (c <= ' ') break; /* Break if end of the path name */ 03000 if (c == '/' || c == '\\') { /* Break if a separator is found */ 03001 while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ 03002 break; 03003 } 03004 if (c == '.' || i >= ni) { /* End of body or field overflow? */ 03005 if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ 03006 i = 8; ni = 11; /* Enter file extension field */ 03007 continue; 03008 } 03009 #if FF_CODE_PAGE == 0 03010 if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ 03011 c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ 03012 } 03013 #elif FF_CODE_PAGE < 900 03014 if (c >= 0x80) { /* Is SBC extended character? */ 03015 c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ 03016 } 03017 #endif 03018 if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ 03019 d = (BYTE)p[si++]; /* Get 2nd byte */ 03020 if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ 03021 sfn[i++] = c; 03022 sfn[i++] = d; 03023 } else { /* SBC */ 03024 if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ 03025 if (IsLower(c)) c -= 0x20; /* To upper */ 03026 sfn[i++] = c; 03027 } 03028 } 03029 *path = p + si; /* Return pointer to the next segment */ 03030 if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ 03031 03032 if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ 03033 sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ 03034 03035 return FR_OK; 03036 #endif /* FF_USE_LFN */ 03037 } 03038 03039 03040 03041 03042 /*-----------------------------------------------------------------------*/ 03043 /* Follow a file path */ 03044 /*-----------------------------------------------------------------------*/ 03045 03046 static 03047 FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ 03048 FATFS_DIR* dp, /* Directory object to return last directory and found object */ 03049 const TCHAR* path /* Full-path string to find a file or directory */ 03050 ) 03051 { 03052 FRESULT res; 03053 BYTE ns; 03054 FATFS *fs = dp->obj.fs; 03055 03056 03057 #if FF_FS_RPATH != 0 03058 if (*path != '/' && *path != '\\') { /* Without heading separator */ 03059 dp->obj.sclust = fs->cdir; /* Start from current directory */ 03060 } else 03061 #endif 03062 { /* With heading separator */ 03063 while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ 03064 dp->obj.sclust = 0; /* Start from root directory */ 03065 } 03066 #if FF_FS_EXFAT 03067 dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ 03068 #if FF_FS_RPATH != 0 03069 if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ 03070 FATFS_DIR dj; 03071 03072 dp->obj.c_scl = fs->cdc_scl; 03073 dp->obj.c_size = fs->cdc_size; 03074 dp->obj.c_ofs = fs->cdc_ofs; 03075 res = load_obj_xdir(&dj, &dp->obj); 03076 if (res != FR_OK) return res; 03077 dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); 03078 dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; 03079 } 03080 #endif 03081 #endif 03082 03083 if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ 03084 dp->fn[NSFLAG] = NS_NONAME; 03085 res = dir_sdi(dp, 0); 03086 03087 } else { /* Follow path */ 03088 for (;;) { 03089 res = create_name(dp, &path); /* Get a segment name of the path */ 03090 if (res != FR_OK) break; 03091 res = dir_find(dp); /* Find an object with the segment name */ 03092 ns = dp->fn[NSFLAG]; 03093 if (res != FR_OK) { /* Failed to find the object */ 03094 if (res == FR_NO_FILE) { /* Object is not found */ 03095 if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ 03096 if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ 03097 dp->fn[NSFLAG] = NS_NONAME; 03098 res = FR_OK; 03099 } else { /* Could not find the object */ 03100 if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ 03101 } 03102 } 03103 break; 03104 } 03105 if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ 03106 /* Get into the sub-directory */ 03107 if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ 03108 res = FR_NO_PATH; break; 03109 } 03110 #if FF_FS_EXFAT 03111 if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ 03112 dp->obj.c_scl = dp->obj.sclust; 03113 dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; 03114 dp->obj.c_ofs = dp->blk_ofs; 03115 init_alloc_info(fs, &dp->obj); /* Open next directory */ 03116 } else 03117 #endif 03118 { 03119 dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ 03120 } 03121 } 03122 } 03123 03124 return res; 03125 } 03126 03127 03128 03129 03130 /*-----------------------------------------------------------------------*/ 03131 /* Get logical drive number from path name */ 03132 /*-----------------------------------------------------------------------*/ 03133 03134 static 03135 int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ 03136 const TCHAR** path /* Pointer to pointer to the path name */ 03137 ) 03138 { 03139 const TCHAR *tp, *tt; 03140 UINT i; 03141 int vol = -1; 03142 #if FF_STR_VOLUME_ID /* Find string drive id */ 03143 static const char* const volid[] = {FF_VOLUME_STRS}; 03144 const char *sp; 03145 char c; 03146 TCHAR tc; 03147 #endif 03148 03149 03150 if (*path != 0) { /* If the pointer is not a null */ 03151 for (tt = *path; (UINT)*tt >= (FF_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find a colon in the path */ 03152 if (*tt == ':') { /* If a colon is exist in the path name */ 03153 tp = *path; 03154 i = *tp++; 03155 if (IsDigit(i) && tp == tt) { /* Is there a numeric drive id + colon? */ 03156 if ((i -= '0') < FF_VOLUMES) { /* If drive id is found, get the value and strip it */ 03157 vol = (int)i; 03158 *path = ++tt; 03159 } 03160 } 03161 #if FF_STR_VOLUME_ID 03162 else { /* No numeric drive number, find string drive id */ 03163 i = 0; tt++; 03164 do { 03165 sp = volid[i]; tp = *path; 03166 do { /* Compare a string drive id with path name */ 03167 c = *sp++; tc = *tp++; 03168 if (IsLower(tc)) tc -= 0x20; 03169 } while (c && (TCHAR)c == tc); 03170 } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ 03171 if (i < FF_VOLUMES) { /* If a drive id is found, get the value and strip it */ 03172 vol = (int)i; 03173 *path = tt; 03174 } 03175 } 03176 #endif 03177 } else { /* No volume id and use default drive */ 03178 #if FF_FS_RPATH != 0 && FF_VOLUMES >= 2 03179 vol = CurrVol; /* Current drive */ 03180 #else 03181 vol = 0; /* Drive 0 */ 03182 #endif 03183 } 03184 } 03185 return vol; 03186 } 03187 03188 03189 03190 03191 /*-----------------------------------------------------------------------*/ 03192 /* Load a sector and check if it is an FAT VBR */ 03193 /*-----------------------------------------------------------------------*/ 03194 03195 static 03196 BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ 03197 FATFS* fs, /* Filesystem object */ 03198 DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ 03199 ) 03200 { 03201 fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ 03202 if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ 03203 03204 if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */ 03205 03206 #if FF_FS_EXFAT 03207 if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ 03208 #endif 03209 if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) { /* Valid JumpBoot code? */ 03210 if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0; /* Is it an FAT VBR? */ 03211 if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0; /* Is it an FAT32 VBR? */ 03212 } 03213 return 2; /* Valid BS but not FAT */ 03214 } 03215 03216 03217 03218 03219 /*-----------------------------------------------------------------------*/ 03220 /* Determine logical drive number and mount the volume if needed */ 03221 /*-----------------------------------------------------------------------*/ 03222 03223 static 03224 FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ 03225 const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ 03226 FATFS** rfs, /* Pointer to pointer to the found filesystem object */ 03227 BYTE mode /* !=0: Check write protection for write access */ 03228 ) 03229 { 03230 BYTE fmt, *pt; 03231 int vol; 03232 DSTATUS stat; 03233 DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; 03234 WORD nrsv; 03235 FATFS *fs; 03236 UINT i; 03237 03238 03239 /* Get logical drive number */ 03240 *rfs = 0; 03241 vol = get_ldnumber(path); 03242 if (vol < 0) return FR_INVALID_DRIVE; 03243 03244 /* Check if the filesystem object is valid or not */ 03245 fs = FatFs[vol]; /* Get pointer to the filesystem object */ 03246 if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ 03247 #if FF_FS_REENTRANT 03248 if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ 03249 #endif 03250 *rfs = fs; /* Return pointer to the filesystem object */ 03251 03252 mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ 03253 if (fs->fs_type != 0) { /* If the volume has been mounted */ 03254 stat = disk_status(fs->pdrv); 03255 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ 03256 if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ 03257 return FR_WRITE_PROTECTED; 03258 } 03259 return FR_OK; /* The filesystem object is valid */ 03260 } 03261 } 03262 03263 /* The filesystem object is not valid. */ 03264 /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ 03265 03266 fs->fs_type = 0; /* Clear the filesystem object */ 03267 fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ 03268 stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ 03269 if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ 03270 return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ 03271 } 03272 if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ 03273 return FR_WRITE_PROTECTED; 03274 } 03275 #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ 03276 if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; 03277 if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; 03278 #endif 03279 03280 #if FF_FS_HEAPBUF 03281 if (!fs->win) { 03282 fs->win = (BYTE*)ff_memalloc(SS(fs)); /* Allocate buffer to back window if necessary */ 03283 if (!fs->win) 03284 return FR_NOT_ENOUGH_CORE; 03285 } 03286 #endif 03287 03288 /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ 03289 bsect = 0; 03290 fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ 03291 if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ 03292 for (i = 0; i < 4; i++) { /* Get partition offset */ 03293 pt = fs->win + (MBR_Table + i * SZ_PTE); 03294 br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; 03295 } 03296 i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ 03297 if (i != 0) i--; 03298 do { /* Find an FAT volume */ 03299 bsect = br[i]; 03300 fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ 03301 } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); 03302 } 03303 if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ 03304 if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ 03305 03306 /* An FAT volume is found (bsect). Following code initializes the filesystem object */ 03307 03308 #if FF_FS_EXFAT 03309 if (fmt == 1) { 03310 QWORD maxlba; 03311 03312 for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ 03313 if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; 03314 03315 if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ 03316 03317 if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ 03318 return FR_NO_FILESYSTEM; 03319 } 03320 03321 maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ 03322 if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ 03323 03324 fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ 03325 03326 fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ 03327 if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ 03328 03329 fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ 03330 if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ 03331 03332 nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ 03333 if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ 03334 fs->n_fatent = nclst + 2; 03335 03336 /* Boundaries and Limits */ 03337 fs->volbase = bsect; 03338 fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); 03339 fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); 03340 if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ 03341 fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); 03342 03343 /* Check if bitmap location is in assumption (at the first cluster) */ 03344 if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; 03345 for (i = 0; i < SS(fs); i += SZDIRE) { 03346 if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ 03347 } 03348 if (i == SS(fs)) return FR_NO_FILESYSTEM; 03349 #if !FF_FS_READONLY 03350 fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ 03351 #endif 03352 fmt = FS_EXFAT; /* FAT sub-type */ 03353 } else 03354 #endif /* FF_FS_EXFAT */ 03355 { 03356 if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ 03357 03358 fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ 03359 if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); 03360 fs->fsize = fasize; 03361 03362 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ 03363 if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ 03364 fasize *= fs->n_fats; /* Number of sectors for FAT area */ 03365 03366 fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ 03367 if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ 03368 03369 fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ 03370 if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ 03371 03372 tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ 03373 if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); 03374 03375 nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ 03376 if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ 03377 03378 /* Determine the FAT sub type */ 03379 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + FATFS_DIR */ 03380 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 03381 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ 03382 if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 03383 fmt = 0; 03384 if (nclst <= MAX_FAT32) fmt = FS_FAT32; 03385 if (nclst <= MAX_FAT16) fmt = FS_FAT16; 03386 if (nclst <= MAX_FAT12) fmt = FS_FAT12; 03387 if (fmt == 0) return FR_NO_FILESYSTEM; 03388 03389 /* Boundaries and Limits */ 03390 fs->n_fatent = nclst + 2; /* Number of FAT entries */ 03391 fs->volbase = bsect; /* Volume start sector */ 03392 fs->fatbase = bsect + nrsv; /* FAT start sector */ 03393 fs->database = bsect + sysect; /* Data start sector */ 03394 if (fmt == FS_FAT32) { 03395 if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ 03396 if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ 03397 fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ 03398 szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ 03399 } else { 03400 if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ 03401 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ 03402 szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ 03403 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); 03404 } 03405 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ 03406 03407 #if !FF_FS_READONLY 03408 /* Get FSInfo if available */ 03409 fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ 03410 fs->fsi_flag = 0x80; 03411 #if (FF_FS_NOFSINFO & 3) != 3 03412 if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ 03413 && ld_word(fs->win + BPB_FSInfo32) == 1 03414 && move_window(fs, bsect + 1) == FR_OK) 03415 { 03416 fs->fsi_flag = 0; 03417 if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ 03418 && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 03419 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) 03420 { 03421 #if (FF_FS_NOFSINFO & 1) == 0 03422 fs->free_clst = ld_dword(fs->win + FSI_Free_Count); 03423 #endif 03424 #if (FF_FS_NOFSINFO & 2) == 0 03425 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); 03426 #endif 03427 } 03428 } 03429 #endif /* (FF_FS_NOFSINFO & 3) != 3 */ 03430 #endif /* !FF_FS_READONLY */ 03431 } 03432 03433 fs->fs_type = fmt; /* FAT sub-type */ 03434 fs->id = ++Fsid; /* Volume mount ID */ 03435 #if FF_USE_LFN == 1 03436 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ 03437 #if FF_FS_EXFAT 03438 fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ 03439 #endif 03440 #endif 03441 #if FF_FS_RPATH != 0 03442 fs->cdir = 0; /* Initialize current directory */ 03443 #endif 03444 #if FF_FS_LOCK != 0 /* Clear file lock semaphores */ 03445 clear_lock(fs); 03446 #endif 03447 return FR_OK; 03448 } 03449 03450 03451 03452 03453 /*-----------------------------------------------------------------------*/ 03454 /* Check if the file/directory object is valid or not */ 03455 /*-----------------------------------------------------------------------*/ 03456 03457 static 03458 FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ 03459 FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/FATFS_DIR object, to check validity */ 03460 FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ 03461 ) 03462 { 03463 FRESULT res = FR_INVALID_OBJECT; 03464 03465 03466 if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ 03467 #if FF_FS_REENTRANT 03468 if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ 03469 if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ 03470 res = FR_OK; 03471 } else { 03472 unlock_fs(obj->fs, FR_OK); 03473 } 03474 } else { 03475 res = FR_TIMEOUT; 03476 } 03477 #else 03478 if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ 03479 res = FR_OK; 03480 } 03481 #endif 03482 } 03483 *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ 03484 return res; 03485 } 03486 03487 03488 03489 03490 /*--------------------------------------------------------------------------- 03491 03492 Public Functions (FatFs API) 03493 03494 ----------------------------------------------------------------------------*/ 03495 03496 03497 03498 /*-----------------------------------------------------------------------*/ 03499 /* Mount/Unmount a Logical Drive */ 03500 /*-----------------------------------------------------------------------*/ 03501 03502 FRESULT f_mount ( 03503 FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ 03504 const TCHAR* path, /* Logical drive number to be mounted/unmounted */ 03505 BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ 03506 ) 03507 { 03508 FATFS *cfs; 03509 int vol; 03510 FRESULT res; 03511 const TCHAR *rp = path; 03512 03513 03514 /* Get logical drive number */ 03515 vol = get_ldnumber(&rp); 03516 if (vol < 0) return FR_INVALID_DRIVE; 03517 cfs = FatFs[vol]; /* Pointer to fs object */ 03518 03519 if (cfs) { 03520 #if FF_FS_LOCK != 0 03521 clear_lock(cfs); 03522 #endif 03523 #if FF_FS_REENTRANT /* Discard sync object of the current volume */ 03524 if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; 03525 #endif 03526 cfs->fs_type = 0; /* Clear old fs object */ 03527 #if FF_FS_HEAPBUF 03528 ff_memfree(cfs->win); /* Clean up window buffer */ 03529 #endif 03530 } 03531 03532 if (fs) { 03533 fs->fs_type = 0; /* Clear new fs object */ 03534 #if FF_FS_REENTRANT /* Create sync object for the new volume */ 03535 if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; 03536 #endif 03537 #if FF_FS_HEAPBUF 03538 fs->win = 0; /* NULL buffer to prevent use of uninitialized buffer */ 03539 #endif 03540 } 03541 FatFs[vol] = fs; /* Register new fs object */ 03542 03543 if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ 03544 03545 res = find_volume(&path, &fs, 0); /* Force mounted the volume */ 03546 LEAVE_FF(fs, res); 03547 } 03548 03549 03550 03551 03552 /*-----------------------------------------------------------------------*/ 03553 /* Open or Create a File */ 03554 /*-----------------------------------------------------------------------*/ 03555 03556 FRESULT f_open ( 03557 FIL* fp, /* Pointer to the blank file object */ 03558 const TCHAR* path, /* Pointer to the file name */ 03559 BYTE mode /* Access mode and file open mode flags */ 03560 ) 03561 { 03562 FRESULT res; 03563 FATFS_DIR dj; 03564 FATFS *fs; 03565 #if !FF_FS_READONLY 03566 DWORD dw, cl, bcs, clst, sc; 03567 FSIZE_t ofs; 03568 #endif 03569 DEF_NAMBUF 03570 03571 03572 if (!fp) return FR_INVALID_OBJECT; 03573 03574 /* Get logical drive */ 03575 mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; 03576 res = find_volume(&path, &fs, mode); 03577 if (res == FR_OK) { 03578 dj.obj.fs = fs; 03579 INIT_NAMBUF(fs); 03580 res = follow_path(&dj, path); /* Follow the file path */ 03581 #if !FF_FS_READONLY /* Read/Write configuration */ 03582 if (res == FR_OK) { 03583 if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ 03584 res = FR_INVALID_NAME; 03585 } 03586 #if FF_FS_LOCK != 0 03587 else { 03588 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ 03589 } 03590 #endif 03591 } 03592 /* Create or Open a file */ 03593 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { 03594 if (res != FR_OK) { /* No file, create new */ 03595 if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ 03596 #if FF_FS_LOCK != 0 03597 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; 03598 #else 03599 res = dir_register(&dj); 03600 #endif 03601 } 03602 mode |= FA_CREATE_ALWAYS; /* File is created */ 03603 } 03604 else { /* Any object with the same name is already existing */ 03605 if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or FATFS_DIR) */ 03606 res = FR_DENIED; 03607 } else { 03608 if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ 03609 } 03610 } 03611 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ 03612 #if FF_FS_EXFAT 03613 if (fs->fs_type == FS_EXFAT) { 03614 /* Get current allocation info */ 03615 fp->obj.fs = fs; 03616 init_alloc_info(fs, &fp->obj); 03617 /* Set directory entry block initial state */ 03618 mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ 03619 mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ 03620 fs->dirbuf[XDIR_Attr] = AM_ARC; 03621 st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); 03622 fs->dirbuf[XDIR_GenFlags] = 1; 03623 res = store_xdir(&dj); 03624 if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ 03625 res = remove_chain(&fp->obj, fp->obj.sclust, 0); 03626 fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ 03627 } 03628 } else 03629 #endif 03630 { 03631 /* Set directory entry initial state */ 03632 cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ 03633 st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ 03634 dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ 03635 st_clust(fs, dj.dir, 0); /* Reset file allocation info */ 03636 st_dword(dj.dir + DIR_FileSize, 0); 03637 fs->wflag = 1; 03638 if (cl != 0) { /* Remove the cluster chain if exist */ 03639 dw = fs->winsect; 03640 res = remove_chain(&dj.obj, cl, 0); 03641 if (res == FR_OK) { 03642 res = move_window(fs, dw); 03643 fs->last_clst = cl - 1; /* Reuse the cluster hole */ 03644 } 03645 } 03646 } 03647 } 03648 } 03649 else { /* Open an existing file */ 03650 if (res == FR_OK) { /* Is the object exsiting? */ 03651 if (dj.obj.attr & AM_DIR) { /* File open against a directory */ 03652 res = FR_NO_FILE; 03653 } else { 03654 if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ 03655 res = FR_DENIED; 03656 } 03657 } 03658 } 03659 } 03660 if (res == FR_OK) { 03661 if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ 03662 fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ 03663 fp->dir_ptr = dj.dir; 03664 #if FF_FS_LOCK != 0 03665 fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ 03666 if (fp->obj.lockid == 0) res = FR_INT_ERR; 03667 #endif 03668 } 03669 #else /* R/O configuration */ 03670 if (res == FR_OK) { 03671 if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ 03672 res = FR_INVALID_NAME; 03673 } else { 03674 if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ 03675 res = FR_NO_FILE; 03676 } 03677 } 03678 } 03679 #endif 03680 03681 if (res == FR_OK) { 03682 #if FF_FS_EXFAT 03683 if (fs->fs_type == FS_EXFAT) { 03684 fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ 03685 fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; 03686 fp->obj.c_ofs = dj.blk_ofs; 03687 init_alloc_info(fs, &fp->obj); 03688 } else 03689 #endif 03690 { 03691 fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ 03692 fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); 03693 } 03694 #if FF_USE_FASTSEEK 03695 fp->cltbl = 0; /* Disable fast seek mode */ 03696 #endif 03697 fp->obj.fs = fs; /* Validate the file object */ 03698 fp->obj.id = fs->id; 03699 fp->flag = mode; /* Set file access mode */ 03700 fp->err = 0; /* Clear error flag */ 03701 fp->sect = 0; /* Invalidate current data sector */ 03702 fp->fptr = 0; /* Set file pointer top of the file */ 03703 #if !FF_FS_READONLY 03704 #if !FF_FS_TINY 03705 #if FF_FS_HEAPBUF 03706 fp->buf = (BYTE*)ff_memalloc(SS(dj.obj.fs)); /* Allocate buffer if necessary */ 03707 if (!fp->buf) 03708 return FR_NOT_ENOUGH_CORE; 03709 #endif 03710 mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */ 03711 #endif 03712 if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ 03713 fp->fptr = fp->obj.objsize; /* Offset to seek */ 03714 bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ 03715 clst = fp->obj.sclust; /* Follow the cluster chain */ 03716 for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { 03717 clst = get_fat(&fp->obj, clst); 03718 if (clst <= 1) res = FR_INT_ERR; 03719 if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; 03720 } 03721 fp->clust = clst; 03722 if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ 03723 if ((sc = clst2sect(fs, clst)) == 0) { 03724 res = FR_INT_ERR; 03725 } else { 03726 fp->sect = sc + (DWORD)(ofs / SS(fs)); 03727 #if !FF_FS_TINY 03728 if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; 03729 #endif 03730 } 03731 } 03732 } 03733 #endif 03734 } 03735 03736 FREE_NAMBUF(); 03737 } 03738 03739 if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ 03740 03741 LEAVE_FF(fs, res); 03742 } 03743 03744 03745 03746 03747 /*-----------------------------------------------------------------------*/ 03748 /* Read File */ 03749 /*-----------------------------------------------------------------------*/ 03750 03751 FRESULT f_read ( 03752 FIL* fp, /* Pointer to the file object */ 03753 void* buff, /* Pointer to data buffer */ 03754 UINT btr, /* Number of bytes to read */ 03755 UINT* br /* Pointer to number of bytes read */ 03756 ) 03757 { 03758 FRESULT res; 03759 FATFS *fs; 03760 DWORD clst, sect; 03761 FSIZE_t remain; 03762 UINT rcnt, cc, csect; 03763 BYTE *rbuff = (BYTE*)buff; 03764 03765 03766 *br = 0; /* Clear read byte counter */ 03767 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 03768 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ 03769 if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 03770 remain = fp->obj.objsize - fp->fptr; 03771 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ 03772 03773 for ( ; btr; /* Repeat until all data read */ 03774 btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { 03775 if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ 03776 csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ 03777 if (csect == 0) { /* On the cluster boundary? */ 03778 if (fp->fptr == 0) { /* On the top of the file? */ 03779 clst = fp->obj.sclust; /* Follow cluster chain from the origin */ 03780 } else { /* Middle or end of the file */ 03781 #if FF_USE_FASTSEEK 03782 if (fp->cltbl) { 03783 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 03784 } else 03785 #endif 03786 { 03787 clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ 03788 } 03789 } 03790 if (clst < 2) ABORT(fs, FR_INT_ERR); 03791 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 03792 fp->clust = clst; /* Update current cluster */ 03793 } 03794 sect = clst2sect(fs, fp->clust); /* Get current sector */ 03795 if (sect == 0) ABORT(fs, FR_INT_ERR); 03796 sect += csect; 03797 cc = btr / SS(fs); /* When remaining bytes >= sector size, */ 03798 if (cc > 0) { /* Read maximum contiguous sectors directly */ 03799 if (csect + cc > fs->csize) { /* Clip at cluster boundary */ 03800 cc = fs->csize - csect; 03801 } 03802 if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); 03803 #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ 03804 #if FF_FS_TINY 03805 if (fs->wflag && fs->winsect - sect < cc) { 03806 mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); 03807 } 03808 #else 03809 if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { 03810 mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); 03811 } 03812 #endif 03813 #endif 03814 rcnt = SS(fs) * cc; /* Number of bytes transferred */ 03815 continue; 03816 } 03817 #if !FF_FS_TINY 03818 if (fp->sect != sect) { /* Load data sector if not in cache */ 03819 #if !FF_FS_READONLY 03820 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 03821 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 03822 fp->flag &= (BYTE)~FA_DIRTY; 03823 } 03824 #endif 03825 if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ 03826 } 03827 #endif 03828 fp->sect = sect; 03829 } 03830 rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ 03831 if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ 03832 #if FF_FS_TINY 03833 if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ 03834 mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ 03835 #else 03836 mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ 03837 #endif 03838 } 03839 03840 LEAVE_FF(fs, FR_OK); 03841 } 03842 03843 03844 03845 03846 #if !FF_FS_READONLY 03847 /*-----------------------------------------------------------------------*/ 03848 /* Write File */ 03849 /*-----------------------------------------------------------------------*/ 03850 03851 FRESULT f_write ( 03852 FIL* fp, /* Pointer to the file object */ 03853 const void* buff, /* Pointer to the data to be written */ 03854 UINT btw, /* Number of bytes to write */ 03855 UINT* bw /* Pointer to number of bytes written */ 03856 ) 03857 { 03858 FRESULT res; 03859 FATFS *fs; 03860 DWORD clst, sect; 03861 UINT wcnt, cc, csect; 03862 const BYTE *wbuff = (const BYTE*)buff; 03863 bool need_sync = false; 03864 03865 *bw = 0; /* Clear write byte counter */ 03866 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 03867 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ 03868 if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 03869 03870 /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ 03871 if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { 03872 btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); 03873 } 03874 03875 for ( ; btw; /* Repeat until all data written */ 03876 btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { 03877 if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ 03878 csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ 03879 if (csect == 0) { /* On the cluster boundary? */ 03880 if (fp->fptr == 0) { /* On the top of the file? */ 03881 clst = fp->obj.sclust; /* Follow from the origin */ 03882 if (clst == 0) { /* If no cluster is allocated, */ 03883 clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ 03884 } 03885 } else { /* On the middle or end of the file */ 03886 #if FF_USE_FASTSEEK 03887 if (fp->cltbl) { 03888 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 03889 } else 03890 #endif 03891 { 03892 clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ 03893 } 03894 } 03895 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ 03896 if (clst == 1) ABORT(fs, FR_INT_ERR); 03897 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 03898 fp->clust = clst; /* Update current cluster */ 03899 if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ 03900 #if FLUSH_ON_NEW_CLUSTER 03901 // We do not need to flush for the first cluster 03902 if (fp->fptr != 0) { 03903 need_sync = true; 03904 } 03905 #endif 03906 } 03907 #if FF_FS_TINY 03908 if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ 03909 #else 03910 if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ 03911 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 03912 fp->flag &= (BYTE)~FA_DIRTY; 03913 } 03914 #endif 03915 sect = clst2sect(fs, fp->clust); /* Get current sector */ 03916 if (sect == 0) ABORT(fs, FR_INT_ERR); 03917 sect += csect; 03918 cc = btw / SS(fs); /* When remaining bytes >= sector size, */ 03919 if (cc > 0) { /* Write maximum contiguous sectors directly */ 03920 if (csect + cc > fs->csize) { /* Clip at cluster boundary */ 03921 cc = fs->csize - csect; 03922 } 03923 if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); 03924 #if FF_FS_MINIMIZE <= 2 03925 #if FF_FS_TINY 03926 if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 03927 mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); 03928 fs->wflag = 0; 03929 } 03930 #else 03931 if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 03932 mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); 03933 fp->flag &= (BYTE)~FA_DIRTY; 03934 } 03935 #endif 03936 #endif 03937 wcnt = SS(fs) * cc; /* Number of bytes transferred */ 03938 #if FLUSH_ON_NEW_SECTOR 03939 need_sync = true; 03940 #endif 03941 continue; 03942 } 03943 #if FF_FS_TINY 03944 if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ 03945 if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); 03946 fs->winsect = sect; 03947 } 03948 #else 03949 if (fp->sect != sect && /* Fill sector cache with file data */ 03950 fp->fptr < fp->obj.objsize && 03951 disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { 03952 ABORT(fs, FR_DISK_ERR); 03953 } 03954 #endif 03955 fp->sect = sect; 03956 } 03957 wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ 03958 if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ 03959 #if FF_FS_TINY 03960 if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ 03961 mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ 03962 fs->wflag = 1; 03963 #else 03964 mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ 03965 fp->flag |= FA_DIRTY; 03966 #endif 03967 } 03968 03969 fp->flag |= FA_MODIFIED; /* Set file change flag */ 03970 03971 if (need_sync) { 03972 f_sync (fp); 03973 } 03974 03975 LEAVE_FF(fs, FR_OK); 03976 } 03977 03978 03979 03980 03981 /*-----------------------------------------------------------------------*/ 03982 /* Synchronize the File */ 03983 /*-----------------------------------------------------------------------*/ 03984 03985 FRESULT f_sync ( 03986 FIL* fp /* Pointer to the file object */ 03987 ) 03988 { 03989 FRESULT res; 03990 FATFS *fs; 03991 DWORD tm; 03992 BYTE *dir; 03993 03994 03995 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 03996 if (res == FR_OK) { 03997 if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ 03998 #if !FF_FS_TINY 03999 if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ 04000 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); 04001 fp->flag &= (BYTE)~FA_DIRTY; 04002 } 04003 #endif 04004 /* Update the directory entry */ 04005 tm = GET_FATTIME(); /* Modified time */ 04006 #if FF_FS_EXFAT 04007 if (fs->fs_type == FS_EXFAT) { 04008 res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ 04009 if (res == FR_OK) { 04010 res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ 04011 } 04012 if (res == FR_OK) { 04013 FATFS_DIR dj; 04014 DEF_NAMBUF 04015 04016 INIT_NAMBUF(fs); 04017 res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ 04018 if (res == FR_OK) { 04019 fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ 04020 fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ 04021 st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); 04022 st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); 04023 st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); 04024 st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ 04025 fs->dirbuf[XDIR_ModTime10] = 0; 04026 st_dword(fs->dirbuf + XDIR_AccTime, 0); 04027 res = store_xdir(&dj); /* Restore it to the directory */ 04028 if (res == FR_OK) { 04029 res = sync_fs(fs); 04030 fp->flag &= (BYTE)~FA_MODIFIED; 04031 } 04032 } 04033 FREE_NAMBUF(); 04034 } 04035 } else 04036 #endif 04037 { 04038 res = move_window(fs, fp->dir_sect); 04039 if (res == FR_OK) { 04040 dir = fp->dir_ptr; 04041 dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ 04042 st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ 04043 st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ 04044 st_dword(dir + DIR_ModTime, tm); /* Update modified time */ 04045 st_word(dir + DIR_LstAccDate, 0); 04046 fs->wflag = 1; 04047 res = sync_fs(fs); /* Restore it to the directory */ 04048 fp->flag &= (BYTE)~FA_MODIFIED; 04049 } 04050 } 04051 } 04052 } 04053 04054 LEAVE_FF(fs, res); 04055 } 04056 04057 #endif /* !FF_FS_READONLY */ 04058 04059 04060 04061 04062 /*-----------------------------------------------------------------------*/ 04063 /* Close File */ 04064 /*-----------------------------------------------------------------------*/ 04065 04066 FRESULT f_close ( 04067 FIL* fp /* Pointer to the file object to be closed */ 04068 ) 04069 { 04070 FRESULT res; 04071 FATFS *fs; 04072 04073 #if !FF_FS_READONLY 04074 res = f_sync(fp); /* Flush cached data */ 04075 if (res == FR_OK) 04076 #endif 04077 { 04078 res = validate(&fp->obj, &fs); /* Lock volume */ 04079 if (res == FR_OK) { 04080 #if FF_FS_LOCK != 0 04081 res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ 04082 if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ 04083 #else 04084 fp->obj.fs = 0; /* Invalidate file object */ 04085 #endif 04086 #if FF_FS_REENTRANT 04087 unlock_fs(fs, FR_OK); /* Unlock volume */ 04088 #endif 04089 #if !FF_FS_TINY && FF_FS_HEAPBUF 04090 ff_memfree(fp->buf); /* Deallocate buffer */ 04091 #endif 04092 } 04093 } 04094 return res; 04095 } 04096 04097 04098 04099 04100 #if FF_FS_RPATH >= 1 04101 /*-----------------------------------------------------------------------*/ 04102 /* Change Current Directory or Current Drive, Get Current Directory */ 04103 /*-----------------------------------------------------------------------*/ 04104 04105 #if FF_VOLUMES >= 2 04106 FRESULT f_chdrive ( 04107 const TCHAR* path /* Drive number */ 04108 ) 04109 { 04110 int vol; 04111 04112 04113 /* Get logical drive number */ 04114 vol = get_ldnumber(&path); 04115 if (vol < 0) return FR_INVALID_DRIVE; 04116 04117 CurrVol = (BYTE)vol; /* Set it as current volume */ 04118 04119 return FR_OK; 04120 } 04121 #endif 04122 04123 04124 FRESULT f_chdir ( 04125 const TCHAR* path /* Pointer to the directory path */ 04126 ) 04127 { 04128 FRESULT res; 04129 FATFS_DIR dj; 04130 FATFS *fs; 04131 DEF_NAMBUF 04132 04133 /* Get logical drive */ 04134 res = find_volume(&path, &fs, 0); 04135 if (res == FR_OK) { 04136 dj.obj.fs = fs; 04137 INIT_NAMBUF(fs); 04138 res = follow_path(&dj, path); /* Follow the path */ 04139 if (res == FR_OK) { /* Follow completed */ 04140 if (dj.fn[NSFLAG] & NS_NONAME) { 04141 fs->cdir = dj.obj.sclust; /* It is the start directory itself */ 04142 #if FF_FS_EXFAT 04143 if (fs->fs_type == FS_EXFAT) { 04144 fs->cdc_scl = dj.obj.c_scl; 04145 fs->cdc_size = dj.obj.c_size; 04146 fs->cdc_ofs = dj.obj.c_ofs; 04147 } 04148 #endif 04149 } else { 04150 if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ 04151 #if FF_FS_EXFAT 04152 if (fs->fs_type == FS_EXFAT) { 04153 fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ 04154 fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ 04155 fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; 04156 fs->cdc_ofs = dj.blk_ofs; 04157 } else 04158 #endif 04159 { 04160 fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ 04161 } 04162 } else { 04163 res = FR_NO_PATH; /* Reached but a file */ 04164 } 04165 } 04166 } 04167 FREE_NAMBUF(); 04168 if (res == FR_NO_FILE) res = FR_NO_PATH; 04169 } 04170 04171 LEAVE_FF(fs, res); 04172 } 04173 04174 04175 #if FF_FS_RPATH >= 2 04176 FRESULT f_getcwd ( 04177 TCHAR* buff, /* Pointer to the directory path */ 04178 UINT len /* Size of path */ 04179 ) 04180 { 04181 FRESULT res; 04182 FATFS_DIR dj; 04183 FATFS *fs; 04184 UINT i, n; 04185 DWORD ccl; 04186 TCHAR *tp; 04187 FILINFO fno; 04188 DEF_NAMBUF 04189 04190 04191 *buff = 0; 04192 /* Get logical drive */ 04193 res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ 04194 if (res == FR_OK) { 04195 dj.obj.fs = fs; 04196 INIT_NAMBUF(fs); 04197 i = len; /* Bottom of buffer (directory stack base) */ 04198 if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ 04199 dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ 04200 while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ 04201 res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ 04202 if (res != FR_OK) break; 04203 res = move_window(fs, dj.sect); 04204 if (res != FR_OK) break; 04205 dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ 04206 res = dir_sdi(&dj, 0); 04207 if (res != FR_OK) break; 04208 do { /* Find the entry links to the child directory */ 04209 res = dir_read_file(&dj); 04210 if (res != FR_OK) break; 04211 if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ 04212 res = dir_next(&dj, 0); 04213 } while (res == FR_OK); 04214 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ 04215 if (res != FR_OK) break; 04216 get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ 04217 for (n = 0; fno.fname[n]; n++) ; 04218 if (i < n + 3) { 04219 res = FR_NOT_ENOUGH_CORE; break; 04220 } 04221 while (n) buff[--i] = fno.fname[--n]; 04222 buff[--i] = '/'; 04223 } 04224 } 04225 tp = buff; 04226 if (res == FR_OK) { 04227 #if FF_VOLUMES >= 2 04228 *tp++ = '0' + CurrVol; /* Put drive number */ 04229 *tp++ = ':'; 04230 #endif 04231 if (i == len) { /* Root-directory */ 04232 *tp++ = '/'; 04233 } else { /* Sub-directroy */ 04234 do /* Add stacked path str */ 04235 *tp++ = buff[i++]; 04236 while (i < len); 04237 } 04238 } 04239 *tp = 0; 04240 FREE_NAMBUF(); 04241 } 04242 04243 LEAVE_FF(fs, res); 04244 } 04245 04246 #endif /* FF_FS_RPATH >= 2 */ 04247 #endif /* FF_FS_RPATH >= 1 */ 04248 04249 04250 04251 #if FF_FS_MINIMIZE <= 2 04252 /*-----------------------------------------------------------------------*/ 04253 /* Seek File Read/Write Pointer */ 04254 /*-----------------------------------------------------------------------*/ 04255 04256 FRESULT f_lseek ( 04257 FIL* fp, /* Pointer to the file object */ 04258 FSIZE_t ofs /* File pointer from top of file */ 04259 ) 04260 { 04261 FRESULT res; 04262 FATFS *fs; 04263 DWORD clst, bcs, nsect; 04264 FSIZE_t ifptr; 04265 #if FF_USE_FASTSEEK 04266 DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; 04267 #endif 04268 04269 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 04270 if (res == FR_OK) res = (FRESULT)fp->err; 04271 #if FF_FS_EXFAT && !FF_FS_READONLY 04272 if (res == FR_OK && fs->fs_type == FS_EXFAT) { 04273 res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ 04274 } 04275 #endif 04276 if (res != FR_OK) LEAVE_FF(fs, res); 04277 04278 #if FF_USE_FASTSEEK 04279 if (fp->cltbl) { /* Fast seek */ 04280 if (ofs == CREATE_LINKMAP) { /* Create CLMT */ 04281 tbl = fp->cltbl; 04282 tlen = *tbl++; ulen = 2; /* Given table size and required table size */ 04283 cl = fp->obj.sclust; /* Origin of the chain */ 04284 if (cl != 0) { 04285 do { 04286 /* Get a fragment */ 04287 tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ 04288 do { 04289 pcl = cl; ncl++; 04290 cl = get_fat(&fp->obj, cl); 04291 if (cl <= 1) ABORT(fs, FR_INT_ERR); 04292 if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 04293 } while (cl == pcl + 1); 04294 if (ulen <= tlen) { /* Store the length and top of the fragment */ 04295 *tbl++ = ncl; *tbl++ = tcl; 04296 } 04297 } while (cl < fs->n_fatent); /* Repeat until end of chain */ 04298 } 04299 *fp->cltbl = ulen; /* Number of items used */ 04300 if (ulen <= tlen) { 04301 *tbl = 0; /* Terminate table */ 04302 } else { 04303 res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ 04304 } 04305 } else { /* Fast seek */ 04306 if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ 04307 fp->fptr = ofs; /* Set file pointer */ 04308 if (ofs > 0) { 04309 fp->clust = clmt_clust(fp, ofs - 1); 04310 dsc = clst2sect(fs, fp->clust); 04311 if (dsc == 0) ABORT(fs, FR_INT_ERR); 04312 dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); 04313 if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ 04314 #if !FF_FS_TINY 04315 #if !FF_FS_READONLY 04316 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 04317 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 04318 fp->flag &= (BYTE)~FA_DIRTY; 04319 } 04320 #endif 04321 if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ 04322 #endif 04323 fp->sect = dsc; 04324 } 04325 } 04326 } 04327 } else 04328 #endif 04329 04330 /* Normal Seek */ 04331 { 04332 #if FF_FS_EXFAT 04333 if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ 04334 #endif 04335 if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ 04336 ofs = fp->obj.objsize; 04337 } 04338 ifptr = fp->fptr; 04339 fp->fptr = nsect = 0; 04340 if (ofs > 0) { 04341 bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ 04342 if (ifptr > 0 && 04343 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ 04344 fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ 04345 ofs -= fp->fptr; 04346 clst = fp->clust; 04347 } else { /* When seek to back cluster, */ 04348 clst = fp->obj.sclust; /* start from the first cluster */ 04349 #if !FF_FS_READONLY 04350 if (clst == 0) { /* If no cluster chain, create a new chain */ 04351 clst = create_chain(&fp->obj, 0); 04352 if (clst == 1) ABORT(fs, FR_INT_ERR); 04353 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 04354 fp->obj.sclust = clst; 04355 } 04356 #endif 04357 fp->clust = clst; 04358 } 04359 if (clst != 0) { 04360 while (ofs > bcs) { /* Cluster following loop */ 04361 ofs -= bcs; fp->fptr += bcs; 04362 #if !FF_FS_READONLY 04363 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ 04364 if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ 04365 fp->obj.objsize = fp->fptr; 04366 fp->flag |= FA_MODIFIED; 04367 } 04368 clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ 04369 if (clst == 0) { /* Clip file size in case of disk full */ 04370 ofs = 0; break; 04371 } 04372 } else 04373 #endif 04374 { 04375 clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ 04376 } 04377 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 04378 if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); 04379 fp->clust = clst; 04380 } 04381 fp->fptr += ofs; 04382 if (ofs % SS(fs)) { 04383 nsect = clst2sect(fs, clst); /* Current sector */ 04384 if (nsect == 0) ABORT(fs, FR_INT_ERR); 04385 nsect += (DWORD)(ofs / SS(fs)); 04386 } 04387 } 04388 } 04389 if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ 04390 fp->obj.objsize = fp->fptr; 04391 fp->flag |= FA_MODIFIED; 04392 } 04393 if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ 04394 #if !FF_FS_TINY 04395 #if !FF_FS_READONLY 04396 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 04397 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 04398 fp->flag &= (BYTE)~FA_DIRTY; 04399 } 04400 #endif 04401 if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ 04402 #endif 04403 fp->sect = nsect; 04404 } 04405 } 04406 04407 LEAVE_FF(fs, res); 04408 } 04409 04410 04411 04412 #if FF_FS_MINIMIZE <= 1 04413 /*-----------------------------------------------------------------------*/ 04414 /* Create a Directory Object */ 04415 /*-----------------------------------------------------------------------*/ 04416 04417 FRESULT f_opendir ( 04418 FATFS_DIR* dp, /* Pointer to directory object to create */ 04419 const TCHAR* path /* Pointer to the directory path */ 04420 ) 04421 { 04422 FRESULT res; 04423 FATFS *fs; 04424 DEF_NAMBUF 04425 04426 04427 if (!dp) return FR_INVALID_OBJECT; 04428 04429 /* Get logical drive */ 04430 res = find_volume(&path, &fs, 0); 04431 if (res == FR_OK) { 04432 dp->obj.fs = fs; 04433 INIT_NAMBUF(fs); 04434 res = follow_path(dp, path); /* Follow the path to the directory */ 04435 if (res == FR_OK) { /* Follow completed */ 04436 if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ 04437 if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ 04438 #if FF_FS_EXFAT 04439 if (fs->fs_type == FS_EXFAT) { 04440 dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ 04441 dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; 04442 dp->obj.c_ofs = dp->blk_ofs; 04443 init_alloc_info(fs, &dp->obj); /* Get object allocation info */ 04444 } else 04445 #endif 04446 { 04447 dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ 04448 } 04449 } else { /* This object is a file */ 04450 res = FR_NO_PATH; 04451 } 04452 } 04453 if (res == FR_OK) { 04454 dp->obj.id = fs->id; 04455 res = dir_sdi(dp, 0); /* Rewind directory */ 04456 #if FF_FS_LOCK != 0 04457 if (res == FR_OK) { 04458 if (dp->obj.sclust != 0) { 04459 dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ 04460 if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; 04461 } else { 04462 dp->obj.lockid = 0; /* Root directory need not to be locked */ 04463 } 04464 } 04465 #endif 04466 } 04467 } 04468 FREE_NAMBUF(); 04469 if (res == FR_NO_FILE) res = FR_NO_PATH; 04470 } 04471 if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ 04472 04473 LEAVE_FF(fs, res); 04474 } 04475 04476 04477 04478 04479 /*-----------------------------------------------------------------------*/ 04480 /* Close Directory */ 04481 /*-----------------------------------------------------------------------*/ 04482 04483 FRESULT f_closedir ( 04484 FATFS_DIR *dp /* Pointer to the directory object to be closed */ 04485 ) 04486 { 04487 FRESULT res; 04488 FATFS *fs; 04489 04490 04491 res = validate(&dp->obj, &fs); /* Check validity of the file object */ 04492 if (res == FR_OK) { 04493 #if FF_FS_LOCK != 0 04494 if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ 04495 if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ 04496 #else 04497 dp->obj.fs = 0; /* Invalidate directory object */ 04498 #endif 04499 #if FF_FS_REENTRANT 04500 unlock_fs(fs, FR_OK); /* Unlock volume */ 04501 #endif 04502 } 04503 return res; 04504 } 04505 04506 04507 04508 04509 /*-----------------------------------------------------------------------*/ 04510 /* Read Directory Entries in Sequence */ 04511 /*-----------------------------------------------------------------------*/ 04512 04513 FRESULT f_readdir ( 04514 FATFS_DIR* dp, /* Pointer to the open directory object */ 04515 FILINFO* fno /* Pointer to file information to return */ 04516 ) 04517 { 04518 FRESULT res; 04519 FATFS *fs; 04520 DEF_NAMBUF 04521 04522 04523 res = validate(&dp->obj, &fs); /* Check validity of the directory object */ 04524 if (res == FR_OK) { 04525 if (!fno) { 04526 res = dir_sdi(dp, 0); /* Rewind the directory object */ 04527 } else { 04528 INIT_NAMBUF(fs); 04529 res = dir_read_file(dp); /* Read an item */ 04530 if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ 04531 if (res == FR_OK) { /* A valid entry is found */ 04532 get_fileinfo(dp, fno); /* Get the object information */ 04533 res = dir_next(dp, 0); /* Increment index for next */ 04534 if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ 04535 } 04536 FREE_NAMBUF(); 04537 } 04538 } 04539 LEAVE_FF(fs, res); 04540 } 04541 04542 04543 04544 #if FF_USE_FIND 04545 /*-----------------------------------------------------------------------*/ 04546 /* Find Next File */ 04547 /*-----------------------------------------------------------------------*/ 04548 04549 FRESULT f_findnext ( 04550 FATFS_DIR* dp, /* Pointer to the open directory object */ 04551 FILINFO* fno /* Pointer to the file information structure */ 04552 ) 04553 { 04554 FRESULT res; 04555 04556 04557 for (;;) { 04558 res = f_readdir(dp, fno); /* Get a directory item */ 04559 if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ 04560 if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ 04561 #if FF_USE_LFN && FF_USE_FIND == 2 04562 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ 04563 #endif 04564 } 04565 return res; 04566 } 04567 04568 04569 04570 /*-----------------------------------------------------------------------*/ 04571 /* Find First File */ 04572 /*-----------------------------------------------------------------------*/ 04573 04574 FRESULT f_findfirst ( 04575 FATFS_DIR* dp, /* Pointer to the blank directory object */ 04576 FILINFO* fno, /* Pointer to the file information structure */ 04577 const TCHAR* path, /* Pointer to the directory to open */ 04578 const TCHAR* pattern /* Pointer to the matching pattern */ 04579 ) 04580 { 04581 FRESULT res; 04582 04583 04584 dp->pat = pattern; /* Save pointer to pattern string */ 04585 res = f_opendir(dp, path); /* Open the target directory */ 04586 if (res == FR_OK) { 04587 res = f_findnext(dp, fno); /* Find the first item */ 04588 } 04589 return res; 04590 } 04591 04592 #endif /* FF_USE_FIND */ 04593 04594 04595 04596 #if FF_FS_MINIMIZE == 0 04597 /*-----------------------------------------------------------------------*/ 04598 /* Get File Status */ 04599 /*-----------------------------------------------------------------------*/ 04600 04601 FRESULT f_stat ( 04602 const TCHAR* path, /* Pointer to the file path */ 04603 FILINFO* fno /* Pointer to file information to return */ 04604 ) 04605 { 04606 FRESULT res; 04607 FATFS_DIR dj; 04608 DEF_NAMBUF 04609 04610 04611 /* Get logical drive */ 04612 res = find_volume(&path, &dj.obj.fs, 0); 04613 if (res == FR_OK) { 04614 INIT_NAMBUF(dj.obj.fs); 04615 res = follow_path(&dj, path); /* Follow the file path */ 04616 if (res == FR_OK) { /* Follow completed */ 04617 if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ 04618 res = FR_INVALID_NAME; 04619 } else { /* Found an object */ 04620 if (fno) get_fileinfo(&dj, fno); 04621 } 04622 } 04623 FREE_NAMBUF(); 04624 } 04625 04626 LEAVE_FF(dj.obj.fs, res); 04627 } 04628 04629 04630 04631 #if !FF_FS_READONLY 04632 /*-----------------------------------------------------------------------*/ 04633 /* Get Number of Free Clusters */ 04634 /*-----------------------------------------------------------------------*/ 04635 04636 FRESULT f_getfree ( 04637 const TCHAR* path, /* Logical drive number */ 04638 DWORD* nclst, /* Pointer to a variable to return number of free clusters */ 04639 FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ 04640 ) 04641 { 04642 FRESULT res; 04643 FATFS *fs; 04644 DWORD nfree, clst, sect, stat; 04645 UINT i; 04646 FFOBJID obj; 04647 04648 04649 /* Get logical drive */ 04650 res = find_volume(&path, &fs, 0); 04651 if (res == FR_OK) { 04652 *fatfs = fs; /* Return ptr to the fs object */ 04653 /* If free_clst is valid, return it without full FAT scan */ 04654 if (fs->free_clst <= fs->n_fatent - 2) { 04655 *nclst = fs->free_clst; 04656 } else { 04657 /* Scan FAT to obtain number of free clusters */ 04658 nfree = 0; 04659 if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ 04660 clst = 2; obj.fs = fs; 04661 do { 04662 stat = get_fat(&obj, clst); 04663 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } 04664 if (stat == 1) { res = FR_INT_ERR; break; } 04665 if (stat == 0) nfree++; 04666 } while (++clst < fs->n_fatent); 04667 } else { 04668 #if FF_FS_EXFAT 04669 if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ 04670 BYTE bm; 04671 UINT b; 04672 04673 clst = fs->n_fatent - 2; /* Number of clusters */ 04674 sect = fs->database; /* Assuming bitmap starts at cluster 2 */ 04675 i = 0; /* Offset in the sector */ 04676 do { /* Counts numbuer of bits with zero in the bitmap */ 04677 if (i == 0) { 04678 res = move_window(fs, sect++); 04679 if (res != FR_OK) break; 04680 } 04681 for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { 04682 if (!(bm & 1)) nfree++; 04683 bm >>= 1; 04684 } 04685 i = (i + 1) % SS(fs); 04686 } while (clst); 04687 } else 04688 #endif 04689 { /* FAT16/32: Scan WORD/DWORD FAT entries */ 04690 clst = fs->n_fatent; /* Number of entries */ 04691 sect = fs->fatbase; /* Top of the FAT */ 04692 i = 0; /* Offset in the sector */ 04693 do { /* Counts numbuer of entries with zero in the FAT */ 04694 if (i == 0) { 04695 res = move_window(fs, sect++); 04696 if (res != FR_OK) break; 04697 } 04698 if (fs->fs_type == FS_FAT16) { 04699 if (ld_word(fs->win + i) == 0) nfree++; 04700 i += 2; 04701 } else { 04702 if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; 04703 i += 4; 04704 } 04705 i %= SS(fs); 04706 } while (--clst); 04707 } 04708 } 04709 *nclst = nfree; /* Return the free clusters */ 04710 fs->free_clst = nfree; /* Now free_clst is valid */ 04711 fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ 04712 } 04713 } 04714 04715 LEAVE_FF(fs, res); 04716 } 04717 04718 04719 04720 04721 /*-----------------------------------------------------------------------*/ 04722 /* Truncate File */ 04723 /*-----------------------------------------------------------------------*/ 04724 04725 FRESULT f_truncate ( 04726 FIL* fp /* Pointer to the file object */ 04727 ) 04728 { 04729 FRESULT res; 04730 FATFS *fs; 04731 DWORD ncl; 04732 04733 04734 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 04735 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); 04736 if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 04737 04738 if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ 04739 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ 04740 res = remove_chain(&fp->obj, fp->obj.sclust, 0); 04741 fp->obj.sclust = 0; 04742 } else { /* When truncate a part of the file, remove remaining clusters */ 04743 ncl = get_fat(&fp->obj, fp->clust); 04744 res = FR_OK; 04745 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; 04746 if (ncl == 1) res = FR_INT_ERR; 04747 if (res == FR_OK && ncl < fs->n_fatent) { 04748 res = remove_chain(&fp->obj, ncl, fp->clust); 04749 } 04750 } 04751 fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ 04752 fp->flag |= FA_MODIFIED; 04753 #if !FF_FS_TINY 04754 if (res == FR_OK && (fp->flag & FA_DIRTY)) { 04755 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { 04756 res = FR_DISK_ERR; 04757 } else { 04758 fp->flag &= (BYTE)~FA_DIRTY; 04759 } 04760 } 04761 #endif 04762 if (res != FR_OK) ABORT(fs, res); 04763 } 04764 04765 LEAVE_FF(fs, res); 04766 } 04767 04768 04769 04770 04771 /*-----------------------------------------------------------------------*/ 04772 /* Delete a File/Directory */ 04773 /*-----------------------------------------------------------------------*/ 04774 04775 FRESULT f_unlink ( 04776 const TCHAR* path /* Pointer to the file or directory path */ 04777 ) 04778 { 04779 FRESULT res; 04780 FATFS_DIR dj, sdj; 04781 DWORD dclst = 0; 04782 FATFS *fs; 04783 #if FF_FS_EXFAT 04784 FFOBJID obj; 04785 #endif 04786 DEF_NAMBUF 04787 04788 04789 /* Get logical drive */ 04790 res = find_volume(&path, &fs, FA_WRITE); 04791 if (res == FR_OK) { 04792 dj.obj.fs = fs; 04793 INIT_NAMBUF(fs); 04794 res = follow_path(&dj, path); /* Follow the file path */ 04795 if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { 04796 res = FR_INVALID_NAME; /* Cannot remove dot entry */ 04797 } 04798 #if FF_FS_LOCK != 0 04799 if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ 04800 #endif 04801 if (res == FR_OK) { /* The object is accessible */ 04802 if (dj.fn[NSFLAG] & NS_NONAME) { 04803 res = FR_INVALID_NAME; /* Cannot remove the origin directory */ 04804 } else { 04805 if (dj.obj.attr & AM_RDO) { 04806 res = FR_DENIED; /* Cannot remove R/O object */ 04807 } 04808 } 04809 if (res == FR_OK) { 04810 #if FF_FS_EXFAT 04811 obj.fs = fs; 04812 if (fs->fs_type == FS_EXFAT) { 04813 init_alloc_info(fs, &obj); 04814 dclst = obj.sclust; 04815 } else 04816 #endif 04817 { 04818 dclst = ld_clust(fs, dj.dir); 04819 } 04820 if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ 04821 #if FF_FS_RPATH != 0 04822 if (dclst == fs->cdir) { /* Is it the current directory? */ 04823 res = FR_DENIED; 04824 } else 04825 #endif 04826 { 04827 sdj.obj.fs = fs; /* Open the sub-directory */ 04828 sdj.obj.sclust = dclst; 04829 #if FF_FS_EXFAT 04830 if (fs->fs_type == FS_EXFAT) { 04831 sdj.obj.objsize = obj.objsize; 04832 sdj.obj.stat = obj.stat; 04833 } 04834 #endif 04835 res = dir_sdi(&sdj, 0); 04836 if (res == FR_OK) { 04837 res = dir_read_file(&sdj); /* Test if the directory is empty */ 04838 if (res == FR_OK) res = FR_DENIED; /* Not empty? */ 04839 if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ 04840 } 04841 } 04842 } 04843 } 04844 if (res == FR_OK) { 04845 res = dir_remove(&dj); /* Remove the directory entry */ 04846 if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ 04847 #if FF_FS_EXFAT 04848 res = remove_chain(&obj, dclst, 0); 04849 #else 04850 res = remove_chain(&dj.obj, dclst, 0); 04851 #endif 04852 } 04853 if (res == FR_OK) res = sync_fs(fs); 04854 } 04855 } 04856 FREE_NAMBUF(); 04857 } 04858 04859 LEAVE_FF(fs, res); 04860 } 04861 04862 04863 04864 04865 /*-----------------------------------------------------------------------*/ 04866 /* Create a Directory */ 04867 /*-----------------------------------------------------------------------*/ 04868 04869 FRESULT f_mkdir ( 04870 const TCHAR* path /* Pointer to the directory path */ 04871 ) 04872 { 04873 FRESULT res; 04874 FATFS_DIR dj; 04875 FATFS *fs; 04876 BYTE *dir; 04877 DWORD dcl, pcl, tm; 04878 DEF_NAMBUF 04879 04880 04881 /* Get logical drive */ 04882 res = find_volume(&path, &fs, FA_WRITE); 04883 if (res == FR_OK) { 04884 dj.obj.fs = fs; 04885 INIT_NAMBUF(fs); 04886 res = follow_path(&dj, path); /* Follow the file path */ 04887 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ 04888 if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { 04889 res = FR_INVALID_NAME; 04890 } 04891 if (res == FR_NO_FILE) { /* Can create a new directory */ 04892 dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ 04893 dj.obj.objsize = (DWORD)fs->csize * SS(fs); 04894 res = FR_OK; 04895 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ 04896 if (dcl == 1) res = FR_INT_ERR; 04897 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; 04898 if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ 04899 tm = GET_FATTIME(); 04900 if (res == FR_OK) { /* Initialize the new directory table */ 04901 res = dir_clear(fs, dcl); /* Clean up the new table */ 04902 if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */ 04903 dir = fs->win; 04904 mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ 04905 dir[DIR_Name] = '.'; 04906 dir[DIR_Attr] = AM_DIR; 04907 st_dword(dir + DIR_ModTime, tm); 04908 st_clust(fs, dir, dcl); 04909 mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ 04910 dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; 04911 st_clust(fs, dir + SZDIRE, pcl); 04912 fs->wflag = 1; 04913 } 04914 } 04915 if (res == FR_OK) { 04916 res = dir_register(&dj); /* Register the object to the directoy */ 04917 } 04918 if (res == FR_OK) { 04919 #if FF_FS_EXFAT 04920 if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ 04921 st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ 04922 st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ 04923 st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ 04924 st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); 04925 fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ 04926 fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ 04927 res = store_xdir(&dj); 04928 } else 04929 #endif 04930 { 04931 dir = dj.dir; 04932 st_dword(dir + DIR_ModTime, tm); /* Created time */ 04933 st_clust(fs, dir, dcl); /* Table start cluster */ 04934 dir[DIR_Attr] = AM_DIR; /* Attribute */ 04935 fs->wflag = 1; 04936 } 04937 if (res == FR_OK) { 04938 res = sync_fs(fs); 04939 } 04940 } else { 04941 remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ 04942 } 04943 } 04944 FREE_NAMBUF(); 04945 } 04946 04947 LEAVE_FF(fs, res); 04948 } 04949 04950 04951 04952 04953 /*-----------------------------------------------------------------------*/ 04954 /* Rename a File/Directory */ 04955 /*-----------------------------------------------------------------------*/ 04956 04957 FRESULT f_rename ( 04958 const TCHAR* path_old, /* Pointer to the object name to be renamed */ 04959 const TCHAR* path_new /* Pointer to the new name */ 04960 ) 04961 { 04962 FRESULT res; 04963 FATFS_DIR djo, djn; 04964 FATFS *fs; 04965 BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; 04966 DWORD dw; 04967 DEF_NAMBUF 04968 04969 04970 get_ldnumber(&path_new); /* Snip the drive number of new name off */ 04971 res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ 04972 if (res == FR_OK) { 04973 djo.obj.fs = fs; 04974 INIT_NAMBUF(fs); 04975 res = follow_path(&djo, path_old); /* Check old object */ 04976 if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ 04977 #if FF_FS_LOCK != 0 04978 if (res == FR_OK) { 04979 res = chk_lock(&djo, 2); 04980 } 04981 #endif 04982 if (res == FR_OK) { /* Object to be renamed is found */ 04983 #if FF_FS_EXFAT 04984 if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ 04985 BYTE nf, nn; 04986 WORD nh; 04987 04988 mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ 04989 mem_cpy(&djn, &djo, sizeof djo); 04990 res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ 04991 if (res == FR_OK) { /* Is new name already in use by any other object? */ 04992 res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; 04993 } 04994 if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ 04995 res = dir_register(&djn); /* Register the new entry */ 04996 if (res == FR_OK) { 04997 nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; 04998 nh = ld_word(fs->dirbuf + XDIR_NameHash); 04999 mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ 05000 fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; 05001 st_word(fs->dirbuf + XDIR_NameHash, nh); 05002 if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ 05003 /* Start of critical section where an interruption can cause a cross-link */ 05004 res = store_xdir(&djn); 05005 } 05006 } 05007 } else 05008 #endif 05009 { /* At FAT/FAT32 volume */ 05010 mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ 05011 mem_cpy(&djn, &djo, sizeof (FATFS_DIR)); /* Duplicate the directory object */ 05012 res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ 05013 if (res == FR_OK) { /* Is new name already in use by any other object? */ 05014 res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; 05015 } 05016 if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ 05017 res = dir_register(&djn); /* Register the new entry */ 05018 if (res == FR_OK) { 05019 dir = djn.dir; /* Copy directory entry of the object except name */ 05020 mem_cpy(dir + 13, buf + 13, SZDIRE - 13); 05021 dir[DIR_Attr] = buf[DIR_Attr]; 05022 if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ 05023 fs->wflag = 1; 05024 if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ 05025 dw = clst2sect(fs, ld_clust(fs, dir)); 05026 if (dw == 0) { 05027 res = FR_INT_ERR; 05028 } else { 05029 /* Start of critical section where an interruption can cause a cross-link */ 05030 res = move_window(fs, dw); 05031 dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ 05032 if (res == FR_OK && dir[1] == '.') { 05033 st_clust(fs, dir, djn.obj.sclust); 05034 fs->wflag = 1; 05035 } 05036 } 05037 } 05038 } 05039 } 05040 } 05041 if (res == FR_OK) { 05042 res = dir_remove(&djo); /* Remove old entry */ 05043 if (res == FR_OK) { 05044 res = sync_fs(fs); 05045 } 05046 } 05047 /* End of the critical section */ 05048 } 05049 FREE_NAMBUF(); 05050 } 05051 05052 LEAVE_FF(fs, res); 05053 } 05054 05055 #endif /* !FF_FS_READONLY */ 05056 #endif /* FF_FS_MINIMIZE == 0 */ 05057 #endif /* FF_FS_MINIMIZE <= 1 */ 05058 #endif /* FF_FS_MINIMIZE <= 2 */ 05059 05060 05061 05062 #if FF_USE_CHMOD && !FF_FS_READONLY 05063 /*-----------------------------------------------------------------------*/ 05064 /* Change Attribute */ 05065 /*-----------------------------------------------------------------------*/ 05066 05067 FRESULT f_chmod ( 05068 const TCHAR* path, /* Pointer to the file path */ 05069 BYTE attr, /* Attribute bits */ 05070 BYTE mask /* Attribute mask to change */ 05071 ) 05072 { 05073 FRESULT res; 05074 FATFS_DIR dj; 05075 FATFS *fs; 05076 DEF_NAMBUF 05077 05078 05079 res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ 05080 if (res == FR_OK) { 05081 dj.obj.fs = fs; 05082 INIT_NAMBUF(fs); 05083 res = follow_path(&dj, path); /* Follow the file path */ 05084 if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ 05085 if (res == FR_OK) { 05086 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ 05087 #if FF_FS_EXFAT 05088 if (fs->fs_type == FS_EXFAT) { 05089 fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ 05090 res = store_xdir(&dj); 05091 } else 05092 #endif 05093 { 05094 dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ 05095 fs->wflag = 1; 05096 } 05097 if (res == FR_OK) { 05098 res = sync_fs(fs); 05099 } 05100 } 05101 FREE_NAMBUF(); 05102 } 05103 05104 LEAVE_FF(fs, res); 05105 } 05106 05107 05108 05109 05110 /*-----------------------------------------------------------------------*/ 05111 /* Change Timestamp */ 05112 /*-----------------------------------------------------------------------*/ 05113 05114 FRESULT f_utime ( 05115 const TCHAR* path, /* Pointer to the file/directory name */ 05116 const FILINFO* fno /* Pointer to the timestamp to be set */ 05117 ) 05118 { 05119 FRESULT res; 05120 FATFS_DIR dj; 05121 FATFS *fs; 05122 DEF_NAMBUF 05123 05124 05125 res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ 05126 if (res == FR_OK) { 05127 dj.obj.fs = fs; 05128 INIT_NAMBUF(fs); 05129 res = follow_path(&dj, path); /* Follow the file path */ 05130 if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ 05131 if (res == FR_OK) { 05132 #if FF_FS_EXFAT 05133 if (fs->fs_type == FS_EXFAT) { 05134 st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); 05135 res = store_xdir(&dj); 05136 } else 05137 #endif 05138 { 05139 st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); 05140 fs->wflag = 1; 05141 } 05142 if (res == FR_OK) { 05143 res = sync_fs(fs); 05144 } 05145 } 05146 FREE_NAMBUF(); 05147 } 05148 05149 LEAVE_FF(fs, res); 05150 } 05151 05152 #endif /* FF_USE_CHMOD && !FF_FS_READONLY */ 05153 05154 05155 05156 #if FF_USE_LABEL 05157 /*-----------------------------------------------------------------------*/ 05158 /* Get Volume Label */ 05159 /*-----------------------------------------------------------------------*/ 05160 05161 FRESULT f_getlabel ( 05162 const TCHAR* path, /* Logical drive number */ 05163 TCHAR* label, /* Buffer to store the volume label */ 05164 DWORD* vsn /* Variable to store the volume serial number */ 05165 ) 05166 { 05167 FRESULT res; 05168 FATFS_DIR dj; 05169 FATFS *fs; 05170 UINT si, di; 05171 WCHAR wc; 05172 05173 /* Get logical drive */ 05174 res = find_volume(&path, &fs, 0); 05175 05176 /* Get volume label */ 05177 if (res == FR_OK && label) { 05178 dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ 05179 res = dir_sdi(&dj, 0); 05180 if (res == FR_OK) { 05181 res = dir_read_label(&dj); /* Find a volume label entry */ 05182 if (res == FR_OK) { 05183 #if FF_FS_EXFAT 05184 if (fs->fs_type == FS_EXFAT) { 05185 WCHAR hs; 05186 05187 for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ 05188 wc = ld_word(dj.dir + XDIR_Label + si * 2); 05189 if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ 05190 hs = wc; continue; 05191 } 05192 wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); 05193 if (wc == 0) { di = 0; break; } 05194 di += wc; 05195 hs = 0; 05196 } 05197 if (hs != 0) di = 0; /* Broken surrogate pair? */ 05198 label[di] = 0; 05199 } else 05200 #endif 05201 { 05202 si = di = 0; /* Extract volume label from AM_VOL entry */ 05203 while (si < 11) { 05204 wc = dj.dir[si++]; 05205 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ 05206 if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ 05207 wc = ff_oem2uni(wc, CODEPAGE); 05208 if (wc != 0) wc = put_utf(wc, &label[di], 4); 05209 if (wc == 0) { di = 0; break; } 05210 di += wc; 05211 #else /* ANSI/OEM output */ 05212 label[di++] = (TCHAR)wc; 05213 #endif 05214 } 05215 do { /* Truncate trailing spaces */ 05216 label[di] = 0; 05217 if (di == 0) break; 05218 } while (label[--di] == ' '); 05219 } 05220 } 05221 } 05222 if (res == FR_NO_FILE) { /* No label entry and return nul string */ 05223 label[0] = 0; 05224 res = FR_OK; 05225 } 05226 } 05227 05228 /* Get volume serial number */ 05229 if (res == FR_OK && vsn) { 05230 res = move_window(fs, fs->volbase); 05231 if (res == FR_OK) { 05232 switch (fs->fs_type) { 05233 case FS_EXFAT: 05234 di = BPB_VolIDEx; break; 05235 05236 case FS_FAT32: 05237 di = BS_VolID32; break; 05238 05239 default: 05240 di = BS_VolID; 05241 } 05242 *vsn = ld_dword(fs->win + di); 05243 } 05244 } 05245 05246 LEAVE_FF(fs, res); 05247 } 05248 05249 05250 05251 #if !FF_FS_READONLY 05252 /*-----------------------------------------------------------------------*/ 05253 /* Set Volume Label */ 05254 /*-----------------------------------------------------------------------*/ 05255 05256 FRESULT f_setlabel ( 05257 const TCHAR* label /* Volume label to set with heading logical drive number */ 05258 ) 05259 { 05260 FRESULT res; 05261 FATFS_DIR dj; 05262 FATFS *fs; 05263 BYTE dirvn[22]; 05264 UINT di; 05265 WCHAR wc; 05266 static const char badchr[] = "+.,;=[]\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ 05267 #if FF_USE_LFN 05268 DWORD dc; 05269 #endif 05270 05271 /* Get logical drive */ 05272 res = find_volume(&label, &fs, FA_WRITE); 05273 if (res != FR_OK) LEAVE_FF(fs, res); 05274 05275 #if FF_FS_EXFAT 05276 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 05277 mem_set(dirvn, 0, 22); 05278 di = 0; 05279 while (*label) { /* Create volume label in directory form */ 05280 dc = tchar2uni(&label); /* Get a Unicode character */ 05281 if (dc >= 0x10000) { 05282 if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ 05283 dc = 0; 05284 } else { 05285 st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; 05286 } 05287 } 05288 if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ 05289 LEAVE_FF(fs, FR_INVALID_NAME); 05290 } 05291 st_word(dirvn + di * 2, (WCHAR)dc); di++; 05292 } 05293 } else 05294 #endif 05295 { /* On the FAT/FAT32 volume */ 05296 mem_set(dirvn, ' ', 11); 05297 di = 0; 05298 while (*label) { /* Create volume label in directory form */ 05299 #if FF_USE_LFN 05300 dc = tchar2uni(&label); 05301 wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; 05302 #else /* ANSI/OEM input */ 05303 wc = (BYTE)*label++; 05304 if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; 05305 if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ 05306 #if FF_CODE_PAGE == 0 05307 if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ 05308 #elif FF_CODE_PAGE < 900 05309 if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ 05310 #endif 05311 #endif 05312 if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ 05313 LEAVE_FF(fs, FR_INVALID_NAME); 05314 } 05315 if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); 05316 dirvn[di++] = (BYTE)wc; 05317 } 05318 if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ 05319 while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ 05320 } 05321 05322 /* Set volume label */ 05323 dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ 05324 res = dir_sdi(&dj, 0); 05325 if (res == FR_OK) { 05326 res = dir_read_label(&dj); /* Get volume label entry */ 05327 if (res == FR_OK) { 05328 if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { 05329 dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ 05330 mem_cpy(dj.dir + XDIR_Label, dirvn, 22); 05331 } else { 05332 if (di != 0) { 05333 mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ 05334 } else { 05335 dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ 05336 } 05337 } 05338 fs->wflag = 1; 05339 res = sync_fs(fs); 05340 } else { /* No volume label entry or an error */ 05341 if (res == FR_NO_FILE) { 05342 res = FR_OK; 05343 if (di != 0) { /* Create a volume label entry */ 05344 res = dir_alloc(&dj, 1); /* Allocate an entry */ 05345 if (res == FR_OK) { 05346 mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ 05347 if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { 05348 dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ 05349 dj.dir[XDIR_NumLabel] = (BYTE)di; 05350 mem_cpy(dj.dir + XDIR_Label, dirvn, 22); 05351 } else { 05352 dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ 05353 mem_cpy(dj.dir, dirvn, 11); 05354 } 05355 fs->wflag = 1; 05356 res = sync_fs(fs); 05357 } 05358 } 05359 } 05360 } 05361 } 05362 05363 LEAVE_FF(fs, res); 05364 } 05365 05366 #endif /* !FF_FS_READONLY */ 05367 #endif /* FF_USE_LABEL */ 05368 05369 05370 05371 #if FF_USE_EXPAND && !FF_FS_READONLY 05372 /*-----------------------------------------------------------------------*/ 05373 /* Allocate a Contiguous Blocks to the File */ 05374 /*-----------------------------------------------------------------------*/ 05375 05376 FRESULT f_expand ( 05377 FIL* fp, /* Pointer to the file object */ 05378 FSIZE_t fsz, /* File size to be expanded to */ 05379 BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ 05380 ) 05381 { 05382 FRESULT res; 05383 FATFS *fs; 05384 DWORD n, clst, stcl, scl, ncl, tcl, lclst; 05385 05386 05387 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 05388 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); 05389 if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); 05390 #if FF_FS_EXFAT 05391 if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ 05392 #endif 05393 n = (DWORD)fs->csize * SS(fs); /* Cluster size */ 05394 tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ 05395 stcl = fs->last_clst; lclst = 0; 05396 if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; 05397 05398 #if FF_FS_EXFAT 05399 if (fs->fs_type == FS_EXFAT) { 05400 scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ 05401 if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ 05402 if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; 05403 if (res == FR_OK) { /* A contiguous free area is found */ 05404 if (opt) { /* Allocate it now */ 05405 res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ 05406 lclst = scl + tcl - 1; 05407 } else { /* Set it as suggested point for next allocation */ 05408 lclst = scl - 1; 05409 } 05410 } 05411 } else 05412 #endif 05413 { 05414 scl = clst = stcl; ncl = 0; 05415 for (;;) { /* Find a contiguous cluster block */ 05416 n = get_fat(&fp->obj, clst); 05417 if (++clst >= fs->n_fatent) clst = 2; 05418 if (n == 1) { res = FR_INT_ERR; break; } 05419 if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } 05420 if (n == 0) { /* Is it a free cluster? */ 05421 if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ 05422 } else { 05423 scl = clst; ncl = 0; /* Not a free cluster */ 05424 } 05425 if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ 05426 } 05427 if (res == FR_OK) { /* A contiguous free area is found */ 05428 if (opt) { /* Allocate it now */ 05429 for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ 05430 res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); 05431 if (res != FR_OK) break; 05432 lclst = clst; 05433 } 05434 } else { /* Set it as suggested point for next allocation */ 05435 lclst = scl - 1; 05436 } 05437 } 05438 } 05439 05440 if (res == FR_OK) { 05441 fs->last_clst = lclst; /* Set suggested start cluster to start next */ 05442 if (opt) { /* Is it allocated now? */ 05443 fp->obj.sclust = scl; /* Update object allocation information */ 05444 fp->obj.objsize = fsz; 05445 if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ 05446 fp->flag |= FA_MODIFIED; 05447 if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ 05448 fs->free_clst -= tcl; 05449 fs->fsi_flag |= 1; 05450 } 05451 } 05452 } 05453 05454 LEAVE_FF(fs, res); 05455 } 05456 05457 #endif /* FF_USE_EXPAND && !FF_FS_READONLY */ 05458 05459 05460 05461 #if FF_USE_FORWARD 05462 /*-----------------------------------------------------------------------*/ 05463 /* Forward Data to the Stream Directly */ 05464 /*-----------------------------------------------------------------------*/ 05465 05466 FRESULT f_forward ( 05467 FIL* fp, /* Pointer to the file object */ 05468 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ 05469 UINT btf, /* Number of bytes to forward */ 05470 UINT* bf /* Pointer to number of bytes forwarded */ 05471 ) 05472 { 05473 FRESULT res; 05474 FATFS *fs; 05475 DWORD clst, sect; 05476 FSIZE_t remain; 05477 UINT rcnt, csect; 05478 BYTE *dbuf; 05479 05480 05481 *bf = 0; /* Clear transfer byte counter */ 05482 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 05483 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); 05484 if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 05485 05486 remain = fp->obj.objsize - fp->fptr; 05487 if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ 05488 05489 for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ 05490 fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { 05491 csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ 05492 if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ 05493 if (csect == 0) { /* On the cluster boundary? */ 05494 clst = (fp->fptr == 0) ? /* On the top of the file? */ 05495 fp->obj.sclust : get_fat(&fp->obj, fp->clust); 05496 if (clst <= 1) ABORT(fs, FR_INT_ERR); 05497 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 05498 fp->clust = clst; /* Update current cluster */ 05499 } 05500 } 05501 sect = clst2sect(fs, fp->clust); /* Get current data sector */ 05502 if (sect == 0) ABORT(fs, FR_INT_ERR); 05503 sect += csect; 05504 #if FF_FS_TINY 05505 if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ 05506 dbuf = fs->win; 05507 #else 05508 if (fp->sect != sect) { /* Fill sector cache with file data */ 05509 #if !FF_FS_READONLY 05510 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 05511 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 05512 fp->flag &= (BYTE)~FA_DIRTY; 05513 } 05514 #endif 05515 if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 05516 } 05517 dbuf = fp->buf; 05518 #endif 05519 fp->sect = sect; 05520 rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ 05521 if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ 05522 rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ 05523 if (rcnt == 0) ABORT(fs, FR_INT_ERR); 05524 } 05525 05526 LEAVE_FF(fs, FR_OK); 05527 } 05528 #endif /* FF_USE_FORWARD */ 05529 05530 05531 05532 #if FF_USE_MKFS && !FF_FS_READONLY 05533 /*-----------------------------------------------------------------------*/ 05534 /* Create an FAT/exFAT volume */ 05535 /*-----------------------------------------------------------------------*/ 05536 05537 FRESULT f_mkfs ( 05538 const TCHAR* path, /* Logical drive number */ 05539 BYTE opt, /* Format option */ 05540 DWORD au, /* Size of allocation unit (cluster) [byte] */ 05541 void* work, /* Pointer to working buffer (null: use heap memory) */ 05542 UINT len /* Size of working buffer [byte] */ 05543 ) 05544 { 05545 const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ 05546 const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ 05547 static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ 05548 static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ 05549 BYTE fmt, sys, *buf, *pte, pdrv, part; 05550 WORD ss; /* Sector size */ 05551 DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; 05552 DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ 05553 DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ 05554 UINT i; 05555 int vol; 05556 DSTATUS stat; 05557 #if FF_USE_TRIM || FF_FS_EXFAT 05558 DWORD tbl[3]; 05559 #endif 05560 05561 05562 /* Check mounted drive and clear work area */ 05563 vol = get_ldnumber(&path); /* Get target logical drive */ 05564 if (vol < 0) return FR_INVALID_DRIVE; 05565 if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume if mounted */ 05566 pdrv = LD2PD(vol); /* Physical drive */ 05567 part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ 05568 05569 /* Check physical drive status */ 05570 stat = disk_initialize(pdrv); 05571 if (stat & STA_NOINIT) return FR_NOT_READY; 05572 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 05573 if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ 05574 #if FF_MAX_SS != FF_MIN_SS /* Get sector size of the medium if variable sector size cfg. */ 05575 if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; 05576 if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; 05577 #else 05578 ss = FF_MAX_SS; 05579 #endif 05580 if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ 05581 au /= ss; /* Cluster size in unit of sector */ 05582 05583 /* Get working buffer */ 05584 #if FF_USE_LFN == 3 || FF_FS_HEAPBUF 05585 if (!work) { /* Use heap memory for working buffer */ 05586 for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && !(buf = (BYTE *)ff_memalloc(szb_buf)); szb_buf /= 2) ; 05587 sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ 05588 } else 05589 #endif 05590 { 05591 buf = (BYTE*)work; /* Working buffer */ 05592 sz_buf = len / ss; /* Size of working buffer (sector) */ 05593 szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ 05594 } 05595 if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE; 05596 05597 /* Determine where the volume to be located (b_vol, sz_vol) */ 05598 if (FF_MULTI_PARTITION && part != 0) { 05599 /* Get partition information from partition table in the MBR */ 05600 if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ 05601 if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ 05602 pte = buf + (MBR_Table + (part - 1) * SZ_PTE); 05603 if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ 05604 b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ 05605 sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ 05606 } else { 05607 /* Create a single-partition in this function */ 05608 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05609 b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ 05610 if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); 05611 sz_vol -= b_vol; /* Volume size */ 05612 } 05613 if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ 05614 05615 /* Pre-determine the FAT type */ 05616 do { 05617 if (FF_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ 05618 if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ 05619 fmt = FS_EXFAT; break; 05620 } 05621 } 05622 if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */ 05623 if (opt & FM_FAT32) { /* FAT32 possible? */ 05624 if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ 05625 fmt = FS_FAT32; break; 05626 } 05627 } 05628 if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ 05629 fmt = FS_FAT16; 05630 } while (0); 05631 05632 #if FF_FS_EXFAT 05633 if (fmt == FS_EXFAT) { /* Create an exFAT volume */ 05634 DWORD szb_bit, szb_case, sum, nb, cl; 05635 WCHAR ch, si; 05636 UINT j, st; 05637 BYTE b; 05638 05639 if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ 05640 #if FF_USE_TRIM 05641 tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ 05642 disk_ioctl(pdrv, CTRL_TRIM, tbl); 05643 #endif 05644 /* Determine FAT location, data location and number of clusters */ 05645 if (au == 0) { /* au auto-selection */ 05646 au = 8; 05647 if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ 05648 if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ 05649 } 05650 b_fat = b_vol + 32; /* FAT start at offset 32 */ 05651 sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ 05652 b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ 05653 if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ 05654 n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ 05655 if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ 05656 if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ 05657 05658 szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ 05659 tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ 05660 05661 /* Create a compressed up-case table */ 05662 sect = b_data + au * tbl[0]; /* Table start sector */ 05663 sum = 0; /* Table checksum to be stored in the 82 entry */ 05664 st = si = i = j = szb_case = 0; 05665 do { 05666 switch (st) { 05667 case 0: 05668 ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ 05669 if (ch != si) { 05670 si++; break; /* Store the up-case char if exist */ 05671 } 05672 for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ 05673 if (j >= 128) { 05674 ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ 05675 } 05676 st = 1; /* Do not compress short run */ 05677 /* go to next case */ 05678 case 1: 05679 ch = si++; /* Fill the short run */ 05680 if (--j == 0) st = 0; 05681 break; 05682 05683 default: 05684 ch = (WCHAR)j; si += j; /* Number of chars to skip */ 05685 st = 0; 05686 } 05687 sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ 05688 sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); 05689 i += 2; szb_case += 2; 05690 if (si == 0 || i == szb_buf) { /* Write buffered data when buffer full or end of process */ 05691 n = (i + ss - 1) / ss; 05692 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05693 sect += n; i = 0; 05694 } 05695 } while (si); 05696 tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ 05697 tbl[2] = 1; /* Number of root dir clusters */ 05698 05699 /* Initialize the allocation bitmap */ 05700 sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ 05701 nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ 05702 do { 05703 mem_set(buf, 0, szb_buf); 05704 for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; 05705 for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; 05706 n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ 05707 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05708 sect += n; nsect -= n; 05709 } while (nsect); 05710 05711 /* Initialize the FAT */ 05712 sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ 05713 j = nb = cl = 0; 05714 do { 05715 mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ 05716 if (cl == 0) { /* Set entry 0 and 1 */ 05717 st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; 05718 st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; 05719 } 05720 do { /* Create chains of bitmap, up-case and root dir */ 05721 while (nb != 0 && i < szb_buf) { /* Create a chain */ 05722 st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); 05723 i += 4; cl++; nb--; 05724 } 05725 if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ 05726 } while (nb != 0 && i < szb_buf); 05727 n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ 05728 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05729 sect += n; nsect -= n; 05730 } while (nsect); 05731 05732 /* Initialize the root directory */ 05733 mem_set(buf, 0, szb_buf); 05734 buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ 05735 buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ 05736 st_dword(buf + SZDIRE * 1 + 20, 2); 05737 st_dword(buf + SZDIRE * 1 + 24, szb_bit); 05738 buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ 05739 st_dword(buf + SZDIRE * 2 + 4, sum); 05740 st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); 05741 st_dword(buf + SZDIRE * 2 + 24, szb_case); 05742 sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ 05743 do { /* Fill root directory sectors */ 05744 n = (nsect > sz_buf) ? sz_buf : nsect; 05745 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05746 mem_set(buf, 0, ss); 05747 sect += n; nsect -= n; 05748 } while (nsect); 05749 05750 /* Create two set of the exFAT VBR blocks */ 05751 sect = b_vol; 05752 for (n = 0; n < 2; n++) { 05753 /* Main record (+0) */ 05754 mem_set(buf, 0, ss); 05755 mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ 05756 st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ 05757 st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ 05758 st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ 05759 st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ 05760 st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ 05761 st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ 05762 st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ 05763 st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ 05764 st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ 05765 for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ 05766 for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ 05767 buf[BPB_NumFATsEx] = 1; /* Number of FATs */ 05768 buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ 05769 st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ 05770 st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ 05771 for (i = sum = 0; i < ss; i++) { /* VBR checksum */ 05772 if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); 05773 } 05774 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05775 /* Extended bootstrap record (+1..+8) */ 05776 mem_set(buf, 0, ss); 05777 st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ 05778 for (j = 1; j < 9; j++) { 05779 for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ 05780 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05781 } 05782 /* OEM/Reserved record (+9..+10) */ 05783 mem_set(buf, 0, ss); 05784 for ( ; j < 11; j++) { 05785 for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ 05786 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05787 } 05788 /* Sum record (+11) */ 05789 for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ 05790 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05791 } 05792 05793 } else 05794 #endif /* FF_FS_EXFAT */ 05795 { /* Create an FAT/FAT32 volume */ 05796 do { 05797 pau = au; 05798 /* Pre-determine number of clusters and FAT sub-type */ 05799 if (fmt == FS_FAT32) { /* FAT32 volume */ 05800 if (pau == 0) { /* au auto-selection */ 05801 n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ 05802 for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ 05803 } 05804 n_clst = sz_vol / pau; /* Number of clusters */ 05805 sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ 05806 sz_rsv = 32; /* Number of reserved sectors */ 05807 sz_dir = 0; /* No static directory */ 05808 if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); 05809 } else { /* FAT volume */ 05810 if (pau == 0) { /* au auto-selection */ 05811 n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ 05812 for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ 05813 } 05814 n_clst = sz_vol / pau; 05815 if (n_clst > MAX_FAT12) { 05816 n = n_clst * 2 + 4; /* FAT size [byte] */ 05817 } else { 05818 fmt = FS_FAT12; 05819 n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ 05820 } 05821 sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ 05822 sz_rsv = 1; /* Number of reserved sectors */ 05823 sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ 05824 } 05825 b_fat = b_vol + sz_rsv; /* FAT base */ 05826 b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ 05827 05828 /* Align data base to erase block boundary (for flash memory media) */ 05829 n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ 05830 if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ 05831 sz_rsv += n; b_fat += n; 05832 } else { /* FAT: Expand FAT size */ 05833 sz_fat += n / n_fats; 05834 } 05835 05836 /* Determine number of clusters and final check of validity of the FAT sub-type */ 05837 if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume */ 05838 n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; 05839 if (fmt == FS_FAT32) { 05840 if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ 05841 if (au == 0 && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ 05842 LEAVE_MKFS(FR_MKFS_ABORTED); 05843 } 05844 } 05845 if (fmt == FS_FAT16) { 05846 if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ 05847 if (au == 0 && (pau * 2) <= 64) { 05848 au = pau * 2; continue; /* Adjust cluster size and retry */ 05849 } 05850 if ((opt & FM_FAT32)) { 05851 fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ 05852 } 05853 if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ 05854 LEAVE_MKFS(FR_MKFS_ABORTED); 05855 } 05856 if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ 05857 if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ 05858 LEAVE_MKFS(FR_MKFS_ABORTED); 05859 } 05860 } 05861 if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ 05862 05863 /* Ok, it is the valid cluster configuration */ 05864 break; 05865 } while (1); 05866 05867 #if FF_USE_TRIM 05868 tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ 05869 disk_ioctl(pdrv, CTRL_TRIM, tbl); 05870 #endif 05871 /* Create FAT VBR */ 05872 mem_set(buf, 0, ss); 05873 mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ 05874 st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ 05875 buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ 05876 st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ 05877 buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ 05878 st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ 05879 if (sz_vol < 0x10000) { 05880 st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ 05881 } else { 05882 st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ 05883 } 05884 buf[BPB_Media] = 0xF8; /* Media descriptor byte */ 05885 st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ 05886 st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ 05887 st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ 05888 if (fmt == FS_FAT32) { 05889 st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ 05890 st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ 05891 st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ 05892 st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ 05893 st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ 05894 buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ 05895 buf[BS_BootSig32] = 0x29; /* Extended boot signature */ 05896 mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ 05897 } else { 05898 st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ 05899 st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ 05900 buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ 05901 buf[BS_BootSig] = 0x29; /* Extended boot signature */ 05902 mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ 05903 } 05904 st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ 05905 if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ 05906 05907 /* Create FSINFO record if needed */ 05908 if (fmt == FS_FAT32) { 05909 disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ 05910 mem_set(buf, 0, ss); 05911 st_dword(buf + FSI_LeadSig, 0x41615252); 05912 st_dword(buf + FSI_StrucSig, 0x61417272); 05913 st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ 05914 st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ 05915 st_word(buf + BS_55AA, 0xAA55); 05916 disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ 05917 disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ 05918 } 05919 05920 /* Initialize FAT area */ 05921 mem_set(buf, 0, (UINT)szb_buf); 05922 sect = b_fat; /* FAT start sector */ 05923 for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ 05924 if (fmt == FS_FAT32) { 05925 st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ 05926 st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ 05927 st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ 05928 } else { 05929 st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ 05930 } 05931 nsect = sz_fat; /* Number of FAT sectors */ 05932 do { /* Fill FAT sectors */ 05933 n = (nsect > sz_buf) ? sz_buf : nsect; 05934 if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05935 mem_set(buf, 0, ss); 05936 sect += n; nsect -= n; 05937 } while (nsect); 05938 } 05939 05940 /* Initialize root directory (fill with zero) */ 05941 nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ 05942 do { 05943 n = (nsect > sz_buf) ? sz_buf : nsect; 05944 if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05945 sect += n; nsect -= n; 05946 } while (nsect); 05947 } 05948 05949 /* Determine system ID in the partition table */ 05950 if (FF_FS_EXFAT && fmt == FS_EXFAT) { 05951 sys = 0x07; /* HPFS/NTFS/exFAT */ 05952 } else { 05953 if (fmt == FS_FAT32) { 05954 sys = 0x0C; /* FAT32X */ 05955 } else { 05956 if (sz_vol >= 0x10000) { 05957 sys = 0x06; /* FAT12/16 (large) */ 05958 } else { 05959 sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ 05960 } 05961 } 05962 } 05963 05964 /* Update partition information */ 05965 if (FF_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ 05966 /* Update system ID in the partition table */ 05967 if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ 05968 buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ 05969 if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ 05970 } else { /* Created as a new single partition */ 05971 if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ 05972 mem_set(buf, 0, ss); 05973 st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ 05974 pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ 05975 pte[PTE_Boot] = 0; /* Boot indicator */ 05976 pte[PTE_StHead] = 1; /* Start head */ 05977 pte[PTE_StSec] = 1; /* Start sector */ 05978 pte[PTE_StCyl] = 0; /* Start cylinder */ 05979 pte[PTE_System] = sys; /* System type */ 05980 n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ 05981 pte[PTE_EdHead] = 254; /* End head */ 05982 pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63); /* End sector */ 05983 pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ 05984 st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ 05985 st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ 05986 if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the MBR */ 05987 } 05988 } 05989 05990 if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05991 05992 LEAVE_MKFS(FR_OK); 05993 } 05994 05995 05996 05997 #if FF_MULTI_PARTITION 05998 /*-----------------------------------------------------------------------*/ 05999 /* Create Partition Table on the Physical Drive */ 06000 /*-----------------------------------------------------------------------*/ 06001 06002 FRESULT f_fdisk ( 06003 BYTE pdrv, /* Physical drive number */ 06004 const DWORD* szt, /* Pointer to the size table for each partitions */ 06005 void* work /* Pointer to the working buffer (null: use heap memory) */ 06006 ) 06007 { 06008 UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; 06009 BYTE s_hd, e_hd, *p, *buf; = (BYTE*)work; 06010 DSTATUS stat; 06011 DWORD sz_disk, sz_part, s_part; 06012 FRESULT res; 06013 06014 06015 stat = disk_initialize(pdrv); 06016 if (stat & STA_NOINIT) return FR_NOT_READY; 06017 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 06018 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; 06019 06020 buf = (BYTE*)work; 06021 #if FF_USE_LFN == 3 06022 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ 06023 #endif 06024 if (!buf) return FR_NOT_ENOUGH_CORE; 06025 06026 /* Determine the CHS without any consideration of the drive geometry */ 06027 for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; 06028 if (n == 256) n--; 06029 e_hd = n - 1; 06030 sz_cyl = 63 * n; 06031 tot_cyl = sz_disk / sz_cyl; 06032 06033 /* Create partition table */ 06034 mem_set(buf, 0, FF_MAX_SS); 06035 p = buf + MBR_Table; b_cyl = 0; 06036 for (i = 0; i < 4; i++, p += SZ_PTE) { 06037 p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ 06038 if (p_cyl == 0) continue; 06039 s_part = (DWORD)sz_cyl * b_cyl; 06040 sz_part = (DWORD)sz_cyl * p_cyl; 06041 if (i == 0) { /* Exclude first track of cylinder 0 */ 06042 s_hd = 1; 06043 s_part += 63; sz_part -= 63; 06044 } else { 06045 s_hd = 0; 06046 } 06047 e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ 06048 if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); 06049 06050 /* Set partition table */ 06051 p[1] = s_hd; /* Start head */ 06052 p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ 06053 p[3] = (BYTE)b_cyl; /* Start cylinder */ 06054 p[4] = 0x07; /* System type (temporary setting) */ 06055 p[5] = e_hd; /* End head */ 06056 p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ 06057 p[7] = (BYTE)e_cyl; /* End cylinder */ 06058 st_dword(p + 8, s_part); /* Start sector in LBA */ 06059 st_dword(p + 12, sz_part); /* Number of sectors */ 06060 06061 /* Next partition */ 06062 b_cyl += p_cyl; 06063 } 06064 st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ 06065 06066 /* Write it to the MBR */ 06067 res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; 06068 LEAVE_MKFS(res); 06069 } 06070 06071 #endif /* FF_MULTI_PARTITION */ 06072 #endif /* FF_USE_MKFS && !FF_FS_READONLY */ 06073 06074 06075 06076 06077 #if FF_USE_STRFUNC 06078 #if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) 06079 #error Wrong FF_STRF_ENCODE setting 06080 #endif 06081 /*-----------------------------------------------------------------------*/ 06082 /* Get a String from the File */ 06083 /*-----------------------------------------------------------------------*/ 06084 06085 TCHAR* f_gets ( 06086 TCHAR* buff, /* Pointer to the string buffer to read */ 06087 int len, /* Size of string buffer (items) */ 06088 FIL* fp /* Pointer to the file object */ 06089 ) 06090 { 06091 int nc = 0; 06092 TCHAR *p = buff; 06093 BYTE s[2]; 06094 UINT rc; 06095 WCHAR wc; 06096 #if FF_USE_LFN && ((FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3) || (FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3)) 06097 DWORD dc; 06098 #endif 06099 #if FF_USE_LFN && FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3 06100 UINT ct; 06101 #endif 06102 06103 #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 output */ 06104 #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ 06105 while (nc < len - 1) { 06106 f_read(fp, s, 1, &rc); 06107 if (rc != 1) break; 06108 wc = s[0]; 06109 if (dbc_1st((BYTE)wc)) { 06110 f_read(fp, s, 1, &rc); 06111 if (rc != 1 || !dbc_2nd(s[0])) continue; 06112 wc = wc << 8 | s[0]; 06113 } 06114 wc = ff_oem2uni(wc, CODEPAGE); 06115 if (wc == 0) continue; 06116 #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ 06117 while (nc < len - 1) { 06118 f_read(fp, s, 2, &rc); 06119 if (rc != 2) break; 06120 wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; 06121 #elif FF_STRF_ENCODE == 3 /* Read a character in UTF-8 */ 06122 while (nc < len - 2) { 06123 f_read(fp, s, 1, &rc); 06124 if (rc != 1) break; 06125 dc = s[0]; 06126 if (dc >= 0x80) { 06127 ct = 0; 06128 if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } 06129 if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } 06130 if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } 06131 if (ct == 0) continue; 06132 do { 06133 f_read(fp, s, 1, &rc); 06134 if (rc != 1 || (s[0] & 0xC0) != 0x80) break; 06135 dc = dc << 6 | (s[0] & 0x3F); 06136 } while (--ct); 06137 if (ct || dc < 0x80 || dc >= 0x110000) continue; 06138 } 06139 if (dc >= 0x10000) { 06140 wc = (WCHAR)(0xD800 | ((dc >> 10) - 0x40)); 06141 *p++ = wc; nc++; 06142 wc = (WCHAR)(0xDC00 | (dc & 0x3FF)); 06143 } else { 06144 wc = (WCHAR)dc; 06145 } 06146 #endif 06147 /* Output it in UTF-16 encoding */ 06148 if (FF_USE_STRFUNC == 2 && wc == '\r') continue; 06149 *p++ = wc; nc++; 06150 if (wc == '\n') break; 06151 } 06152 06153 #elif FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 /* UTF-8 output */ 06154 while (nc < len - 4) { 06155 #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ 06156 f_read(fp, s, 1, &rc); 06157 if (rc != 1) break; 06158 wc = s[0]; 06159 if (dbc_1st((BYTE)wc)) { 06160 f_read(fp, s, 1, &rc); 06161 if (rc != 1 || !dbc_2nd(s[0])) continue; 06162 wc = wc << 8 | s[0]; 06163 } 06164 dc = ff_oem2uni(wc, CODEPAGE); 06165 if (dc == 0) continue; 06166 #else /* Read a character in UTF-16LE/BE */ 06167 f_read(fp, s, 2, &rc); 06168 if (rc != 2) break; 06169 dc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; 06170 if (IsSurrogate(dc)) { 06171 f_read(fp, s, 2, &rc); 06172 if (rc != 2) break; 06173 wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; 06174 if (!IsSurrogateH(dc) || !IsSurrogateL(wc)) continue; 06175 dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); 06176 } 06177 #endif 06178 /* Output it in UTF-8 encoding */ 06179 if (FF_USE_STRFUNC == 2 && dc == '\r') continue; 06180 if (dc < 0x80) { /* 1-byte */ 06181 *p++ = (TCHAR)dc; 06182 nc++; 06183 if (dc == '\n') break; 06184 } else { 06185 if (dc < 0x800) { /* 2-byte */ 06186 *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); 06187 *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); 06188 nc += 2; 06189 } else { 06190 if (dc < 0x10000) { /* 3-byte */ 06191 *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); 06192 *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); 06193 *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); 06194 nc += 3; 06195 } else { /* 4-byte */ 06196 *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); 06197 *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); 06198 *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); 06199 *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); 06200 nc += 4; 06201 } 06202 } 06203 } 06204 } 06205 06206 #else /* Byte-by-byte without any conversion (ANSI/OEM API or UTF-8 to UTF-8) */ 06207 while (nc < len - 1) { 06208 f_read(fp, s, 1, &rc); 06209 if (rc != 1) break; 06210 wc = s[0]; 06211 if (FF_USE_STRFUNC == 2 && wc == '\r') continue; 06212 *p++ = (TCHAR)wc; nc++; 06213 if (wc == '\n') break; 06214 } 06215 #endif 06216 06217 *p = 0; 06218 return nc ? buff : 0; /* When no data read (EOF or error), return with error. */ 06219 } 06220 06221 06222 06223 06224 #if !FF_FS_READONLY 06225 #include <stdarg.h> 06226 /*-----------------------------------------------------------------------*/ 06227 /* Put a Character to the File */ 06228 /*-----------------------------------------------------------------------*/ 06229 06230 typedef struct { /* Putchar output buffer and work area */ 06231 FIL *fp; /* Ptr to the writing file */ 06232 int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ 06233 #if FF_USE_LFN && FF_LFN_UNICODE == 1 06234 WCHAR hs; 06235 #elif FF_USE_LFN && FF_LFN_UNICODE == 2 06236 BYTE bs[4]; 06237 UINT wi, ct; 06238 #endif 06239 BYTE buf[64]; /* Write buffer */ 06240 } putbuff; 06241 06242 06243 static 06244 void putc_bfd ( /* Buffered write with code conversion */ 06245 putbuff* pb, 06246 TCHAR c 06247 ) 06248 { 06249 UINT n; 06250 int i, nc; 06251 #if FF_USE_LFN && (FF_LFN_UNICODE == 1 || (FF_LFN_UNICODE == 2 && (FF_STRF_ENCODE != 3))) 06252 WCHAR hs, wc; 06253 #endif 06254 #if FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 06255 DWORD dc; 06256 TCHAR *tp; 06257 #endif 06258 06259 if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ 06260 putc_bfd(pb, '\r'); 06261 } 06262 06263 i = pb->idx; /* Write index of pb->buf[] */ 06264 if (i < 0) return; 06265 nc = pb->nchr; /* Write unit count */ 06266 06267 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 06268 #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 input */ 06269 if (IsSurrogateH(c)) { 06270 pb->hs = c; return; 06271 } 06272 wc = c; hs = pb->hs; pb->hs = 0; 06273 if (hs != 0) { 06274 if (!IsSurrogateL(wc)) hs = 0; 06275 } else { 06276 if (IsSurrogateL(wc)) return; 06277 } 06278 #if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ 06279 if (hs != 0) { /* 4-byte */ 06280 nc += 4; 06281 hs = (hs & 0x3FF) + 0x40; 06282 pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); 06283 pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); 06284 pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); 06285 pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); 06286 } else { 06287 if (wc < 0x80) { /* 1-byte */ 06288 nc++; 06289 pb->buf[i++] = (BYTE)wc; 06290 } else { 06291 if (wc < 0x800) { /* 2-byte */ 06292 nc += 2; 06293 pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); 06294 } else { /* 3-byte */ 06295 nc += 3; 06296 pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); 06297 pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); 06298 } 06299 pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); 06300 } 06301 } 06302 #endif 06303 #else /* UTF-8 input */ 06304 for (;;) { 06305 if (pb->ct == 0) { /* Out of multi-byte sequence? */ 06306 pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ 06307 if ((BYTE)c < 0x80) break; /* 1-byte? */ 06308 if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte? */ 06309 if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte? */ 06310 if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte? */ 06311 return; 06312 } else { /* In the multi-byte sequence */ 06313 if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ 06314 pb->ct = 0; continue; 06315 } 06316 pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ 06317 if (--pb->ct == 0) break; /* End of sequence? */ 06318 return; 06319 } 06320 } 06321 #if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ 06322 pb->buf[i++] = pb->bs[0]; nc++; 06323 if (pb->bs[0] >= 0xC0) { 06324 pb->buf[i++] = pb->bs[1]; nc++; 06325 } 06326 if (pb->bs[0] >= 0xE0) { 06327 pb->buf[i++] = pb->bs[2]; nc++; 06328 } 06329 if (pb->bs[0] >= 0xF0) { 06330 pb->buf[i++] = pb->bs[3]; nc++; 06331 } 06332 #else /* Write it in UTF-16 or ANSI/OEM */ 06333 tp = (TCHAR*)pb->bs; 06334 dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ 06335 if (dc == 0xFFFFFFFF) return; 06336 wc = (WCHAR)dc; 06337 hs = (WCHAR)(dc >> 16); 06338 #endif 06339 #endif 06340 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 && FF_STRF_ENCODE != 3 06341 #if FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ 06342 if (hs != 0) { 06343 pb->buf[i++] = (BYTE)(hs >> 8); 06344 pb->buf[i++] = (BYTE)hs; 06345 nc++; 06346 } 06347 pb->buf[i++] = (BYTE)(wc >> 8); 06348 pb->buf[i++] = (BYTE)wc; 06349 nc++; 06350 #elif FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ 06351 if (hs != 0) { 06352 pb->buf[i++] = (BYTE)hs; 06353 pb->buf[i++] = (BYTE)(hs >> 8); 06354 nc++; 06355 } 06356 pb->buf[i++] = (BYTE)wc; 06357 pb->buf[i++] = (BYTE)(wc >> 8); 06358 nc++; 06359 #else /* Write a character in ANSI/OEM */ 06360 if (hs != 0) return; 06361 wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ 06362 if (wc == 0) return;; 06363 if (wc >= 0x100) { 06364 pb->buf[i++] = (BYTE)(wc >> 8); nc++; 06365 } 06366 pb->buf[i++] = (BYTE)wc; nc++; 06367 #endif 06368 #endif 06369 06370 #else /* ANSI/OEM input */ 06371 pb->buf[i++] = (BYTE)c; 06372 nc++; 06373 #endif 06374 06375 if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ 06376 f_write(pb->fp, pb->buf, (UINT)i, &n); 06377 i = (n == (UINT)i) ? 0 : -1; 06378 } 06379 pb->idx = i; 06380 pb->nchr = nc; 06381 } 06382 06383 06384 static 06385 int putc_flush ( /* Flush left characters in the buffer */ 06386 putbuff* pb 06387 ) 06388 { 06389 UINT nw; 06390 06391 if ( pb->idx >= 0 /* Flush buffered characters to the file */ 06392 && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK 06393 && (UINT)pb->idx == nw) return pb->nchr; 06394 return EOF; 06395 } 06396 06397 06398 static 06399 void putc_init ( /* Initialize write buffer */ 06400 putbuff* pb, 06401 FIL* fp 06402 ) 06403 { 06404 mem_set(pb, 0, sizeof (putbuff)); 06405 pb->fp = fp; 06406 } 06407 06408 06409 06410 int f_putc ( 06411 TCHAR c, /* A character to be output */ 06412 FIL* fp /* Pointer to the file object */ 06413 ) 06414 { 06415 putbuff pb; 06416 06417 06418 putc_init(&pb, fp); 06419 putc_bfd(&pb, c); /* Put the character */ 06420 return putc_flush(&pb); 06421 } 06422 06423 06424 06425 06426 /*-----------------------------------------------------------------------*/ 06427 /* Put a String to the File */ 06428 /*-----------------------------------------------------------------------*/ 06429 06430 int f_puts ( 06431 const TCHAR* str, /* Pointer to the string to be output */ 06432 FIL* fp /* Pointer to the file object */ 06433 ) 06434 { 06435 putbuff pb; 06436 06437 06438 putc_init(&pb, fp); 06439 while (*str) putc_bfd(&pb, *str++); /* Put the string */ 06440 return putc_flush(&pb); 06441 } 06442 06443 06444 06445 06446 /*-----------------------------------------------------------------------*/ 06447 /* Put a Formatted String to the File */ 06448 /*-----------------------------------------------------------------------*/ 06449 06450 int f_printf ( 06451 FIL* fp, /* Pointer to the file object */ 06452 const TCHAR* fmt, /* Pointer to the format string */ 06453 ... /* Optional arguments... */ 06454 ) 06455 { 06456 va_list arp; 06457 putbuff pb; 06458 BYTE f, r; 06459 UINT i, j, w; 06460 DWORD v; 06461 TCHAR c, d, str[32], *p; 06462 06463 06464 putc_init(&pb, fp); 06465 06466 va_start(arp, fmt); 06467 06468 for (;;) { 06469 c = *fmt++; 06470 if (c == 0) break; /* End of string */ 06471 if (c != '%') { /* Non escape character */ 06472 putc_bfd(&pb, c); 06473 continue; 06474 } 06475 w = f = 0; 06476 c = *fmt++; 06477 if (c == '0') { /* Flag: '0' padding */ 06478 f = 1; c = *fmt++; 06479 } else { 06480 if (c == '-') { /* Flag: left justified */ 06481 f = 2; c = *fmt++; 06482 } 06483 } 06484 if (c == '*') { /* Minimum width by argument */ 06485 w = va_arg(arp, int); 06486 c = *fmt++; 06487 } else { 06488 while (IsDigit(c)) { /* Minimum width */ 06489 w = w * 10 + c - '0'; 06490 c = *fmt++; 06491 } 06492 } 06493 if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ 06494 f |= 4; c = *fmt++; 06495 } 06496 if (c == 0) break; 06497 d = c; 06498 if (IsLower(d)) d -= 0x20; 06499 switch (d) { /* Atgument type is... */ 06500 case 'S' : /* String */ 06501 p = va_arg(arp, TCHAR*); 06502 for (j = 0; p[j]; j++) ; 06503 if (!(f & 2)) { /* Right padded */ 06504 while (j++ < w) putc_bfd(&pb, ' ') ; 06505 } 06506 while (*p) putc_bfd(&pb, *p++) ; /* String body */ 06507 while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ 06508 continue; 06509 06510 case 'C' : /* Character */ 06511 putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; 06512 06513 case 'B' : /* Unsigned binary */ 06514 r = 2; break; 06515 06516 case 'O' : /* Unsigned octal */ 06517 r = 8; break; 06518 06519 case 'D' : /* Signed decimal */ 06520 case 'U' : /* Unsigned decimal */ 06521 r = 10; break; 06522 06523 case 'X' : /* Unsigned hexdecimal */ 06524 r = 16; break; 06525 06526 default: /* Unknown type (pass-through) */ 06527 putc_bfd(&pb, c); continue; 06528 } 06529 06530 /* Get an argument and put it in numeral */ 06531 v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); 06532 if (d == 'D' && (v & 0x80000000)) { 06533 v = 0 - v; 06534 f |= 8; 06535 } 06536 i = 0; 06537 do { 06538 d = (TCHAR)(v % r); v /= r; 06539 if (d > 9) d += (c == 'x') ? 0x27 : 0x07; 06540 str[i++] = d + '0'; 06541 } while (v && i < sizeof str / sizeof *str); 06542 if (f & 8) str[i++] = '-'; 06543 j = i; d = (f & 1) ? '0' : ' '; 06544 if (!(f & 2)) { 06545 while (j++ < w) putc_bfd(&pb, d); /* Right pad */ 06546 } 06547 do { 06548 putc_bfd(&pb, str[--i]); /* Number body */ 06549 } while (i); 06550 while (j++ < w) putc_bfd(&pb, d); /* Left pad */ 06551 } 06552 06553 va_end(arp); 06554 06555 return putc_flush(&pb); 06556 } 06557 06558 #endif /* !FF_FS_READONLY */ 06559 #endif /* FF_USE_STRFUNC */ 06560 06561 06562 06563 #if FF_CODE_PAGE == 0 06564 /*-----------------------------------------------------------------------*/ 06565 /* Set Active Codepage for the Path Name */ 06566 /*-----------------------------------------------------------------------*/ 06567 06568 FRESULT f_setcp ( 06569 WORD cp /* Value to be set as active code page */ 06570 ) 06571 { 06572 static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; 06573 static const BYTE *const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, 0}; 06574 UINT i; 06575 06576 06577 for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ 06578 if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ 06579 06580 CodePage = cp; 06581 if (cp >= 900) { /* DBCS */ 06582 ExCvt = 0; 06583 DbcTbl = tables[i]; 06584 } else { /* SBCS */ 06585 ExCvt = tables[i]; 06586 DbcTbl = 0; 06587 } 06588 return FR_OK; 06589 } 06590 #endif /* FF_CODE_PAGE == 0 */ 06591
Generated on Tue Jul 12 2022 13:53:10 by
