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 (dp->sect == 0 || ofs >= (DWORD)((FF_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ 01744 01745 if (ofs % SS(fs) == 0) { /* Sector changed? */ 01746 dp->sect++; /* Next sector */ 01747 01748 if (dp->clust == 0) { /* Static table */ 01749 if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ 01750 dp->sect = 0; return FR_NO_FILE; 01751 } 01752 } 01753 else { /* Dynamic table */ 01754 if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ 01755 clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ 01756 if (clst <= 1) return FR_INT_ERR; /* Internal error */ 01757 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ 01758 if (clst >= fs->n_fatent) { /* It reached end of dynamic table */ 01759 #if !FF_FS_READONLY 01760 if (!stretch) { /* If no stretch, report EOT */ 01761 dp->sect = 0; return FR_NO_FILE; 01762 } 01763 clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ 01764 if (clst == 0) return FR_DENIED; /* No free cluster */ 01765 if (clst == 1) return FR_INT_ERR; /* Internal error */ 01766 if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ 01767 if (dir_clear(fs, clst) != FR_OK) return FR_DISK_ERR; /* Clean up the stretched table */ 01768 if (FF_FS_EXFAT) dp->obj.stat |= 4; /* exFAT: The directory has been stretched */ 01769 #else 01770 if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ 01771 dp->sect = 0; return FR_NO_FILE; /* Report EOT */ 01772 #endif 01773 } 01774 dp->clust = clst; /* Initialize data for new cluster */ 01775 dp->sect = clst2sect(fs, clst); 01776 } 01777 } 01778 } 01779 dp->dptr = ofs; /* Current entry */ 01780 dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ 01781 01782 return FR_OK; 01783 } 01784 01785 01786 01787 01788 #if !FF_FS_READONLY 01789 /*-----------------------------------------------------------------------*/ 01790 /* Directory handling - Reserve a block of directory entries */ 01791 /*-----------------------------------------------------------------------*/ 01792 01793 static 01794 FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ 01795 FATFS_DIR* dp, /* Pointer to the directory object */ 01796 UINT nent /* Number of contiguous entries to allocate */ 01797 ) 01798 { 01799 FRESULT res; 01800 UINT n; 01801 FATFS *fs = dp->obj.fs; 01802 01803 01804 res = dir_sdi(dp, 0); 01805 if (res == FR_OK) { 01806 n = 0; 01807 do { 01808 res = move_window(fs, dp->sect); 01809 if (res != FR_OK) break; 01810 #if FF_FS_EXFAT 01811 if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { 01812 #else 01813 if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { 01814 #endif 01815 if (++n == nent) break; /* A block of contiguous free entries is found */ 01816 } else { 01817 n = 0; /* Not a blank entry. Restart to search */ 01818 } 01819 res = dir_next(dp, 1); 01820 } while (res == FR_OK); /* Next entry with table stretch enabled */ 01821 } 01822 01823 if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ 01824 return res; 01825 } 01826 01827 #endif /* !FF_FS_READONLY */ 01828 01829 01830 01831 01832 /*-----------------------------------------------------------------------*/ 01833 /* FAT: Directory handling - Load/Store start cluster number */ 01834 /*-----------------------------------------------------------------------*/ 01835 01836 static 01837 DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ 01838 FATFS* fs, /* Pointer to the fs object */ 01839 const BYTE* dir /* Pointer to the key entry */ 01840 ) 01841 { 01842 DWORD cl; 01843 01844 cl = ld_word(dir + DIR_FstClusLO); 01845 if (fs->fs_type == FS_FAT32) { 01846 cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; 01847 } 01848 01849 return cl; 01850 } 01851 01852 01853 #if !FF_FS_READONLY 01854 static 01855 void st_clust ( 01856 FATFS* fs, /* Pointer to the fs object */ 01857 BYTE* dir, /* Pointer to the key entry */ 01858 DWORD cl /* Value to be set */ 01859 ) 01860 { 01861 st_word(dir + DIR_FstClusLO, (WORD)cl); 01862 if (fs->fs_type == FS_FAT32) { 01863 st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); 01864 } 01865 } 01866 #endif 01867 01868 01869 01870 #if FF_USE_LFN 01871 /*--------------------------------------------------------*/ 01872 /* FAT-LFN: Compare a part of file name with an LFN entry */ 01873 /*--------------------------------------------------------*/ 01874 static 01875 int cmp_lfn ( /* 1:matched, 0:not matched */ 01876 const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ 01877 BYTE* dir /* Pointer to the directory entry containing the part of LFN */ 01878 ) 01879 { 01880 UINT i, s; 01881 WCHAR wc, uc; 01882 01883 01884 if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ 01885 01886 i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ 01887 01888 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ 01889 uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ 01890 if (wc != 0) { 01891 if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ 01892 return 0; /* Not matched */ 01893 } 01894 wc = uc; 01895 } else { 01896 if (uc != 0xFFFF) return 0; /* Check filler */ 01897 } 01898 } 01899 01900 if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ 01901 01902 return 1; /* The part of LFN matched */ 01903 } 01904 01905 01906 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT 01907 /*-----------------------------------------------------*/ 01908 /* FAT-LFN: Pick a part of file name from an LFN entry */ 01909 /*-----------------------------------------------------*/ 01910 static 01911 int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ 01912 WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ 01913 BYTE* dir /* Pointer to the LFN entry */ 01914 ) 01915 { 01916 UINT i, s; 01917 WCHAR wc, uc; 01918 01919 01920 if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ 01921 01922 i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ 01923 01924 for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ 01925 uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ 01926 if (wc != 0) { 01927 if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ 01928 lfnbuf[i++] = wc = uc; /* Store it */ 01929 } else { 01930 if (uc != 0xFFFF) return 0; /* Check filler */ 01931 } 01932 } 01933 01934 if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ 01935 if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ 01936 lfnbuf[i] = 0; 01937 } 01938 01939 return 1; /* The part of LFN is valid */ 01940 } 01941 #endif 01942 01943 01944 #if !FF_FS_READONLY 01945 /*-----------------------------------------*/ 01946 /* FAT-LFN: Create an entry of LFN entries */ 01947 /*-----------------------------------------*/ 01948 static 01949 void put_lfn ( 01950 const WCHAR* lfn, /* Pointer to the LFN */ 01951 BYTE* dir, /* Pointer to the LFN entry to be created */ 01952 BYTE ord, /* LFN order (1-20) */ 01953 BYTE sum /* Checksum of the corresponding SFN */ 01954 ) 01955 { 01956 UINT i, s; 01957 WCHAR wc; 01958 01959 01960 dir[LDIR_Chksum] = sum; /* Set checksum */ 01961 dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ 01962 dir[LDIR_Type] = 0; 01963 st_word(dir + LDIR_FstClusLO, 0); 01964 01965 i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ 01966 s = wc = 0; 01967 do { 01968 if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ 01969 st_word(dir + LfnOfs[s], wc); /* Put it */ 01970 if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ 01971 } while (++s < 13); 01972 if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ 01973 dir[LDIR_Ord] = ord; /* Set the LFN order */ 01974 } 01975 01976 #endif /* !FF_FS_READONLY */ 01977 #endif /* FF_USE_LFN */ 01978 01979 01980 01981 #if FF_USE_LFN && !FF_FS_READONLY 01982 /*-----------------------------------------------------------------------*/ 01983 /* FAT-LFN: Create a Numbered SFN */ 01984 /*-----------------------------------------------------------------------*/ 01985 01986 static 01987 void gen_numname ( 01988 BYTE* dst, /* Pointer to the buffer to store numbered SFN */ 01989 const BYTE* src, /* Pointer to SFN */ 01990 const WCHAR* lfn, /* Pointer to LFN */ 01991 UINT seq /* Sequence number */ 01992 ) 01993 { 01994 BYTE ns[8], c; 01995 UINT i, j; 01996 WCHAR wc; 01997 DWORD sr; 01998 01999 02000 mem_cpy(dst, src, 11); 02001 02002 if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ 02003 sr = seq; 02004 while (*lfn) { /* Create a CRC */ 02005 wc = *lfn++; 02006 for (i = 0; i < 16; i++) { 02007 sr = (sr << 1) + (wc & 1); 02008 wc >>= 1; 02009 if (sr & 0x10000) sr ^= 0x11021; 02010 } 02011 } 02012 seq = (UINT)sr; 02013 } 02014 02015 /* itoa (hexdecimal) */ 02016 i = 7; 02017 do { 02018 c = (BYTE)((seq % 16) + '0'); 02019 if (c > '9') c += 7; 02020 ns[i--] = c; 02021 seq /= 16; 02022 } while (seq); 02023 ns[i] = '~'; 02024 02025 /* Append the number to the SFN body */ 02026 for (j = 0; j < i && dst[j] != ' '; j++) { 02027 if (dbc_1st(dst[j])) { 02028 if (j == i - 1) break; 02029 j++; 02030 } 02031 } 02032 do { 02033 dst[j++] = (i < 8) ? ns[i++] : ' '; 02034 } while (j < 8); 02035 } 02036 #endif /* FF_USE_LFN && !FF_FS_READONLY */ 02037 02038 02039 02040 #if FF_USE_LFN 02041 /*-----------------------------------------------------------------------*/ 02042 /* FAT-LFN: Calculate checksum of an SFN entry */ 02043 /*-----------------------------------------------------------------------*/ 02044 02045 static 02046 BYTE sum_sfn ( 02047 const BYTE* dir /* Pointer to the SFN entry */ 02048 ) 02049 { 02050 BYTE sum = 0; 02051 UINT n = 11; 02052 02053 do { 02054 sum = (sum >> 1) + (sum << 7) + *dir++; 02055 } while (--n); 02056 return sum; 02057 } 02058 02059 #endif /* FF_USE_LFN */ 02060 02061 02062 02063 #if FF_FS_EXFAT 02064 /*-----------------------------------------------------------------------*/ 02065 /* exFAT: Checksum */ 02066 /*-----------------------------------------------------------------------*/ 02067 02068 static 02069 WORD xdir_sum ( /* Get checksum of the directoly entry block */ 02070 const BYTE* dir /* Directory entry block to be calculated */ 02071 ) 02072 { 02073 UINT i, szblk; 02074 WORD sum; 02075 02076 02077 szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; 02078 for (i = sum = 0; i < szblk; i++) { 02079 if (i == XDIR_SetSum) { /* Skip sum field */ 02080 i++; 02081 } else { 02082 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; 02083 } 02084 } 02085 return sum; 02086 } 02087 02088 02089 02090 static 02091 WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ 02092 const WCHAR* name /* File name to be calculated */ 02093 ) 02094 { 02095 WCHAR chr; 02096 WORD sum = 0; 02097 02098 02099 while ((chr = *name++) != 0) { 02100 chr = (WCHAR)ff_wtoupper(chr); /* File name needs to be upper-case converted */ 02101 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); 02102 sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); 02103 } 02104 return sum; 02105 } 02106 02107 02108 #if !FF_FS_READONLY && FF_USE_MKFS 02109 static 02110 DWORD xsum32 ( 02111 BYTE dat, /* Byte to be calculated */ 02112 DWORD sum /* Previous sum */ 02113 ) 02114 { 02115 sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; 02116 return sum; 02117 } 02118 #endif 02119 02120 02121 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 02122 /*------------------------------------------------------*/ 02123 /* exFAT: Get object information from a directory block */ 02124 /*------------------------------------------------------*/ 02125 02126 static 02127 void get_xfileinfo ( 02128 BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ 02129 FILINFO* fno /* Buffer to store the extracted file information */ 02130 ) 02131 { 02132 WCHAR wc, hs; 02133 UINT di, si, nc; 02134 02135 /* Get file name from the entry block */ 02136 si = SZDIRE * 2; /* 1st C1 entry */ 02137 nc = hs = di = 0; 02138 while (nc < dirb[XDIR_NumName]) { 02139 if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ 02140 if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ 02141 wc = ld_word(dirb + si); si += 2; nc++; /* Get a character */ 02142 if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ 02143 hs = wc; continue; /* Get low surrogate */ 02144 } 02145 wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ 02146 if (wc == 0) { di = 0; break; } /* Buffer overflow or wrong encoding? */ 02147 di += wc; 02148 hs = 0; 02149 } 02150 if (hs != 0) di = 0; /* Broken surrogate pair? */ 02151 if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ 02152 fno->fname[di] = 0; /* Terminate the name */ 02153 fno->altname[0] = 0; /* exFAT does not have SFN */ 02154 02155 fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ 02156 fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ 02157 fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ 02158 fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ 02159 } 02160 02161 #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ 02162 02163 02164 /*-----------------------------------*/ 02165 /* exFAT: Get a directry entry block */ 02166 /*-----------------------------------*/ 02167 02168 static 02169 FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ 02170 FATFS_DIR* dp /* Reading direcotry object pointing top of the entry block to load */ 02171 ) 02172 { 02173 FRESULT res; 02174 UINT i, sz_ent; 02175 BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ 02176 02177 02178 /* Load 85 entry */ 02179 res = move_window(dp->obj.fs, dp->sect); 02180 if (res != FR_OK) return res; 02181 if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; /* Invalid order */ 02182 mem_cpy(dirb + 0 * SZDIRE, dp->dir, SZDIRE); 02183 sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; 02184 if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; 02185 02186 /* Load C0 entry */ 02187 res = dir_next(dp, 0); 02188 if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ 02189 if (res != FR_OK) return res; 02190 res = move_window(dp->obj.fs, dp->sect); 02191 if (res != FR_OK) return res; 02192 if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; /* Invalid order */ 02193 mem_cpy(dirb + 1 * SZDIRE, dp->dir, SZDIRE); 02194 if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; 02195 02196 /* Load C1 entries */ 02197 i = 2 * SZDIRE; /* C1 offset to load */ 02198 do { 02199 res = dir_next(dp, 0); 02200 if (res == FR_NO_FILE) res = FR_INT_ERR; /* It cannot be */ 02201 if (res != FR_OK) return res; 02202 res = move_window(dp->obj.fs, dp->sect); 02203 if (res != FR_OK) return res; 02204 if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; /* Invalid order */ 02205 if (i < MAXDIRB(FF_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); 02206 } while ((i += SZDIRE) < sz_ent); 02207 02208 /* Sanity check (do it for only accessible object) */ 02209 if (i <= MAXDIRB(FF_MAX_LFN)) { 02210 if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; 02211 } 02212 return FR_OK; 02213 } 02214 02215 02216 /*------------------------------------------------------------------*/ 02217 /* exFAT: Initialize object allocation info with loaded entry block */ 02218 /*------------------------------------------------------------------*/ 02219 02220 static 02221 void init_alloc_info ( 02222 FATFS* fs, /* Filesystem object */ 02223 FFOBJID* obj /* Object allocation information to be initialized */ 02224 ) 02225 { 02226 obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Start cluster */ 02227 obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); /* Size */ 02228 obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; /* Allocation status */ 02229 obj->n_frag = 0; /* No last fragment info */ 02230 } 02231 02232 02233 02234 #if !FF_FS_READONLY || FF_FS_RPATH != 0 02235 /*------------------------------------------------*/ 02236 /* exFAT: Load the object's directory entry block */ 02237 /*------------------------------------------------*/ 02238 static 02239 FRESULT load_obj_xdir ( 02240 FATFS_DIR* dp, /* Blank directory object to be used to access containing direcotry */ 02241 const FFOBJID* obj /* Object with its containing directory information */ 02242 ) 02243 { 02244 FRESULT res; 02245 02246 /* Open object containing directory */ 02247 dp->obj.fs = obj->fs; 02248 dp->obj.sclust = obj->c_scl; 02249 dp->obj.stat = (BYTE)obj->c_size; 02250 dp->obj.objsize = obj->c_size & 0xFFFFFF00; 02251 dp->obj.n_frag = 0; 02252 dp->blk_ofs = obj->c_ofs; 02253 02254 res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ 02255 if (res == FR_OK) { 02256 res = load_xdir(dp); /* Load the object's entry block */ 02257 } 02258 return res; 02259 } 02260 #endif 02261 02262 02263 #if !FF_FS_READONLY 02264 /*----------------------------------------*/ 02265 /* exFAT: Store the directory entry block */ 02266 /*----------------------------------------*/ 02267 static 02268 FRESULT store_xdir ( 02269 FATFS_DIR* dp /* Pointer to the direcotry object */ 02270 ) 02271 { 02272 FRESULT res; 02273 UINT nent; 02274 BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ 02275 02276 /* Create set sum */ 02277 st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); 02278 nent = dirb[XDIR_NumSec] + 1; 02279 02280 /* Store the direcotry entry block to the directory */ 02281 res = dir_sdi(dp, dp->blk_ofs); 02282 while (res == FR_OK) { 02283 res = move_window(dp->obj.fs, dp->sect); 02284 if (res != FR_OK) break; 02285 mem_cpy(dp->dir, dirb, SZDIRE); 02286 dp->obj.fs->wflag = 1; 02287 if (--nent == 0) break; 02288 dirb += SZDIRE; 02289 res = dir_next(dp, 0); 02290 } 02291 return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; 02292 } 02293 02294 02295 02296 /*-------------------------------------------*/ 02297 /* exFAT: Create a new directory enrty block */ 02298 /*-------------------------------------------*/ 02299 02300 static 02301 void create_xdir ( 02302 BYTE* dirb, /* Pointer to the direcotry entry block buffer */ 02303 const WCHAR* lfn /* Pointer to the object name */ 02304 ) 02305 { 02306 UINT i; 02307 BYTE nc1, nlen; 02308 WCHAR wc; 02309 02310 02311 /* Create 85,C0 entry */ 02312 mem_set(dirb, 0, 2 * SZDIRE); 02313 dirb[0 * SZDIRE + XDIR_Type] = 0x85; /* 85 entry */ 02314 dirb[1 * SZDIRE + XDIR_Type] = 0xC0; /* C0 entry */ 02315 02316 /* Create C1 entries */ 02317 i = SZDIRE * 2; /* Top of C1 entries */ 02318 nlen = nc1 = 0; wc = 1; 02319 do { 02320 dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ 02321 do { /* Fill name field */ 02322 if (wc != 0 && (wc = lfn[nlen]) != 0) nlen++; /* Get a character if exist */ 02323 st_word(dirb + i, wc); /* Store it */ 02324 i += 2; 02325 } while (i % SZDIRE != 0); 02326 nc1++; 02327 } while (lfn[nlen]); /* Fill next entry if any char follows */ 02328 02329 dirb[XDIR_NumName] = nlen; /* Set name length */ 02330 dirb[XDIR_NumSec] = 1 + nc1; /* Set secondary count (C0 + C1s) */ 02331 st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ 02332 } 02333 02334 #endif /* !FF_FS_READONLY */ 02335 #endif /* FF_FS_EXFAT */ 02336 02337 02338 02339 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 || FF_USE_LABEL || FF_FS_EXFAT 02340 /*-----------------------------------------------------------------------*/ 02341 /* Read an object from the directory */ 02342 /*-----------------------------------------------------------------------*/ 02343 02344 #define dir_read_file(dp) dir_read(dp, 0) 02345 #define dir_read_label(dp) dir_read(dp, 1) 02346 02347 static 02348 FRESULT dir_read ( 02349 FATFS_DIR* dp, /* Pointer to the directory object */ 02350 int vol /* Filtered by 0:file/directory or 1:volume label */ 02351 ) 02352 { 02353 FRESULT res = FR_NO_FILE; 02354 FATFS *fs = dp->obj.fs; 02355 BYTE a, c; 02356 #if FF_USE_LFN 02357 BYTE ord = 0xFF, sum = 0xFF; 02358 #endif 02359 02360 while (dp->sect) { 02361 res = move_window(fs, dp->sect); 02362 if (res != FR_OK) break; 02363 c = dp->dir[DIR_Name]; /* Test for the entry type */ 02364 if (c == 0) { 02365 res = FR_NO_FILE; break; /* Reached to end of the directory */ 02366 } 02367 #if FF_FS_EXFAT 02368 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02369 if (FF_USE_LABEL && vol) { 02370 if (c == 0x83) break; /* Volume label entry? */ 02371 } else { 02372 if (c == 0x85) { /* Start of the file entry block? */ 02373 dp->blk_ofs = dp->dptr; /* Get location of the block */ 02374 res = load_xdir(dp); /* Load the entry block */ 02375 if (res == FR_OK) { 02376 dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ 02377 } 02378 break; 02379 } 02380 } 02381 } else 02382 #endif 02383 { /* On the FAT/FAT32 volume */ 02384 dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ 02385 #if FF_USE_LFN /* LFN configuration */ 02386 if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ 02387 ord = 0xFF; 02388 } else { 02389 if (a == AM_LFN) { /* An LFN entry is found */ 02390 if (c & LLEF) { /* Is it start of an LFN sequence? */ 02391 sum = dp->dir[LDIR_Chksum]; 02392 c &= (BYTE)~LLEF; ord = c; 02393 dp->blk_ofs = dp->dptr; 02394 } 02395 /* Check LFN validity and capture it */ 02396 ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; 02397 } else { /* An SFN entry is found */ 02398 if (ord != 0 || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ 02399 dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ 02400 } 02401 break; 02402 } 02403 } 02404 #else /* Non LFN configuration */ 02405 if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ 02406 break; 02407 } 02408 #endif 02409 } 02410 res = dir_next(dp, 0); /* Next entry */ 02411 if (res != FR_OK) break; 02412 } 02413 02414 if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ 02415 return res; 02416 } 02417 02418 #endif /* FF_FS_MINIMIZE <= 1 || FF_USE_LABEL || FF_FS_RPATH >= 2 */ 02419 02420 02421 02422 /*-----------------------------------------------------------------------*/ 02423 /* Directory handling - Find an object in the directory */ 02424 /*-----------------------------------------------------------------------*/ 02425 02426 static 02427 FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ 02428 FATFS_DIR* dp /* Pointer to the directory object with the file name */ 02429 ) 02430 { 02431 FRESULT res; 02432 FATFS *fs = dp->obj.fs; 02433 BYTE c; 02434 #if FF_USE_LFN 02435 BYTE a, ord, sum; 02436 #endif 02437 02438 res = dir_sdi(dp, 0); /* Rewind directory object */ 02439 if (res != FR_OK) return res; 02440 #if FF_FS_EXFAT 02441 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02442 BYTE nc; 02443 UINT di, ni; 02444 WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ 02445 02446 while ((res = dir_read_file(dp)) == FR_OK) { /* Read an item */ 02447 #if FF_MAX_LFN < 255 02448 if (fs->dirbuf[XDIR_NumName] > FF_MAX_LFN) continue; /* Skip comparison if inaccessible object name */ 02449 #endif 02450 if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ 02451 for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ 02452 if ((di % SZDIRE) == 0) di += 2; 02453 if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; 02454 } 02455 if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ 02456 } 02457 return res; 02458 } 02459 #endif 02460 /* On the FAT/FAT32 volume */ 02461 #if FF_USE_LFN 02462 ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ 02463 #endif 02464 do { 02465 res = move_window(fs, dp->sect); 02466 if (res != FR_OK) break; 02467 c = dp->dir[DIR_Name]; 02468 if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ 02469 #if FF_USE_LFN /* LFN configuration */ 02470 dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; 02471 if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ 02472 ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ 02473 } else { 02474 if (a == AM_LFN) { /* An LFN entry is found */ 02475 if (!(dp->fn[NSFLAG] & NS_NOLFN)) { 02476 if (c & LLEF) { /* Is it start of LFN sequence? */ 02477 sum = dp->dir[LDIR_Chksum]; 02478 c &= (BYTE)~LLEF; ord = c; /* LFN start order */ 02479 dp->blk_ofs = dp->dptr; /* Start offset of LFN */ 02480 } 02481 /* Check validity of the LFN entry and compare it with given name */ 02482 ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; 02483 } 02484 } else { /* An SFN entry is found */ 02485 if (ord == 0 && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ 02486 if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ 02487 ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ 02488 } 02489 } 02490 #else /* Non LFN configuration */ 02491 dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; 02492 if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ 02493 #endif 02494 res = dir_next(dp, 0); /* Next entry */ 02495 } while (res == FR_OK); 02496 02497 return res; 02498 } 02499 02500 02501 02502 02503 #if !FF_FS_READONLY 02504 /*-----------------------------------------------------------------------*/ 02505 /* Register an object to the directory */ 02506 /*-----------------------------------------------------------------------*/ 02507 02508 static 02509 FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ 02510 FATFS_DIR* dp /* Target directory with object name to be created */ 02511 ) 02512 { 02513 FRESULT res; 02514 FATFS *fs = dp->obj.fs; 02515 #if FF_USE_LFN /* LFN configuration */ 02516 UINT n, nlen, nent; 02517 BYTE sn[12], sum; 02518 02519 02520 if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ 02521 for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ 02522 02523 #if FF_FS_EXFAT 02524 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02525 nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ 02526 res = dir_alloc(dp, nent); /* Allocate entries */ 02527 if (res != FR_OK) return res; 02528 dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ 02529 02530 if (dp->obj.stat & 4) { /* Has the directory been stretched? */ 02531 dp->obj.stat &= ~4; 02532 res = fill_first_frag(&dp->obj); /* Fill the first fragment on the FAT if needed */ 02533 if (res != FR_OK) return res; 02534 res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill the last fragment on the FAT if needed */ 02535 if (res != FR_OK) return res; 02536 if (dp->obj.sclust != 0) { /* Is it a sub directory? */ 02537 FATFS_DIR dj; 02538 02539 res = load_obj_xdir(&dj, &dp->obj); /* Load the object status */ 02540 if (res != FR_OK) return res; 02541 dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ 02542 st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ 02543 st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); 02544 fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; 02545 res = store_xdir(&dj); /* Store the object status */ 02546 if (res != FR_OK) return res; 02547 } 02548 } 02549 02550 create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ 02551 return FR_OK; 02552 } 02553 #endif 02554 /* On the FAT/FAT32 volume */ 02555 mem_cpy(sn, dp->fn, 12); 02556 if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ 02557 dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ 02558 for (n = 1; n < 100; n++) { 02559 gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ 02560 res = dir_find(dp); /* Check if the name collides with existing SFN */ 02561 if (res != FR_OK) break; 02562 } 02563 if (n == 100) return FR_DENIED; /* Abort if too many collisions */ 02564 if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ 02565 dp->fn[NSFLAG] = sn[NSFLAG]; 02566 } 02567 02568 /* Create an SFN with/without LFNs. */ 02569 nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ 02570 res = dir_alloc(dp, nent); /* Allocate entries */ 02571 if (res == FR_OK && --nent) { /* Set LFN entry if needed */ 02572 res = dir_sdi(dp, dp->dptr - nent * SZDIRE); 02573 if (res == FR_OK) { 02574 sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ 02575 do { /* Store LFN entries in bottom first */ 02576 res = move_window(fs, dp->sect); 02577 if (res != FR_OK) break; 02578 put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); 02579 fs->wflag = 1; 02580 res = dir_next(dp, 0); /* Next entry */ 02581 } while (res == FR_OK && --nent); 02582 } 02583 } 02584 02585 #else /* Non LFN configuration */ 02586 res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ 02587 02588 #endif 02589 02590 /* Set SFN entry */ 02591 if (res == FR_OK) { 02592 res = move_window(fs, dp->sect); 02593 if (res == FR_OK) { 02594 mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ 02595 mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ 02596 #if FF_USE_LFN 02597 dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ 02598 #endif 02599 fs->wflag = 1; 02600 } 02601 } 02602 02603 return res; 02604 } 02605 02606 #endif /* !FF_FS_READONLY */ 02607 02608 02609 02610 #if !FF_FS_READONLY && FF_FS_MINIMIZE == 0 02611 /*-----------------------------------------------------------------------*/ 02612 /* Remove an object from the directory */ 02613 /*-----------------------------------------------------------------------*/ 02614 02615 static 02616 FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ 02617 FATFS_DIR* dp /* Directory object pointing the entry to be removed */ 02618 ) 02619 { 02620 FRESULT res; 02621 FATFS *fs = dp->obj.fs; 02622 #if FF_USE_LFN /* LFN configuration */ 02623 DWORD last = dp->dptr; 02624 02625 res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ 02626 if (res == FR_OK) { 02627 do { 02628 res = move_window(fs, dp->sect); 02629 if (res != FR_OK) break; 02630 if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02631 dp->dir[XDIR_Type] &= 0x7F; /* Clear the entry InUse flag. */ 02632 } else { /* On the FAT/FAT32 volume */ 02633 dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'. */ 02634 } 02635 fs->wflag = 1; 02636 if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ 02637 res = dir_next(dp, 0); /* Next entry */ 02638 } while (res == FR_OK); 02639 if (res == FR_NO_FILE) res = FR_INT_ERR; 02640 } 02641 #else /* Non LFN configuration */ 02642 02643 res = move_window(fs, dp->sect); 02644 if (res == FR_OK) { 02645 dp->dir[DIR_Name] = DDEM; /* Mark the entry 'deleted'.*/ 02646 fs->wflag = 1; 02647 } 02648 #endif 02649 02650 return res; 02651 } 02652 02653 #endif /* !FF_FS_READONLY && FF_FS_MINIMIZE == 0 */ 02654 02655 02656 02657 #if FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 02658 /*-----------------------------------------------------------------------*/ 02659 /* Get file information from directory entry */ 02660 /*-----------------------------------------------------------------------*/ 02661 02662 static 02663 void get_fileinfo ( 02664 FATFS_DIR* dp, /* Pointer to the directory object */ 02665 FILINFO* fno /* Pointer to the file information to be filled */ 02666 ) 02667 { 02668 UINT si, di; 02669 #if FF_USE_LFN 02670 WCHAR wc, hs; 02671 FATFS *fs = dp->obj.fs; 02672 #else 02673 TCHAR c; 02674 #endif 02675 02676 02677 fno->fname[0] = 0; /* Invaidate file info */ 02678 if (dp->sect == 0) return; /* Exit if read pointer has reached end of directory */ 02679 02680 #if FF_USE_LFN /* LFN configuration */ 02681 #if FF_FS_EXFAT 02682 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 02683 get_xfileinfo(fs->dirbuf, fno); 02684 return; 02685 } else 02686 #endif 02687 { /* On the FAT/FAT32 volume */ 02688 if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ 02689 si = di = hs = 0; 02690 while (fs->lfnbuf[si] != 0) { 02691 wc = fs->lfnbuf[si++]; /* Get an LFN character (UTF-16) */ 02692 if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ 02693 hs = wc; continue; /* Get low surrogate */ 02694 } 02695 wc = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in UTF-16 or UTF-8 encoding */ 02696 if (wc == 0) { di = 0; break; } /* Invalid char or buffer overflow? */ 02697 di += wc; 02698 hs = 0; 02699 } 02700 if (hs != 0) di = 0; /* Broken surrogate pair? */ 02701 fno->fname[di] = 0; /* Terminate the LFN (null string means LFN is invalid) */ 02702 } 02703 } 02704 02705 si = di = 0; 02706 while (si < 11) { /* Get SFN from SFN entry */ 02707 wc = dp->dir[si++]; /* Get a char */ 02708 if (wc == ' ') continue; /* Skip padding spaces */ 02709 if (wc == RDDEM) wc = DDEM; /* Restore replaced DDEM character */ 02710 if (si == 9 && di < FF_SFN_BUF) fno->altname[di++] = '.'; /* Insert a . if extension is exist */ 02711 #if FF_LFN_UNICODE >= 1 /* Unicode output */ 02712 if (dbc_1st((BYTE)wc) && si != 8 && si != 11 && dbc_2nd(dp->dir[si])) { /* Make a DBC if needed */ 02713 wc = wc << 8 | dp->dir[si++]; 02714 } 02715 wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ 02716 if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ 02717 wc = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in UTF-16 or UTF-8 */ 02718 if (wc == 0) { di = 0; break; } /* Buffer overflow? */ 02719 di += wc; 02720 #else /* ANSI/OEM output */ 02721 fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ 02722 #endif 02723 } 02724 fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ 02725 02726 if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ 02727 if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ 02728 fno->fname[di++] = '?'; 02729 } else { 02730 for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ 02731 wc = (WCHAR)fno->altname[si]; 02732 if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; 02733 fno->fname[di] = (TCHAR)wc; 02734 } 02735 } 02736 fno->fname[di] = 0; /* Terminate the LFN */ 02737 if (!dp->dir[DIR_NTres]) fno->altname[0] = 0; /* Altname is not needed if neither LFN nor case info is exist. */ 02738 } 02739 02740 #else /* Non-LFN configuration */ 02741 si = di = 0; 02742 while (si < 11) { /* Copy name body and extension */ 02743 c = (TCHAR)dp->dir[si++]; 02744 if (c == ' ') continue; /* Skip padding spaces */ 02745 if (c == RDDEM) c = DDEM; /* Restore replaced DDEM character */ 02746 if (si == 9) fno->fname[di++] = '.';/* Insert a . if extension is exist */ 02747 fno->fname[di++] = c; 02748 } 02749 fno->fname[di] = 0; 02750 #endif 02751 02752 fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ 02753 fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ 02754 fno->ftime = ld_word(dp->dir + DIR_ModTime + 0); /* Time */ 02755 fno->fdate = ld_word(dp->dir + DIR_ModTime + 2); /* Date */ 02756 } 02757 02758 #endif /* FF_FS_MINIMIZE <= 1 || FF_FS_RPATH >= 2 */ 02759 02760 02761 02762 #if FF_USE_FIND && FF_FS_MINIMIZE <= 1 02763 /*-----------------------------------------------------------------------*/ 02764 /* Pattern matching */ 02765 /*-----------------------------------------------------------------------*/ 02766 02767 static 02768 DWORD get_achar ( /* Get a character and advances ptr */ 02769 const TCHAR** ptr /* Pointer to pointer to the ANSI/OEM or Unicode string */ 02770 ) 02771 { 02772 DWORD chr; 02773 02774 02775 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode input */ 02776 chr = tchar2uni(ptr); 02777 if (chr == 0xFFFFFFFF) chr = 0; /* Wrong UTF encoding is recognized as end of the string */ 02778 chr = ff_wtoupper(chr); 02779 02780 #else /* ANSI/OEM input */ 02781 chr = (BYTE)*(*ptr)++; /* Get a byte */ 02782 if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ 02783 #if FF_CODE_PAGE == 0 02784 if (ExCvt && chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ 02785 #elif FF_CODE_PAGE < 900 02786 if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ 02787 #endif 02788 #if FF_CODE_PAGE == 0 || FF_CODE_PAGE >= 900 02789 if (dbc_1st((BYTE)chr)) { /* Get DBC 2nd byte if needed */ 02790 chr = dbc_2nd((BYTE)**ptr) ? chr << 8 | (BYTE)*(*ptr)++ : 0; 02791 } 02792 #endif 02793 02794 #endif 02795 return chr; 02796 } 02797 02798 02799 static 02800 int pattern_matching ( /* 0:not matched, 1:matched */ 02801 const TCHAR* pat, /* Matching pattern */ 02802 const TCHAR* nam, /* String to be tested */ 02803 int skip, /* Number of pre-skip chars (number of ?s) */ 02804 int inf /* Infinite search (* specified) */ 02805 ) 02806 { 02807 const TCHAR *pp, *np; 02808 DWORD pc, nc; 02809 int nm, nx; 02810 02811 02812 while (skip--) { /* Pre-skip name chars */ 02813 if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ 02814 } 02815 if (*pat == 0 && inf) return 1; /* (short circuit) */ 02816 02817 do { 02818 pp = pat; np = nam; /* Top of pattern and name to match */ 02819 for (;;) { 02820 if (*pp == '?' || *pp == '*') { /* Wildcard? */ 02821 nm = nx = 0; 02822 do { /* Analyze the wildcard block */ 02823 if (*pp++ == '?') nm++; else nx = 1; 02824 } while (*pp == '?' || *pp == '*'); 02825 if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ 02826 nc = *np; break; /* Branch mismatched */ 02827 } 02828 pc = get_achar(&pp); /* Get a pattern char */ 02829 nc = get_achar(&np); /* Get a name char */ 02830 if (pc != nc) break; /* Branch mismatched? */ 02831 if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ 02832 } 02833 get_achar(&nam); /* nam++ */ 02834 } while (inf && nc); /* Retry until end of name if infinite search is specified */ 02835 02836 return 0; 02837 } 02838 02839 #endif /* FF_USE_FIND && FF_FS_MINIMIZE <= 1 */ 02840 02841 02842 02843 /*-----------------------------------------------------------------------*/ 02844 /* Pick a top segment and create the object name in directory form */ 02845 /*-----------------------------------------------------------------------*/ 02846 02847 static 02848 FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ 02849 FATFS_DIR* dp, /* Pointer to the directory object */ 02850 const TCHAR** path /* Pointer to pointer to the segment in the path string */ 02851 ) 02852 { 02853 #if FF_USE_LFN /* LFN configuration */ 02854 BYTE b, cf; 02855 WCHAR wc, *lfn; 02856 DWORD uc; 02857 UINT i, ni, si, di; 02858 const TCHAR *p; 02859 02860 02861 /* Create LFN into LFN working buffer */ 02862 p = *path; lfn = dp->obj.fs->lfnbuf; di = 0; 02863 for (;;) { 02864 uc = tchar2uni(&p); /* Get a character */ 02865 if (uc == 0xFFFFFFFF) return FR_INVALID_NAME; /* Invalid code or UTF decode error */ 02866 if (uc >= 0x10000) lfn[di++] = (WCHAR)(uc >> 16); /* Store high surrogate if needed */ 02867 wc = (WCHAR)uc; 02868 if (wc < ' ' || wc == '/' || wc == '\\') break; /* Break if end of the path or a separator is found */ 02869 if (wc < 0x80 && chk_chr("\"*:<>\?|\x7F", wc)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ 02870 if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ 02871 lfn[di++] = wc; /* Store the Unicode character */ 02872 } 02873 while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ 02874 *path = p; /* Return pointer to the next segment */ 02875 cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ 02876 02877 #if FF_FS_RPATH != 0 02878 if ((di == 1 && lfn[di - 1] == '.') || 02879 (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ 02880 lfn[di] = 0; 02881 for (i = 0; i < 11; i++) { /* Create dot name for SFN entry */ 02882 dp->fn[i] = (i < di) ? '.' : ' '; 02883 } 02884 dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ 02885 return FR_OK; 02886 } 02887 #endif 02888 while (di) { /* Snip off trailing spaces and dots if exist */ 02889 wc = lfn[di - 1]; 02890 if (wc != ' ' && wc != '.') break; 02891 di--; 02892 } 02893 lfn[di] = 0; /* LFN is created into the working buffer */ 02894 if (di == 0) return FR_INVALID_NAME; /* Reject null name */ 02895 02896 /* Create SFN in directory form */ 02897 for (si = 0; lfn[si] == ' '; si++) ; /* Remove leading spaces */ 02898 if (si > 0 || lfn[si] == '.') cf |= NS_LOSS | NS_LFN; /* Is there any leading space or dot? */ 02899 while (di > 0 && lfn[di - 1] != '.') di--; /* Find last dot (di<=si: no extension) */ 02900 02901 mem_set(dp->fn, ' ', 11); 02902 i = b = 0; ni = 8; 02903 for (;;) { 02904 wc = lfn[si++]; /* Get an LFN character */ 02905 if (wc == 0) break; /* Break on end of the LFN */ 02906 if (wc == ' ' || (wc == '.' && si != di)) { /* Remove embedded spaces and dots */ 02907 cf |= NS_LOSS | NS_LFN; 02908 continue; 02909 } 02910 02911 if (i >= ni || si == di) { /* End of field? */ 02912 if (ni == 11) { /* Name extension overflow? */ 02913 cf |= NS_LOSS | NS_LFN; 02914 break; 02915 } 02916 if (si != di) cf |= NS_LOSS | NS_LFN; /* Name body overflow? */ 02917 if (si > di) break; /* No name extension? */ 02918 si = di; i = 8; ni = 11; b <<= 2; /* Enter name extension */ 02919 continue; 02920 } 02921 02922 if (wc >= 0x80) { /* Is this a non-ASCII character? */ 02923 cf |= NS_LFN; /* LFN entry needs to be created */ 02924 #if FF_CODE_PAGE == 0 02925 if (ExCvt) { /* At SBCS */ 02926 wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ 02927 if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ 02928 } else { /* At DBCS */ 02929 wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ 02930 } 02931 #elif FF_CODE_PAGE < 900 /* SBCS cfg */ 02932 wc = ff_uni2oem(wc, CODEPAGE); /* Unicode ==> ANSI/OEM code */ 02933 if (wc & 0x80) wc = ExCvt[wc & 0x7F]; /* Convert extended character to upper (SBCS) */ 02934 #else /* DBCS cfg */ 02935 wc = ff_uni2oem(ff_wtoupper(wc), CODEPAGE); /* Unicode ==> Upper convert ==> ANSI/OEM code */ 02936 #endif 02937 } 02938 02939 if (wc >= 0x100) { /* Is this a DBC? */ 02940 if (i >= ni - 1) { /* Field overflow? */ 02941 cf |= NS_LOSS | NS_LFN; 02942 i = ni; continue; /* Next field */ 02943 } 02944 dp->fn[i++] = (BYTE)(wc >> 8); /* Put 1st byte */ 02945 } else { /* SBC */ 02946 if (wc == 0 || chk_chr("+,;=[]", wc)) { /* Replace illegal characters for SFN if needed */ 02947 wc = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ 02948 } else { 02949 if (IsUpper(wc)) { /* ASCII upper case? */ 02950 b |= 2; 02951 } 02952 if (IsLower(wc)) { /* ASCII lower case? */ 02953 b |= 1; wc -= 0x20; 02954 } 02955 } 02956 } 02957 dp->fn[i++] = (BYTE)wc; 02958 } 02959 02960 if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ 02961 02962 if (ni == 8) b <<= 2; /* Shift capital flags if no extension */ 02963 if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* LFN entry needs to be created if composite capitals */ 02964 if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ 02965 if (b & 0x01) cf |= NS_EXT; /* NT flag (Extension has small capital letters only) */ 02966 if (b & 0x04) cf |= NS_BODY; /* NT flag (Body has small capital letters only) */ 02967 } 02968 02969 dp->fn[NSFLAG] = cf; /* SFN is created into dp->fn[] */ 02970 02971 return FR_OK; 02972 02973 02974 #else /* FF_USE_LFN : Non-LFN configuration */ 02975 BYTE c, d, *sfn; 02976 UINT ni, si, i; 02977 const char *p; 02978 02979 /* Create file name in directory form */ 02980 p = *path; sfn = dp->fn; 02981 mem_set(sfn, ' ', 11); 02982 si = i = 0; ni = 8; 02983 #if FF_FS_RPATH != 0 02984 if (p[si] == '.') { /* Is this a dot entry? */ 02985 for (;;) { 02986 c = (BYTE)p[si++]; 02987 if (c != '.' || si >= 3) break; 02988 sfn[i++] = c; 02989 } 02990 if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; 02991 *path = p + si; /* Return pointer to the next segment */ 02992 sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ 02993 return FR_OK; 02994 } 02995 #endif 02996 for (;;) { 02997 c = (BYTE)p[si++]; /* Get a byte */ 02998 if (c <= ' ') break; /* Break if end of the path name */ 02999 if (c == '/' || c == '\\') { /* Break if a separator is found */ 03000 while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ 03001 break; 03002 } 03003 if (c == '.' || i >= ni) { /* End of body or field overflow? */ 03004 if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Field overflow or invalid dot? */ 03005 i = 8; ni = 11; /* Enter file extension field */ 03006 continue; 03007 } 03008 #if FF_CODE_PAGE == 0 03009 if (ExCvt && c >= 0x80) { /* Is SBC extended character? */ 03010 c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ 03011 } 03012 #elif FF_CODE_PAGE < 900 03013 if (c >= 0x80) { /* Is SBC extended character? */ 03014 c = ExCvt[c & 0x7F]; /* To upper SBC extended character */ 03015 } 03016 #endif 03017 if (dbc_1st(c)) { /* Check if it is a DBC 1st byte */ 03018 d = (BYTE)p[si++]; /* Get 2nd byte */ 03019 if (!dbc_2nd(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ 03020 sfn[i++] = c; 03021 sfn[i++] = d; 03022 } else { /* SBC */ 03023 if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ 03024 if (IsLower(c)) c -= 0x20; /* To upper */ 03025 sfn[i++] = c; 03026 } 03027 } 03028 *path = p + si; /* Return pointer to the next segment */ 03029 if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ 03030 03031 if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ 03032 sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ 03033 03034 return FR_OK; 03035 #endif /* FF_USE_LFN */ 03036 } 03037 03038 03039 03040 03041 /*-----------------------------------------------------------------------*/ 03042 /* Follow a file path */ 03043 /*-----------------------------------------------------------------------*/ 03044 03045 static 03046 FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ 03047 FATFS_DIR* dp, /* Directory object to return last directory and found object */ 03048 const TCHAR* path /* Full-path string to find a file or directory */ 03049 ) 03050 { 03051 FRESULT res; 03052 BYTE ns; 03053 FATFS *fs = dp->obj.fs; 03054 03055 03056 #if FF_FS_RPATH != 0 03057 if (*path != '/' && *path != '\\') { /* Without heading separator */ 03058 dp->obj.sclust = fs->cdir; /* Start from current directory */ 03059 } else 03060 #endif 03061 { /* With heading separator */ 03062 while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ 03063 dp->obj.sclust = 0; /* Start from root directory */ 03064 } 03065 #if FF_FS_EXFAT 03066 dp->obj.n_frag = 0; /* Invalidate last fragment counter of the object */ 03067 #if FF_FS_RPATH != 0 03068 if (fs->fs_type == FS_EXFAT && dp->obj.sclust) { /* exFAT: Retrieve the sub-directory's status */ 03069 FATFS_DIR dj; 03070 03071 dp->obj.c_scl = fs->cdc_scl; 03072 dp->obj.c_size = fs->cdc_size; 03073 dp->obj.c_ofs = fs->cdc_ofs; 03074 res = load_obj_xdir(&dj, &dp->obj); 03075 if (res != FR_OK) return res; 03076 dp->obj.objsize = ld_dword(fs->dirbuf + XDIR_FileSize); 03077 dp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; 03078 } 03079 #endif 03080 #endif 03081 03082 if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ 03083 dp->fn[NSFLAG] = NS_NONAME; 03084 res = dir_sdi(dp, 0); 03085 03086 } else { /* Follow path */ 03087 for (;;) { 03088 res = create_name(dp, &path); /* Get a segment name of the path */ 03089 if (res != FR_OK) break; 03090 res = dir_find(dp); /* Find an object with the segment name */ 03091 ns = dp->fn[NSFLAG]; 03092 if (res != FR_OK) { /* Failed to find the object */ 03093 if (res == FR_NO_FILE) { /* Object is not found */ 03094 if (FF_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ 03095 if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ 03096 dp->fn[NSFLAG] = NS_NONAME; 03097 res = FR_OK; 03098 } else { /* Could not find the object */ 03099 if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ 03100 } 03101 } 03102 break; 03103 } 03104 if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ 03105 /* Get into the sub-directory */ 03106 if (!(dp->obj.attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ 03107 res = FR_NO_PATH; break; 03108 } 03109 #if FF_FS_EXFAT 03110 if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ 03111 dp->obj.c_scl = dp->obj.sclust; 03112 dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; 03113 dp->obj.c_ofs = dp->blk_ofs; 03114 init_alloc_info(fs, &dp->obj); /* Open next directory */ 03115 } else 03116 #endif 03117 { 03118 dp->obj.sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ 03119 } 03120 } 03121 } 03122 03123 return res; 03124 } 03125 03126 03127 03128 03129 /*-----------------------------------------------------------------------*/ 03130 /* Get logical drive number from path name */ 03131 /*-----------------------------------------------------------------------*/ 03132 03133 static 03134 int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ 03135 const TCHAR** path /* Pointer to pointer to the path name */ 03136 ) 03137 { 03138 const TCHAR *tp, *tt; 03139 UINT i; 03140 int vol = -1; 03141 #if FF_STR_VOLUME_ID /* Find string drive id */ 03142 static const char* const volid[] = {FF_VOLUME_STRS}; 03143 const char *sp; 03144 char c; 03145 TCHAR tc; 03146 #endif 03147 03148 03149 if (*path != 0) { /* If the pointer is not a null */ 03150 for (tt = *path; (UINT)*tt >= (FF_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find a colon in the path */ 03151 if (*tt == ':') { /* If a colon is exist in the path name */ 03152 tp = *path; 03153 i = *tp++; 03154 if (IsDigit(i) && tp == tt) { /* Is there a numeric drive id + colon? */ 03155 if ((i -= '0') < FF_VOLUMES) { /* If drive id is found, get the value and strip it */ 03156 vol = (int)i; 03157 *path = ++tt; 03158 } 03159 } 03160 #if FF_STR_VOLUME_ID 03161 else { /* No numeric drive number, find string drive id */ 03162 i = 0; tt++; 03163 do { 03164 sp = volid[i]; tp = *path; 03165 do { /* Compare a string drive id with path name */ 03166 c = *sp++; tc = *tp++; 03167 if (IsLower(tc)) tc -= 0x20; 03168 } while (c && (TCHAR)c == tc); 03169 } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ 03170 if (i < FF_VOLUMES) { /* If a drive id is found, get the value and strip it */ 03171 vol = (int)i; 03172 *path = tt; 03173 } 03174 } 03175 #endif 03176 } else { /* No volume id and use default drive */ 03177 #if FF_FS_RPATH != 0 && FF_VOLUMES >= 2 03178 vol = CurrVol; /* Current drive */ 03179 #else 03180 vol = 0; /* Drive 0 */ 03181 #endif 03182 } 03183 } 03184 return vol; 03185 } 03186 03187 03188 03189 03190 /*-----------------------------------------------------------------------*/ 03191 /* Load a sector and check if it is an FAT VBR */ 03192 /*-----------------------------------------------------------------------*/ 03193 03194 static 03195 BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ 03196 FATFS* fs, /* Filesystem object */ 03197 DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ 03198 ) 03199 { 03200 fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ 03201 if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ 03202 03203 if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */ 03204 03205 #if FF_FS_EXFAT 03206 if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; /* Check if exFAT VBR */ 03207 #endif 03208 if (fs->win[BS_JmpBoot] == 0xE9 || fs->win[BS_JmpBoot] == 0xEB || fs->win[BS_JmpBoot] == 0xE8) { /* Valid JumpBoot code? */ 03209 if (!mem_cmp(fs->win + BS_FilSysType, "FAT", 3)) return 0; /* Is it an FAT VBR? */ 03210 if (!mem_cmp(fs->win + BS_FilSysType32, "FAT32", 5)) return 0; /* Is it an FAT32 VBR? */ 03211 } 03212 return 2; /* Valid BS but not FAT */ 03213 } 03214 03215 03216 03217 03218 /*-----------------------------------------------------------------------*/ 03219 /* Determine logical drive number and mount the volume if needed */ 03220 /*-----------------------------------------------------------------------*/ 03221 03222 static 03223 FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ 03224 const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ 03225 FATFS** rfs, /* Pointer to pointer to the found filesystem object */ 03226 BYTE mode /* !=0: Check write protection for write access */ 03227 ) 03228 { 03229 BYTE fmt, *pt; 03230 int vol; 03231 DSTATUS stat; 03232 DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; 03233 WORD nrsv; 03234 FATFS *fs; 03235 UINT i; 03236 03237 03238 /* Get logical drive number */ 03239 *rfs = 0; 03240 vol = get_ldnumber(path); 03241 if (vol < 0) return FR_INVALID_DRIVE; 03242 03243 /* Check if the filesystem object is valid or not */ 03244 fs = FatFs[vol]; /* Get pointer to the filesystem object */ 03245 if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ 03246 #if FF_FS_REENTRANT 03247 if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ 03248 #endif 03249 *rfs = fs; /* Return pointer to the filesystem object */ 03250 03251 mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ 03252 if (fs->fs_type != 0) { /* If the volume has been mounted */ 03253 stat = disk_status(fs->pdrv); 03254 if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ 03255 if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ 03256 return FR_WRITE_PROTECTED; 03257 } 03258 return FR_OK; /* The filesystem object is valid */ 03259 } 03260 } 03261 03262 /* The filesystem object is not valid. */ 03263 /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ 03264 03265 fs->fs_type = 0; /* Clear the filesystem object */ 03266 fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ 03267 stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ 03268 if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ 03269 return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ 03270 } 03271 if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ 03272 return FR_WRITE_PROTECTED; 03273 } 03274 #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ 03275 if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; 03276 if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; 03277 #endif 03278 03279 #if FF_FS_HEAPBUF 03280 if (!fs->win) { 03281 fs->win = (BYTE*)ff_memalloc(SS(fs)); /* Allocate buffer to back window if necessary */ 03282 if (!fs->win) 03283 return FR_NOT_ENOUGH_CORE; 03284 } 03285 #endif 03286 03287 /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ 03288 bsect = 0; 03289 fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ 03290 if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ 03291 for (i = 0; i < 4; i++) { /* Get partition offset */ 03292 pt = fs->win + (MBR_Table + i * SZ_PTE); 03293 br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; 03294 } 03295 i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ 03296 if (i != 0) i--; 03297 do { /* Find an FAT volume */ 03298 bsect = br[i]; 03299 fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ 03300 } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); 03301 } 03302 if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ 03303 if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ 03304 03305 /* An FAT volume is found (bsect). Following code initializes the filesystem object */ 03306 03307 #if FF_FS_EXFAT 03308 if (fmt == 1) { 03309 QWORD maxlba; 03310 03311 for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ 03312 if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; 03313 03314 if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT version (must be version 1.0) */ 03315 03316 if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ 03317 return FR_NO_FILESYSTEM; 03318 } 03319 03320 maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ 03321 if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ 03322 03323 fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ 03324 03325 fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ 03326 if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ 03327 03328 fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ 03329 if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ 03330 03331 nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ 03332 if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ 03333 fs->n_fatent = nclst + 2; 03334 03335 /* Boundaries and Limits */ 03336 fs->volbase = bsect; 03337 fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); 03338 fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); 03339 if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ 03340 fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); 03341 03342 /* Check if bitmap location is in assumption (at the first cluster) */ 03343 if (move_window(fs, clst2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; 03344 for (i = 0; i < SS(fs); i += SZDIRE) { 03345 if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ 03346 } 03347 if (i == SS(fs)) return FR_NO_FILESYSTEM; 03348 #if !FF_FS_READONLY 03349 fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ 03350 #endif 03351 fmt = FS_EXFAT; /* FAT sub-type */ 03352 } else 03353 #endif /* FF_FS_EXFAT */ 03354 { 03355 if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ 03356 03357 fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ 03358 if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); 03359 fs->fsize = fasize; 03360 03361 fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ 03362 if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ 03363 fasize *= fs->n_fats; /* Number of sectors for FAT area */ 03364 03365 fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ 03366 if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ 03367 03368 fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ 03369 if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ 03370 03371 tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ 03372 if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); 03373 03374 nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ 03375 if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ 03376 03377 /* Determine the FAT sub type */ 03378 sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + FATFS_DIR */ 03379 if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 03380 nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ 03381 if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ 03382 fmt = 0; 03383 if (nclst <= MAX_FAT32) fmt = FS_FAT32; 03384 if (nclst <= MAX_FAT16) fmt = FS_FAT16; 03385 if (nclst <= MAX_FAT12) fmt = FS_FAT12; 03386 if (fmt == 0) return FR_NO_FILESYSTEM; 03387 03388 /* Boundaries and Limits */ 03389 fs->n_fatent = nclst + 2; /* Number of FAT entries */ 03390 fs->volbase = bsect; /* Volume start sector */ 03391 fs->fatbase = bsect + nrsv; /* FAT start sector */ 03392 fs->database = bsect + sysect; /* Data start sector */ 03393 if (fmt == FS_FAT32) { 03394 if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ 03395 if (fs->n_rootdir != 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ 03396 fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ 03397 szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ 03398 } else { 03399 if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ 03400 fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ 03401 szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ 03402 fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); 03403 } 03404 if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ 03405 03406 #if !FF_FS_READONLY 03407 /* Get FSInfo if available */ 03408 fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ 03409 fs->fsi_flag = 0x80; 03410 #if (FF_FS_NOFSINFO & 3) != 3 03411 if (fmt == FS_FAT32 /* Allow to update FSInfo only if BPB_FSInfo32 == 1 */ 03412 && ld_word(fs->win + BPB_FSInfo32) == 1 03413 && move_window(fs, bsect + 1) == FR_OK) 03414 { 03415 fs->fsi_flag = 0; 03416 if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSInfo data if available */ 03417 && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 03418 && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) 03419 { 03420 #if (FF_FS_NOFSINFO & 1) == 0 03421 fs->free_clst = ld_dword(fs->win + FSI_Free_Count); 03422 #endif 03423 #if (FF_FS_NOFSINFO & 2) == 0 03424 fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); 03425 #endif 03426 } 03427 } 03428 #endif /* (FF_FS_NOFSINFO & 3) != 3 */ 03429 #endif /* !FF_FS_READONLY */ 03430 } 03431 03432 fs->fs_type = fmt; /* FAT sub-type */ 03433 fs->id = ++Fsid; /* Volume mount ID */ 03434 #if FF_USE_LFN == 1 03435 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ 03436 #if FF_FS_EXFAT 03437 fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ 03438 #endif 03439 #endif 03440 #if FF_FS_RPATH != 0 03441 fs->cdir = 0; /* Initialize current directory */ 03442 #endif 03443 #if FF_FS_LOCK != 0 /* Clear file lock semaphores */ 03444 clear_lock(fs); 03445 #endif 03446 return FR_OK; 03447 } 03448 03449 03450 03451 03452 /*-----------------------------------------------------------------------*/ 03453 /* Check if the file/directory object is valid or not */ 03454 /*-----------------------------------------------------------------------*/ 03455 03456 static 03457 FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ 03458 FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/FATFS_DIR object, to check validity */ 03459 FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ 03460 ) 03461 { 03462 FRESULT res = FR_INVALID_OBJECT; 03463 03464 03465 if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ 03466 #if FF_FS_REENTRANT 03467 if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ 03468 if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ 03469 res = FR_OK; 03470 } else { 03471 unlock_fs(obj->fs, FR_OK); 03472 } 03473 } else { 03474 res = FR_TIMEOUT; 03475 } 03476 #else 03477 if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ 03478 res = FR_OK; 03479 } 03480 #endif 03481 } 03482 *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ 03483 return res; 03484 } 03485 03486 03487 03488 03489 /*--------------------------------------------------------------------------- 03490 03491 Public Functions (FatFs API) 03492 03493 ----------------------------------------------------------------------------*/ 03494 03495 03496 03497 /*-----------------------------------------------------------------------*/ 03498 /* Mount/Unmount a Logical Drive */ 03499 /*-----------------------------------------------------------------------*/ 03500 03501 FRESULT f_mount ( 03502 FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ 03503 const TCHAR* path, /* Logical drive number to be mounted/unmounted */ 03504 BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ 03505 ) 03506 { 03507 FATFS *cfs; 03508 int vol; 03509 FRESULT res; 03510 const TCHAR *rp = path; 03511 03512 03513 /* Get logical drive number */ 03514 vol = get_ldnumber(&rp); 03515 if (vol < 0) return FR_INVALID_DRIVE; 03516 cfs = FatFs[vol]; /* Pointer to fs object */ 03517 03518 if (cfs) { 03519 #if FF_FS_LOCK != 0 03520 clear_lock(cfs); 03521 #endif 03522 #if FF_FS_REENTRANT /* Discard sync object of the current volume */ 03523 if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; 03524 #endif 03525 cfs->fs_type = 0; /* Clear old fs object */ 03526 #if FF_FS_HEAPBUF 03527 ff_memfree(cfs->win); /* Clean up window buffer */ 03528 #endif 03529 } 03530 03531 if (fs) { 03532 fs->fs_type = 0; /* Clear new fs object */ 03533 #if FF_FS_REENTRANT /* Create sync object for the new volume */ 03534 if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; 03535 #endif 03536 #if FF_FS_HEAPBUF 03537 fs->win = 0; /* NULL buffer to prevent use of uninitialized buffer */ 03538 #endif 03539 } 03540 FatFs[vol] = fs; /* Register new fs object */ 03541 03542 if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ 03543 03544 res = find_volume(&path, &fs, 0); /* Force mounted the volume */ 03545 LEAVE_FF(fs, res); 03546 } 03547 03548 03549 03550 03551 /*-----------------------------------------------------------------------*/ 03552 /* Open or Create a File */ 03553 /*-----------------------------------------------------------------------*/ 03554 03555 FRESULT f_open ( 03556 FIL* fp, /* Pointer to the blank file object */ 03557 const TCHAR* path, /* Pointer to the file name */ 03558 BYTE mode /* Access mode and file open mode flags */ 03559 ) 03560 { 03561 FRESULT res; 03562 FATFS_DIR dj; 03563 FATFS *fs; 03564 #if !FF_FS_READONLY 03565 DWORD dw, cl, bcs, clst, sc; 03566 FSIZE_t ofs; 03567 #endif 03568 DEF_NAMBUF 03569 03570 03571 if (!fp) return FR_INVALID_OBJECT; 03572 03573 /* Get logical drive */ 03574 mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; 03575 res = find_volume(&path, &fs, mode); 03576 if (res == FR_OK) { 03577 dj.obj.fs = fs; 03578 INIT_NAMBUF(fs); 03579 res = follow_path(&dj, path); /* Follow the file path */ 03580 #if !FF_FS_READONLY /* Read/Write configuration */ 03581 if (res == FR_OK) { 03582 if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ 03583 res = FR_INVALID_NAME; 03584 } 03585 #if FF_FS_LOCK != 0 03586 else { 03587 res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ 03588 } 03589 #endif 03590 } 03591 /* Create or Open a file */ 03592 if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { 03593 if (res != FR_OK) { /* No file, create new */ 03594 if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ 03595 #if FF_FS_LOCK != 0 03596 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; 03597 #else 03598 res = dir_register(&dj); 03599 #endif 03600 } 03601 mode |= FA_CREATE_ALWAYS; /* File is created */ 03602 } 03603 else { /* Any object with the same name is already existing */ 03604 if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or FATFS_DIR) */ 03605 res = FR_DENIED; 03606 } else { 03607 if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ 03608 } 03609 } 03610 if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate the file if overwrite mode */ 03611 #if FF_FS_EXFAT 03612 if (fs->fs_type == FS_EXFAT) { 03613 /* Get current allocation info */ 03614 fp->obj.fs = fs; 03615 init_alloc_info(fs, &fp->obj); 03616 /* Set directory entry block initial state */ 03617 mem_set(fs->dirbuf + 2, 0, 30); /* Clear 85 entry except for NumSec */ 03618 mem_set(fs->dirbuf + 38, 0, 26); /* Clear C0 entry except for NumName and NameHash */ 03619 fs->dirbuf[XDIR_Attr] = AM_ARC; 03620 st_dword(fs->dirbuf + XDIR_CrtTime, GET_FATTIME()); 03621 fs->dirbuf[XDIR_GenFlags] = 1; 03622 res = store_xdir(&dj); 03623 if (res == FR_OK && fp->obj.sclust != 0) { /* Remove the cluster chain if exist */ 03624 res = remove_chain(&fp->obj, fp->obj.sclust, 0); 03625 fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ 03626 } 03627 } else 03628 #endif 03629 { 03630 /* Set directory entry initial state */ 03631 cl = ld_clust(fs, dj.dir); /* Get current cluster chain */ 03632 st_dword(dj.dir + DIR_CrtTime, GET_FATTIME()); /* Set created time */ 03633 dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ 03634 st_clust(fs, dj.dir, 0); /* Reset file allocation info */ 03635 st_dword(dj.dir + DIR_FileSize, 0); 03636 fs->wflag = 1; 03637 if (cl != 0) { /* Remove the cluster chain if exist */ 03638 dw = fs->winsect; 03639 res = remove_chain(&dj.obj, cl, 0); 03640 if (res == FR_OK) { 03641 res = move_window(fs, dw); 03642 fs->last_clst = cl - 1; /* Reuse the cluster hole */ 03643 } 03644 } 03645 } 03646 } 03647 } 03648 else { /* Open an existing file */ 03649 if (res == FR_OK) { /* Is the object exsiting? */ 03650 if (dj.obj.attr & AM_DIR) { /* File open against a directory */ 03651 res = FR_NO_FILE; 03652 } else { 03653 if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* Write mode open against R/O file */ 03654 res = FR_DENIED; 03655 } 03656 } 03657 } 03658 } 03659 if (res == FR_OK) { 03660 if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ 03661 fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ 03662 fp->dir_ptr = dj.dir; 03663 #if FF_FS_LOCK != 0 03664 fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ 03665 if (fp->obj.lockid == 0) res = FR_INT_ERR; 03666 #endif 03667 } 03668 #else /* R/O configuration */ 03669 if (res == FR_OK) { 03670 if (dj.fn[NSFLAG] & NS_NONAME) { /* Is it origin directory itself? */ 03671 res = FR_INVALID_NAME; 03672 } else { 03673 if (dj.obj.attr & AM_DIR) { /* Is it a directory? */ 03674 res = FR_NO_FILE; 03675 } 03676 } 03677 } 03678 #endif 03679 03680 if (res == FR_OK) { 03681 #if FF_FS_EXFAT 03682 if (fs->fs_type == FS_EXFAT) { 03683 fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ 03684 fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; 03685 fp->obj.c_ofs = dj.blk_ofs; 03686 init_alloc_info(fs, &fp->obj); 03687 } else 03688 #endif 03689 { 03690 fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ 03691 fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); 03692 } 03693 #if FF_USE_FASTSEEK 03694 fp->cltbl = 0; /* Disable fast seek mode */ 03695 #endif 03696 fp->obj.fs = fs; /* Validate the file object */ 03697 fp->obj.id = fs->id; 03698 fp->flag = mode; /* Set file access mode */ 03699 fp->err = 0; /* Clear error flag */ 03700 fp->sect = 0; /* Invalidate current data sector */ 03701 fp->fptr = 0; /* Set file pointer top of the file */ 03702 #if !FF_FS_READONLY 03703 #if !FF_FS_TINY 03704 #if FF_FS_HEAPBUF 03705 fp->buf = (BYTE*)ff_memalloc(SS(dj.obj.fs)); /* Allocate buffer if necessary */ 03706 if (!fp->buf) 03707 return FR_NOT_ENOUGH_CORE; 03708 #endif 03709 mem_set(fp->buf, 0, FF_MAX_SS); /* Clear sector buffer */ 03710 #endif 03711 if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ 03712 fp->fptr = fp->obj.objsize; /* Offset to seek */ 03713 bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ 03714 clst = fp->obj.sclust; /* Follow the cluster chain */ 03715 for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { 03716 clst = get_fat(&fp->obj, clst); 03717 if (clst <= 1) res = FR_INT_ERR; 03718 if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; 03719 } 03720 fp->clust = clst; 03721 if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ 03722 if ((sc = clst2sect(fs, clst)) == 0) { 03723 res = FR_INT_ERR; 03724 } else { 03725 fp->sect = sc + (DWORD)(ofs / SS(fs)); 03726 #if !FF_FS_TINY 03727 if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; 03728 #endif 03729 } 03730 } 03731 } 03732 #endif 03733 } 03734 03735 FREE_NAMBUF(); 03736 } 03737 03738 if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ 03739 03740 LEAVE_FF(fs, res); 03741 } 03742 03743 03744 03745 03746 /*-----------------------------------------------------------------------*/ 03747 /* Read File */ 03748 /*-----------------------------------------------------------------------*/ 03749 03750 FRESULT f_read ( 03751 FIL* fp, /* Pointer to the file object */ 03752 void* buff, /* Pointer to data buffer */ 03753 UINT btr, /* Number of bytes to read */ 03754 UINT* br /* Pointer to number of bytes read */ 03755 ) 03756 { 03757 FRESULT res; 03758 FATFS *fs; 03759 DWORD clst, sect; 03760 FSIZE_t remain; 03761 UINT rcnt, cc, csect; 03762 BYTE *rbuff = (BYTE*)buff; 03763 03764 03765 *br = 0; /* Clear read byte counter */ 03766 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 03767 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ 03768 if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 03769 remain = fp->obj.objsize - fp->fptr; 03770 if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ 03771 03772 for ( ; btr; /* Repeat until all data read */ 03773 btr -= rcnt, *br += rcnt, rbuff += rcnt, fp->fptr += rcnt) { 03774 if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ 03775 csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ 03776 if (csect == 0) { /* On the cluster boundary? */ 03777 if (fp->fptr == 0) { /* On the top of the file? */ 03778 clst = fp->obj.sclust; /* Follow cluster chain from the origin */ 03779 } else { /* Middle or end of the file */ 03780 #if FF_USE_FASTSEEK 03781 if (fp->cltbl) { 03782 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 03783 } else 03784 #endif 03785 { 03786 clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ 03787 } 03788 } 03789 if (clst < 2) ABORT(fs, FR_INT_ERR); 03790 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 03791 fp->clust = clst; /* Update current cluster */ 03792 } 03793 sect = clst2sect(fs, fp->clust); /* Get current sector */ 03794 if (sect == 0) ABORT(fs, FR_INT_ERR); 03795 sect += csect; 03796 cc = btr / SS(fs); /* When remaining bytes >= sector size, */ 03797 if (cc > 0) { /* Read maximum contiguous sectors directly */ 03798 if (csect + cc > fs->csize) { /* Clip at cluster boundary */ 03799 cc = fs->csize - csect; 03800 } 03801 if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); 03802 #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ 03803 #if FF_FS_TINY 03804 if (fs->wflag && fs->winsect - sect < cc) { 03805 mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); 03806 } 03807 #else 03808 if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { 03809 mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); 03810 } 03811 #endif 03812 #endif 03813 rcnt = SS(fs) * cc; /* Number of bytes transferred */ 03814 continue; 03815 } 03816 #if !FF_FS_TINY 03817 if (fp->sect != sect) { /* Load data sector if not in cache */ 03818 #if !FF_FS_READONLY 03819 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 03820 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 03821 fp->flag &= (BYTE)~FA_DIRTY; 03822 } 03823 #endif 03824 if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ 03825 } 03826 #endif 03827 fp->sect = sect; 03828 } 03829 rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ 03830 if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ 03831 #if FF_FS_TINY 03832 if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ 03833 mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ 03834 #else 03835 mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ 03836 #endif 03837 } 03838 03839 LEAVE_FF(fs, FR_OK); 03840 } 03841 03842 03843 03844 03845 #if !FF_FS_READONLY 03846 /*-----------------------------------------------------------------------*/ 03847 /* Write File */ 03848 /*-----------------------------------------------------------------------*/ 03849 03850 FRESULT f_write ( 03851 FIL* fp, /* Pointer to the file object */ 03852 const void* buff, /* Pointer to the data to be written */ 03853 UINT btw, /* Number of bytes to write */ 03854 UINT* bw /* Pointer to number of bytes written */ 03855 ) 03856 { 03857 FRESULT res; 03858 FATFS *fs; 03859 DWORD clst, sect; 03860 UINT wcnt, cc, csect; 03861 const BYTE *wbuff = (const BYTE*)buff; 03862 bool need_sync = false; 03863 03864 *bw = 0; /* Clear write byte counter */ 03865 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 03866 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ 03867 if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 03868 03869 /* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */ 03870 if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { 03871 btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); 03872 } 03873 03874 for ( ; btw; /* Repeat until all data written */ 03875 btw -= wcnt, *bw += wcnt, wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize) { 03876 if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ 03877 csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ 03878 if (csect == 0) { /* On the cluster boundary? */ 03879 if (fp->fptr == 0) { /* On the top of the file? */ 03880 clst = fp->obj.sclust; /* Follow from the origin */ 03881 if (clst == 0) { /* If no cluster is allocated, */ 03882 clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ 03883 } 03884 } else { /* On the middle or end of the file */ 03885 #if FF_USE_FASTSEEK 03886 if (fp->cltbl) { 03887 clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ 03888 } else 03889 #endif 03890 { 03891 clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ 03892 } 03893 } 03894 if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ 03895 if (clst == 1) ABORT(fs, FR_INT_ERR); 03896 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 03897 fp->clust = clst; /* Update current cluster */ 03898 if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ 03899 #if FLUSH_ON_NEW_CLUSTER 03900 // We do not need to flush for the first cluster 03901 if (fp->fptr != 0) { 03902 need_sync = true; 03903 } 03904 #endif 03905 } 03906 #if FF_FS_TINY 03907 if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ 03908 #else 03909 if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ 03910 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 03911 fp->flag &= (BYTE)~FA_DIRTY; 03912 } 03913 #endif 03914 sect = clst2sect(fs, fp->clust); /* Get current sector */ 03915 if (sect == 0) ABORT(fs, FR_INT_ERR); 03916 sect += csect; 03917 cc = btw / SS(fs); /* When remaining bytes >= sector size, */ 03918 if (cc > 0) { /* Write maximum contiguous sectors directly */ 03919 if (csect + cc > fs->csize) { /* Clip at cluster boundary */ 03920 cc = fs->csize - csect; 03921 } 03922 if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); 03923 #if FF_FS_MINIMIZE <= 2 03924 #if FF_FS_TINY 03925 if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 03926 mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); 03927 fs->wflag = 0; 03928 } 03929 #else 03930 if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ 03931 mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); 03932 fp->flag &= (BYTE)~FA_DIRTY; 03933 } 03934 #endif 03935 #endif 03936 wcnt = SS(fs) * cc; /* Number of bytes transferred */ 03937 #if FLUSH_ON_NEW_SECTOR 03938 need_sync = true; 03939 #endif 03940 continue; 03941 } 03942 #if FF_FS_TINY 03943 if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ 03944 if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); 03945 fs->winsect = sect; 03946 } 03947 #else 03948 if (fp->sect != sect && /* Fill sector cache with file data */ 03949 fp->fptr < fp->obj.objsize && 03950 disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { 03951 ABORT(fs, FR_DISK_ERR); 03952 } 03953 #endif 03954 fp->sect = sect; 03955 } 03956 wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ 03957 if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ 03958 #if FF_FS_TINY 03959 if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ 03960 mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ 03961 fs->wflag = 1; 03962 #else 03963 mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ 03964 fp->flag |= FA_DIRTY; 03965 #endif 03966 } 03967 03968 fp->flag |= FA_MODIFIED; /* Set file change flag */ 03969 03970 if (need_sync) { 03971 f_sync (fp); 03972 } 03973 03974 LEAVE_FF(fs, FR_OK); 03975 } 03976 03977 03978 03979 03980 /*-----------------------------------------------------------------------*/ 03981 /* Synchronize the File */ 03982 /*-----------------------------------------------------------------------*/ 03983 03984 FRESULT f_sync ( 03985 FIL* fp /* Pointer to the file object */ 03986 ) 03987 { 03988 FRESULT res; 03989 FATFS *fs; 03990 DWORD tm; 03991 BYTE *dir; 03992 03993 03994 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 03995 if (res == FR_OK) { 03996 if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ 03997 #if !FF_FS_TINY 03998 if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ 03999 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); 04000 fp->flag &= (BYTE)~FA_DIRTY; 04001 } 04002 #endif 04003 /* Update the directory entry */ 04004 tm = GET_FATTIME(); /* Modified time */ 04005 #if FF_FS_EXFAT 04006 if (fs->fs_type == FS_EXFAT) { 04007 res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ 04008 if (res == FR_OK) { 04009 res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ 04010 } 04011 if (res == FR_OK) { 04012 FATFS_DIR dj; 04013 DEF_NAMBUF 04014 04015 INIT_NAMBUF(fs); 04016 res = load_obj_xdir(&dj, &fp->obj); /* Load directory entry block */ 04017 if (res == FR_OK) { 04018 fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ 04019 fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation information */ 04020 st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); 04021 st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); 04022 st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); 04023 st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ 04024 fs->dirbuf[XDIR_ModTime10] = 0; 04025 st_dword(fs->dirbuf + XDIR_AccTime, 0); 04026 res = store_xdir(&dj); /* Restore it to the directory */ 04027 if (res == FR_OK) { 04028 res = sync_fs(fs); 04029 fp->flag &= (BYTE)~FA_MODIFIED; 04030 } 04031 } 04032 FREE_NAMBUF(); 04033 } 04034 } else 04035 #endif 04036 { 04037 res = move_window(fs, fp->dir_sect); 04038 if (res == FR_OK) { 04039 dir = fp->dir_ptr; 04040 dir[DIR_Attr] |= AM_ARC; /* Set archive attribute to indicate that the file has been changed */ 04041 st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation information */ 04042 st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ 04043 st_dword(dir + DIR_ModTime, tm); /* Update modified time */ 04044 st_word(dir + DIR_LstAccDate, 0); 04045 fs->wflag = 1; 04046 res = sync_fs(fs); /* Restore it to the directory */ 04047 fp->flag &= (BYTE)~FA_MODIFIED; 04048 } 04049 } 04050 } 04051 } 04052 04053 LEAVE_FF(fs, res); 04054 } 04055 04056 #endif /* !FF_FS_READONLY */ 04057 04058 04059 04060 04061 /*-----------------------------------------------------------------------*/ 04062 /* Close File */ 04063 /*-----------------------------------------------------------------------*/ 04064 04065 FRESULT f_close ( 04066 FIL* fp /* Pointer to the file object to be closed */ 04067 ) 04068 { 04069 FRESULT res; 04070 FATFS *fs; 04071 04072 #if !FF_FS_READONLY 04073 res = f_sync(fp); /* Flush cached data */ 04074 if (res == FR_OK) 04075 #endif 04076 { 04077 res = validate(&fp->obj, &fs); /* Lock volume */ 04078 if (res == FR_OK) { 04079 #if FF_FS_LOCK != 0 04080 res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ 04081 if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ 04082 #else 04083 fp->obj.fs = 0; /* Invalidate file object */ 04084 #endif 04085 #if FF_FS_REENTRANT 04086 unlock_fs(fs, FR_OK); /* Unlock volume */ 04087 #endif 04088 #if !FF_FS_TINY && FF_FS_HEAPBUF 04089 ff_memfree(fp->buf); /* Deallocate buffer */ 04090 #endif 04091 } 04092 } 04093 return res; 04094 } 04095 04096 04097 04098 04099 #if FF_FS_RPATH >= 1 04100 /*-----------------------------------------------------------------------*/ 04101 /* Change Current Directory or Current Drive, Get Current Directory */ 04102 /*-----------------------------------------------------------------------*/ 04103 04104 #if FF_VOLUMES >= 2 04105 FRESULT f_chdrive ( 04106 const TCHAR* path /* Drive number */ 04107 ) 04108 { 04109 int vol; 04110 04111 04112 /* Get logical drive number */ 04113 vol = get_ldnumber(&path); 04114 if (vol < 0) return FR_INVALID_DRIVE; 04115 04116 CurrVol = (BYTE)vol; /* Set it as current volume */ 04117 04118 return FR_OK; 04119 } 04120 #endif 04121 04122 04123 FRESULT f_chdir ( 04124 const TCHAR* path /* Pointer to the directory path */ 04125 ) 04126 { 04127 FRESULT res; 04128 FATFS_DIR dj; 04129 FATFS *fs; 04130 DEF_NAMBUF 04131 04132 /* Get logical drive */ 04133 res = find_volume(&path, &fs, 0); 04134 if (res == FR_OK) { 04135 dj.obj.fs = fs; 04136 INIT_NAMBUF(fs); 04137 res = follow_path(&dj, path); /* Follow the path */ 04138 if (res == FR_OK) { /* Follow completed */ 04139 if (dj.fn[NSFLAG] & NS_NONAME) { 04140 fs->cdir = dj.obj.sclust; /* It is the start directory itself */ 04141 #if FF_FS_EXFAT 04142 if (fs->fs_type == FS_EXFAT) { 04143 fs->cdc_scl = dj.obj.c_scl; 04144 fs->cdc_size = dj.obj.c_size; 04145 fs->cdc_ofs = dj.obj.c_ofs; 04146 } 04147 #endif 04148 } else { 04149 if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ 04150 #if FF_FS_EXFAT 04151 if (fs->fs_type == FS_EXFAT) { 04152 fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ 04153 fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ 04154 fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; 04155 fs->cdc_ofs = dj.blk_ofs; 04156 } else 04157 #endif 04158 { 04159 fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ 04160 } 04161 } else { 04162 res = FR_NO_PATH; /* Reached but a file */ 04163 } 04164 } 04165 } 04166 FREE_NAMBUF(); 04167 if (res == FR_NO_FILE) res = FR_NO_PATH; 04168 } 04169 04170 LEAVE_FF(fs, res); 04171 } 04172 04173 04174 #if FF_FS_RPATH >= 2 04175 FRESULT f_getcwd ( 04176 TCHAR* buff, /* Pointer to the directory path */ 04177 UINT len /* Size of path */ 04178 ) 04179 { 04180 FRESULT res; 04181 FATFS_DIR dj; 04182 FATFS *fs; 04183 UINT i, n; 04184 DWORD ccl; 04185 TCHAR *tp; 04186 FILINFO fno; 04187 DEF_NAMBUF 04188 04189 04190 *buff = 0; 04191 /* Get logical drive */ 04192 res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ 04193 if (res == FR_OK) { 04194 dj.obj.fs = fs; 04195 INIT_NAMBUF(fs); 04196 i = len; /* Bottom of buffer (directory stack base) */ 04197 if (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ 04198 dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ 04199 while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ 04200 res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ 04201 if (res != FR_OK) break; 04202 res = move_window(fs, dj.sect); 04203 if (res != FR_OK) break; 04204 dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ 04205 res = dir_sdi(&dj, 0); 04206 if (res != FR_OK) break; 04207 do { /* Find the entry links to the child directory */ 04208 res = dir_read_file(&dj); 04209 if (res != FR_OK) break; 04210 if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ 04211 res = dir_next(&dj, 0); 04212 } while (res == FR_OK); 04213 if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ 04214 if (res != FR_OK) break; 04215 get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ 04216 for (n = 0; fno.fname[n]; n++) ; 04217 if (i < n + 3) { 04218 res = FR_NOT_ENOUGH_CORE; break; 04219 } 04220 while (n) buff[--i] = fno.fname[--n]; 04221 buff[--i] = '/'; 04222 } 04223 } 04224 tp = buff; 04225 if (res == FR_OK) { 04226 #if FF_VOLUMES >= 2 04227 *tp++ = '0' + CurrVol; /* Put drive number */ 04228 *tp++ = ':'; 04229 #endif 04230 if (i == len) { /* Root-directory */ 04231 *tp++ = '/'; 04232 } else { /* Sub-directroy */ 04233 do /* Add stacked path str */ 04234 *tp++ = buff[i++]; 04235 while (i < len); 04236 } 04237 } 04238 *tp = 0; 04239 FREE_NAMBUF(); 04240 } 04241 04242 LEAVE_FF(fs, res); 04243 } 04244 04245 #endif /* FF_FS_RPATH >= 2 */ 04246 #endif /* FF_FS_RPATH >= 1 */ 04247 04248 04249 04250 #if FF_FS_MINIMIZE <= 2 04251 /*-----------------------------------------------------------------------*/ 04252 /* Seek File Read/Write Pointer */ 04253 /*-----------------------------------------------------------------------*/ 04254 04255 FRESULT f_lseek ( 04256 FIL* fp, /* Pointer to the file object */ 04257 FSIZE_t ofs /* File pointer from top of file */ 04258 ) 04259 { 04260 FRESULT res; 04261 FATFS *fs; 04262 DWORD clst, bcs, nsect; 04263 FSIZE_t ifptr; 04264 #if FF_USE_FASTSEEK 04265 DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; 04266 #endif 04267 04268 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 04269 if (res == FR_OK) res = (FRESULT)fp->err; 04270 #if FF_FS_EXFAT && !FF_FS_READONLY 04271 if (res == FR_OK && fs->fs_type == FS_EXFAT) { 04272 res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ 04273 } 04274 #endif 04275 if (res != FR_OK) LEAVE_FF(fs, res); 04276 04277 #if FF_USE_FASTSEEK 04278 if (fp->cltbl) { /* Fast seek */ 04279 if (ofs == CREATE_LINKMAP) { /* Create CLMT */ 04280 tbl = fp->cltbl; 04281 tlen = *tbl++; ulen = 2; /* Given table size and required table size */ 04282 cl = fp->obj.sclust; /* Origin of the chain */ 04283 if (cl != 0) { 04284 do { 04285 /* Get a fragment */ 04286 tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ 04287 do { 04288 pcl = cl; ncl++; 04289 cl = get_fat(&fp->obj, cl); 04290 if (cl <= 1) ABORT(fs, FR_INT_ERR); 04291 if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 04292 } while (cl == pcl + 1); 04293 if (ulen <= tlen) { /* Store the length and top of the fragment */ 04294 *tbl++ = ncl; *tbl++ = tcl; 04295 } 04296 } while (cl < fs->n_fatent); /* Repeat until end of chain */ 04297 } 04298 *fp->cltbl = ulen; /* Number of items used */ 04299 if (ulen <= tlen) { 04300 *tbl = 0; /* Terminate table */ 04301 } else { 04302 res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ 04303 } 04304 } else { /* Fast seek */ 04305 if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ 04306 fp->fptr = ofs; /* Set file pointer */ 04307 if (ofs > 0) { 04308 fp->clust = clmt_clust(fp, ofs - 1); 04309 dsc = clst2sect(fs, fp->clust); 04310 if (dsc == 0) ABORT(fs, FR_INT_ERR); 04311 dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); 04312 if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ 04313 #if !FF_FS_TINY 04314 #if !FF_FS_READONLY 04315 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 04316 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 04317 fp->flag &= (BYTE)~FA_DIRTY; 04318 } 04319 #endif 04320 if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ 04321 #endif 04322 fp->sect = dsc; 04323 } 04324 } 04325 } 04326 } else 04327 #endif 04328 04329 /* Normal Seek */ 04330 { 04331 #if FF_FS_EXFAT 04332 if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4 GiB - 1 if at FATxx */ 04333 #endif 04334 if (ofs > fp->obj.objsize && (FF_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ 04335 ofs = fp->obj.objsize; 04336 } 04337 ifptr = fp->fptr; 04338 fp->fptr = nsect = 0; 04339 if (ofs > 0) { 04340 bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ 04341 if (ifptr > 0 && 04342 (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ 04343 fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ 04344 ofs -= fp->fptr; 04345 clst = fp->clust; 04346 } else { /* When seek to back cluster, */ 04347 clst = fp->obj.sclust; /* start from the first cluster */ 04348 #if !FF_FS_READONLY 04349 if (clst == 0) { /* If no cluster chain, create a new chain */ 04350 clst = create_chain(&fp->obj, 0); 04351 if (clst == 1) ABORT(fs, FR_INT_ERR); 04352 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 04353 fp->obj.sclust = clst; 04354 } 04355 #endif 04356 fp->clust = clst; 04357 } 04358 if (clst != 0) { 04359 while (ofs > bcs) { /* Cluster following loop */ 04360 ofs -= bcs; fp->fptr += bcs; 04361 #if !FF_FS_READONLY 04362 if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ 04363 if (FF_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ 04364 fp->obj.objsize = fp->fptr; 04365 fp->flag |= FA_MODIFIED; 04366 } 04367 clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ 04368 if (clst == 0) { /* Clip file size in case of disk full */ 04369 ofs = 0; break; 04370 } 04371 } else 04372 #endif 04373 { 04374 clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ 04375 } 04376 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 04377 if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); 04378 fp->clust = clst; 04379 } 04380 fp->fptr += ofs; 04381 if (ofs % SS(fs)) { 04382 nsect = clst2sect(fs, clst); /* Current sector */ 04383 if (nsect == 0) ABORT(fs, FR_INT_ERR); 04384 nsect += (DWORD)(ofs / SS(fs)); 04385 } 04386 } 04387 } 04388 if (!FF_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ 04389 fp->obj.objsize = fp->fptr; 04390 fp->flag |= FA_MODIFIED; 04391 } 04392 if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ 04393 #if !FF_FS_TINY 04394 #if !FF_FS_READONLY 04395 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 04396 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 04397 fp->flag &= (BYTE)~FA_DIRTY; 04398 } 04399 #endif 04400 if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ 04401 #endif 04402 fp->sect = nsect; 04403 } 04404 } 04405 04406 LEAVE_FF(fs, res); 04407 } 04408 04409 04410 04411 #if FF_FS_MINIMIZE <= 1 04412 /*-----------------------------------------------------------------------*/ 04413 /* Create a Directory Object */ 04414 /*-----------------------------------------------------------------------*/ 04415 04416 FRESULT f_opendir ( 04417 FATFS_DIR* dp, /* Pointer to directory object to create */ 04418 const TCHAR* path /* Pointer to the directory path */ 04419 ) 04420 { 04421 FRESULT res; 04422 FATFS *fs; 04423 DEF_NAMBUF 04424 04425 04426 if (!dp) return FR_INVALID_OBJECT; 04427 04428 /* Get logical drive */ 04429 res = find_volume(&path, &fs, 0); 04430 if (res == FR_OK) { 04431 dp->obj.fs = fs; 04432 INIT_NAMBUF(fs); 04433 res = follow_path(dp, path); /* Follow the path to the directory */ 04434 if (res == FR_OK) { /* Follow completed */ 04435 if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ 04436 if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ 04437 #if FF_FS_EXFAT 04438 if (fs->fs_type == FS_EXFAT) { 04439 dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ 04440 dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; 04441 dp->obj.c_ofs = dp->blk_ofs; 04442 init_alloc_info(fs, &dp->obj); /* Get object allocation info */ 04443 } else 04444 #endif 04445 { 04446 dp->obj.sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ 04447 } 04448 } else { /* This object is a file */ 04449 res = FR_NO_PATH; 04450 } 04451 } 04452 if (res == FR_OK) { 04453 dp->obj.id = fs->id; 04454 res = dir_sdi(dp, 0); /* Rewind directory */ 04455 #if FF_FS_LOCK != 0 04456 if (res == FR_OK) { 04457 if (dp->obj.sclust != 0) { 04458 dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ 04459 if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; 04460 } else { 04461 dp->obj.lockid = 0; /* Root directory need not to be locked */ 04462 } 04463 } 04464 #endif 04465 } 04466 } 04467 FREE_NAMBUF(); 04468 if (res == FR_NO_FILE) res = FR_NO_PATH; 04469 } 04470 if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ 04471 04472 LEAVE_FF(fs, res); 04473 } 04474 04475 04476 04477 04478 /*-----------------------------------------------------------------------*/ 04479 /* Close Directory */ 04480 /*-----------------------------------------------------------------------*/ 04481 04482 FRESULT f_closedir ( 04483 FATFS_DIR *dp /* Pointer to the directory object to be closed */ 04484 ) 04485 { 04486 FRESULT res; 04487 FATFS *fs; 04488 04489 04490 res = validate(&dp->obj, &fs); /* Check validity of the file object */ 04491 if (res == FR_OK) { 04492 #if FF_FS_LOCK != 0 04493 if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ 04494 if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ 04495 #else 04496 dp->obj.fs = 0; /* Invalidate directory object */ 04497 #endif 04498 #if FF_FS_REENTRANT 04499 unlock_fs(fs, FR_OK); /* Unlock volume */ 04500 #endif 04501 } 04502 return res; 04503 } 04504 04505 04506 04507 04508 /*-----------------------------------------------------------------------*/ 04509 /* Read Directory Entries in Sequence */ 04510 /*-----------------------------------------------------------------------*/ 04511 04512 FRESULT f_readdir ( 04513 FATFS_DIR* dp, /* Pointer to the open directory object */ 04514 FILINFO* fno /* Pointer to file information to return */ 04515 ) 04516 { 04517 FRESULT res; 04518 FATFS *fs; 04519 DEF_NAMBUF 04520 04521 04522 res = validate(&dp->obj, &fs); /* Check validity of the directory object */ 04523 if (res == FR_OK) { 04524 if (!fno) { 04525 res = dir_sdi(dp, 0); /* Rewind the directory object */ 04526 } else { 04527 INIT_NAMBUF(fs); 04528 res = dir_read_file(dp); /* Read an item */ 04529 if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ 04530 if (res == FR_OK) { /* A valid entry is found */ 04531 get_fileinfo(dp, fno); /* Get the object information */ 04532 res = dir_next(dp, 0); /* Increment index for next */ 04533 if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ 04534 } 04535 FREE_NAMBUF(); 04536 } 04537 } 04538 LEAVE_FF(fs, res); 04539 } 04540 04541 04542 04543 #if FF_USE_FIND 04544 /*-----------------------------------------------------------------------*/ 04545 /* Find Next File */ 04546 /*-----------------------------------------------------------------------*/ 04547 04548 FRESULT f_findnext ( 04549 FATFS_DIR* dp, /* Pointer to the open directory object */ 04550 FILINFO* fno /* Pointer to the file information structure */ 04551 ) 04552 { 04553 FRESULT res; 04554 04555 04556 for (;;) { 04557 res = f_readdir(dp, fno); /* Get a directory item */ 04558 if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ 04559 if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ 04560 #if FF_USE_LFN && FF_USE_FIND == 2 04561 if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ 04562 #endif 04563 } 04564 return res; 04565 } 04566 04567 04568 04569 /*-----------------------------------------------------------------------*/ 04570 /* Find First File */ 04571 /*-----------------------------------------------------------------------*/ 04572 04573 FRESULT f_findfirst ( 04574 FATFS_DIR* dp, /* Pointer to the blank directory object */ 04575 FILINFO* fno, /* Pointer to the file information structure */ 04576 const TCHAR* path, /* Pointer to the directory to open */ 04577 const TCHAR* pattern /* Pointer to the matching pattern */ 04578 ) 04579 { 04580 FRESULT res; 04581 04582 04583 dp->pat = pattern; /* Save pointer to pattern string */ 04584 res = f_opendir(dp, path); /* Open the target directory */ 04585 if (res == FR_OK) { 04586 res = f_findnext(dp, fno); /* Find the first item */ 04587 } 04588 return res; 04589 } 04590 04591 #endif /* FF_USE_FIND */ 04592 04593 04594 04595 #if FF_FS_MINIMIZE == 0 04596 /*-----------------------------------------------------------------------*/ 04597 /* Get File Status */ 04598 /*-----------------------------------------------------------------------*/ 04599 04600 FRESULT f_stat ( 04601 const TCHAR* path, /* Pointer to the file path */ 04602 FILINFO* fno /* Pointer to file information to return */ 04603 ) 04604 { 04605 FRESULT res; 04606 FATFS_DIR dj; 04607 DEF_NAMBUF 04608 04609 04610 /* Get logical drive */ 04611 res = find_volume(&path, &dj.obj.fs, 0); 04612 if (res == FR_OK) { 04613 INIT_NAMBUF(dj.obj.fs); 04614 res = follow_path(&dj, path); /* Follow the file path */ 04615 if (res == FR_OK) { /* Follow completed */ 04616 if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ 04617 res = FR_INVALID_NAME; 04618 } else { /* Found an object */ 04619 if (fno) get_fileinfo(&dj, fno); 04620 } 04621 } 04622 FREE_NAMBUF(); 04623 } 04624 04625 LEAVE_FF(dj.obj.fs, res); 04626 } 04627 04628 04629 04630 #if !FF_FS_READONLY 04631 /*-----------------------------------------------------------------------*/ 04632 /* Get Number of Free Clusters */ 04633 /*-----------------------------------------------------------------------*/ 04634 04635 FRESULT f_getfree ( 04636 const TCHAR* path, /* Logical drive number */ 04637 DWORD* nclst, /* Pointer to a variable to return number of free clusters */ 04638 FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ 04639 ) 04640 { 04641 FRESULT res; 04642 FATFS *fs; 04643 DWORD nfree, clst, sect, stat; 04644 UINT i; 04645 FFOBJID obj; 04646 04647 04648 /* Get logical drive */ 04649 res = find_volume(&path, &fs, 0); 04650 if (res == FR_OK) { 04651 *fatfs = fs; /* Return ptr to the fs object */ 04652 /* If free_clst is valid, return it without full FAT scan */ 04653 if (fs->free_clst <= fs->n_fatent - 2) { 04654 *nclst = fs->free_clst; 04655 } else { 04656 /* Scan FAT to obtain number of free clusters */ 04657 nfree = 0; 04658 if (fs->fs_type == FS_FAT12) { /* FAT12: Scan bit field FAT entries */ 04659 clst = 2; obj.fs = fs; 04660 do { 04661 stat = get_fat(&obj, clst); 04662 if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } 04663 if (stat == 1) { res = FR_INT_ERR; break; } 04664 if (stat == 0) nfree++; 04665 } while (++clst < fs->n_fatent); 04666 } else { 04667 #if FF_FS_EXFAT 04668 if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan allocation bitmap */ 04669 BYTE bm; 04670 UINT b; 04671 04672 clst = fs->n_fatent - 2; /* Number of clusters */ 04673 sect = fs->database; /* Assuming bitmap starts at cluster 2 */ 04674 i = 0; /* Offset in the sector */ 04675 do { /* Counts numbuer of bits with zero in the bitmap */ 04676 if (i == 0) { 04677 res = move_window(fs, sect++); 04678 if (res != FR_OK) break; 04679 } 04680 for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { 04681 if (!(bm & 1)) nfree++; 04682 bm >>= 1; 04683 } 04684 i = (i + 1) % SS(fs); 04685 } while (clst); 04686 } else 04687 #endif 04688 { /* FAT16/32: Scan WORD/DWORD FAT entries */ 04689 clst = fs->n_fatent; /* Number of entries */ 04690 sect = fs->fatbase; /* Top of the FAT */ 04691 i = 0; /* Offset in the sector */ 04692 do { /* Counts numbuer of entries with zero in the FAT */ 04693 if (i == 0) { 04694 res = move_window(fs, sect++); 04695 if (res != FR_OK) break; 04696 } 04697 if (fs->fs_type == FS_FAT16) { 04698 if (ld_word(fs->win + i) == 0) nfree++; 04699 i += 2; 04700 } else { 04701 if ((ld_dword(fs->win + i) & 0x0FFFFFFF) == 0) nfree++; 04702 i += 4; 04703 } 04704 i %= SS(fs); 04705 } while (--clst); 04706 } 04707 } 04708 *nclst = nfree; /* Return the free clusters */ 04709 fs->free_clst = nfree; /* Now free_clst is valid */ 04710 fs->fsi_flag |= 1; /* FAT32: FSInfo is to be updated */ 04711 } 04712 } 04713 04714 LEAVE_FF(fs, res); 04715 } 04716 04717 04718 04719 04720 /*-----------------------------------------------------------------------*/ 04721 /* Truncate File */ 04722 /*-----------------------------------------------------------------------*/ 04723 04724 FRESULT f_truncate ( 04725 FIL* fp /* Pointer to the file object */ 04726 ) 04727 { 04728 FRESULT res; 04729 FATFS *fs; 04730 DWORD ncl; 04731 04732 04733 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 04734 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); 04735 if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 04736 04737 if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ 04738 if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ 04739 res = remove_chain(&fp->obj, fp->obj.sclust, 0); 04740 fp->obj.sclust = 0; 04741 } else { /* When truncate a part of the file, remove remaining clusters */ 04742 ncl = get_fat(&fp->obj, fp->clust); 04743 res = FR_OK; 04744 if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; 04745 if (ncl == 1) res = FR_INT_ERR; 04746 if (res == FR_OK && ncl < fs->n_fatent) { 04747 res = remove_chain(&fp->obj, ncl, fp->clust); 04748 } 04749 } 04750 fp->obj.objsize = fp->fptr; /* Set file size to current read/write point */ 04751 fp->flag |= FA_MODIFIED; 04752 #if !FF_FS_TINY 04753 if (res == FR_OK && (fp->flag & FA_DIRTY)) { 04754 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { 04755 res = FR_DISK_ERR; 04756 } else { 04757 fp->flag &= (BYTE)~FA_DIRTY; 04758 } 04759 } 04760 #endif 04761 if (res != FR_OK) ABORT(fs, res); 04762 } 04763 04764 LEAVE_FF(fs, res); 04765 } 04766 04767 04768 04769 04770 /*-----------------------------------------------------------------------*/ 04771 /* Delete a File/Directory */ 04772 /*-----------------------------------------------------------------------*/ 04773 04774 FRESULT f_unlink ( 04775 const TCHAR* path /* Pointer to the file or directory path */ 04776 ) 04777 { 04778 FRESULT res; 04779 FATFS_DIR dj, sdj; 04780 DWORD dclst = 0; 04781 FATFS *fs; 04782 #if FF_FS_EXFAT 04783 FFOBJID obj; 04784 #endif 04785 DEF_NAMBUF 04786 04787 04788 /* Get logical drive */ 04789 res = find_volume(&path, &fs, FA_WRITE); 04790 if (res == FR_OK) { 04791 dj.obj.fs = fs; 04792 INIT_NAMBUF(fs); 04793 res = follow_path(&dj, path); /* Follow the file path */ 04794 if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { 04795 res = FR_INVALID_NAME; /* Cannot remove dot entry */ 04796 } 04797 #if FF_FS_LOCK != 0 04798 if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ 04799 #endif 04800 if (res == FR_OK) { /* The object is accessible */ 04801 if (dj.fn[NSFLAG] & NS_NONAME) { 04802 res = FR_INVALID_NAME; /* Cannot remove the origin directory */ 04803 } else { 04804 if (dj.obj.attr & AM_RDO) { 04805 res = FR_DENIED; /* Cannot remove R/O object */ 04806 } 04807 } 04808 if (res == FR_OK) { 04809 #if FF_FS_EXFAT 04810 obj.fs = fs; 04811 if (fs->fs_type == FS_EXFAT) { 04812 init_alloc_info(fs, &obj); 04813 dclst = obj.sclust; 04814 } else 04815 #endif 04816 { 04817 dclst = ld_clust(fs, dj.dir); 04818 } 04819 if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ 04820 #if FF_FS_RPATH != 0 04821 if (dclst == fs->cdir) { /* Is it the current directory? */ 04822 res = FR_DENIED; 04823 } else 04824 #endif 04825 { 04826 sdj.obj.fs = fs; /* Open the sub-directory */ 04827 sdj.obj.sclust = dclst; 04828 #if FF_FS_EXFAT 04829 if (fs->fs_type == FS_EXFAT) { 04830 sdj.obj.objsize = obj.objsize; 04831 sdj.obj.stat = obj.stat; 04832 } 04833 #endif 04834 res = dir_sdi(&sdj, 0); 04835 if (res == FR_OK) { 04836 res = dir_read_file(&sdj); /* Test if the directory is empty */ 04837 if (res == FR_OK) res = FR_DENIED; /* Not empty? */ 04838 if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ 04839 } 04840 } 04841 } 04842 } 04843 if (res == FR_OK) { 04844 res = dir_remove(&dj); /* Remove the directory entry */ 04845 if (res == FR_OK && dclst != 0) { /* Remove the cluster chain if exist */ 04846 #if FF_FS_EXFAT 04847 res = remove_chain(&obj, dclst, 0); 04848 #else 04849 res = remove_chain(&dj.obj, dclst, 0); 04850 #endif 04851 } 04852 if (res == FR_OK) res = sync_fs(fs); 04853 } 04854 } 04855 FREE_NAMBUF(); 04856 } 04857 04858 LEAVE_FF(fs, res); 04859 } 04860 04861 04862 04863 04864 /*-----------------------------------------------------------------------*/ 04865 /* Create a Directory */ 04866 /*-----------------------------------------------------------------------*/ 04867 04868 FRESULT f_mkdir ( 04869 const TCHAR* path /* Pointer to the directory path */ 04870 ) 04871 { 04872 FRESULT res; 04873 FATFS_DIR dj; 04874 FATFS *fs; 04875 BYTE *dir; 04876 DWORD dcl, pcl, tm; 04877 DEF_NAMBUF 04878 04879 04880 /* Get logical drive */ 04881 res = find_volume(&path, &fs, FA_WRITE); 04882 if (res == FR_OK) { 04883 dj.obj.fs = fs; 04884 INIT_NAMBUF(fs); 04885 res = follow_path(&dj, path); /* Follow the file path */ 04886 if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ 04887 if (FF_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { 04888 res = FR_INVALID_NAME; 04889 } 04890 if (res == FR_NO_FILE) { /* Can create a new directory */ 04891 dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ 04892 dj.obj.objsize = (DWORD)fs->csize * SS(fs); 04893 res = FR_OK; 04894 if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ 04895 if (dcl == 1) res = FR_INT_ERR; 04896 if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; 04897 if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ 04898 tm = GET_FATTIME(); 04899 if (res == FR_OK) { /* Initialize the new directory table */ 04900 res = dir_clear(fs, dcl); /* Clean up the new table */ 04901 if (res == FR_OK && (!FF_FS_EXFAT || fs->fs_type != FS_EXFAT)) { /* Create dot entries (FAT only) */ 04902 dir = fs->win; 04903 mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ 04904 dir[DIR_Name] = '.'; 04905 dir[DIR_Attr] = AM_DIR; 04906 st_dword(dir + DIR_ModTime, tm); 04907 st_clust(fs, dir, dcl); 04908 mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ 04909 dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; 04910 st_clust(fs, dir + SZDIRE, pcl); 04911 fs->wflag = 1; 04912 } 04913 } 04914 if (res == FR_OK) { 04915 res = dir_register(&dj); /* Register the object to the directoy */ 04916 } 04917 if (res == FR_OK) { 04918 #if FF_FS_EXFAT 04919 if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ 04920 st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ 04921 st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ 04922 st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ 04923 st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); 04924 fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag */ 04925 fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ 04926 res = store_xdir(&dj); 04927 } else 04928 #endif 04929 { 04930 dir = dj.dir; 04931 st_dword(dir + DIR_ModTime, tm); /* Created time */ 04932 st_clust(fs, dir, dcl); /* Table start cluster */ 04933 dir[DIR_Attr] = AM_DIR; /* Attribute */ 04934 fs->wflag = 1; 04935 } 04936 if (res == FR_OK) { 04937 res = sync_fs(fs); 04938 } 04939 } else { 04940 remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ 04941 } 04942 } 04943 FREE_NAMBUF(); 04944 } 04945 04946 LEAVE_FF(fs, res); 04947 } 04948 04949 04950 04951 04952 /*-----------------------------------------------------------------------*/ 04953 /* Rename a File/Directory */ 04954 /*-----------------------------------------------------------------------*/ 04955 04956 FRESULT f_rename ( 04957 const TCHAR* path_old, /* Pointer to the object name to be renamed */ 04958 const TCHAR* path_new /* Pointer to the new name */ 04959 ) 04960 { 04961 FRESULT res; 04962 FATFS_DIR djo, djn; 04963 FATFS *fs; 04964 BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; 04965 DWORD dw; 04966 DEF_NAMBUF 04967 04968 04969 get_ldnumber(&path_new); /* Snip the drive number of new name off */ 04970 res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ 04971 if (res == FR_OK) { 04972 djo.obj.fs = fs; 04973 INIT_NAMBUF(fs); 04974 res = follow_path(&djo, path_old); /* Check old object */ 04975 if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ 04976 #if FF_FS_LOCK != 0 04977 if (res == FR_OK) { 04978 res = chk_lock(&djo, 2); 04979 } 04980 #endif 04981 if (res == FR_OK) { /* Object to be renamed is found */ 04982 #if FF_FS_EXFAT 04983 if (fs->fs_type == FS_EXFAT) { /* At exFAT volume */ 04984 BYTE nf, nn; 04985 WORD nh; 04986 04987 mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ 04988 mem_cpy(&djn, &djo, sizeof djo); 04989 res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ 04990 if (res == FR_OK) { /* Is new name already in use by any other object? */ 04991 res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; 04992 } 04993 if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ 04994 res = dir_register(&djn); /* Register the new entry */ 04995 if (res == FR_OK) { 04996 nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; 04997 nh = ld_word(fs->dirbuf + XDIR_NameHash); 04998 mem_cpy(fs->dirbuf, buf, SZDIRE * 2); /* Restore 85+C0 entry */ 04999 fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; 05000 st_word(fs->dirbuf + XDIR_NameHash, nh); 05001 if (!(fs->dirbuf[XDIR_Attr] & AM_DIR)) fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ 05002 /* Start of critical section where an interruption can cause a cross-link */ 05003 res = store_xdir(&djn); 05004 } 05005 } 05006 } else 05007 #endif 05008 { /* At FAT/FAT32 volume */ 05009 mem_cpy(buf, djo.dir, SZDIRE); /* Save directory entry of the object */ 05010 mem_cpy(&djn, &djo, sizeof (FATFS_DIR)); /* Duplicate the directory object */ 05011 res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ 05012 if (res == FR_OK) { /* Is new name already in use by any other object? */ 05013 res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; 05014 } 05015 if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ 05016 res = dir_register(&djn); /* Register the new entry */ 05017 if (res == FR_OK) { 05018 dir = djn.dir; /* Copy directory entry of the object except name */ 05019 mem_cpy(dir + 13, buf + 13, SZDIRE - 13); 05020 dir[DIR_Attr] = buf[DIR_Attr]; 05021 if (!(dir[DIR_Attr] & AM_DIR)) dir[DIR_Attr] |= AM_ARC; /* Set archive attribute if it is a file */ 05022 fs->wflag = 1; 05023 if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ 05024 dw = clst2sect(fs, ld_clust(fs, dir)); 05025 if (dw == 0) { 05026 res = FR_INT_ERR; 05027 } else { 05028 /* Start of critical section where an interruption can cause a cross-link */ 05029 res = move_window(fs, dw); 05030 dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ 05031 if (res == FR_OK && dir[1] == '.') { 05032 st_clust(fs, dir, djn.obj.sclust); 05033 fs->wflag = 1; 05034 } 05035 } 05036 } 05037 } 05038 } 05039 } 05040 if (res == FR_OK) { 05041 res = dir_remove(&djo); /* Remove old entry */ 05042 if (res == FR_OK) { 05043 res = sync_fs(fs); 05044 } 05045 } 05046 /* End of the critical section */ 05047 } 05048 FREE_NAMBUF(); 05049 } 05050 05051 LEAVE_FF(fs, res); 05052 } 05053 05054 #endif /* !FF_FS_READONLY */ 05055 #endif /* FF_FS_MINIMIZE == 0 */ 05056 #endif /* FF_FS_MINIMIZE <= 1 */ 05057 #endif /* FF_FS_MINIMIZE <= 2 */ 05058 05059 05060 05061 #if FF_USE_CHMOD && !FF_FS_READONLY 05062 /*-----------------------------------------------------------------------*/ 05063 /* Change Attribute */ 05064 /*-----------------------------------------------------------------------*/ 05065 05066 FRESULT f_chmod ( 05067 const TCHAR* path, /* Pointer to the file path */ 05068 BYTE attr, /* Attribute bits */ 05069 BYTE mask /* Attribute mask to change */ 05070 ) 05071 { 05072 FRESULT res; 05073 FATFS_DIR dj; 05074 FATFS *fs; 05075 DEF_NAMBUF 05076 05077 05078 res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ 05079 if (res == FR_OK) { 05080 dj.obj.fs = fs; 05081 INIT_NAMBUF(fs); 05082 res = follow_path(&dj, path); /* Follow the file path */ 05083 if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ 05084 if (res == FR_OK) { 05085 mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ 05086 #if FF_FS_EXFAT 05087 if (fs->fs_type == FS_EXFAT) { 05088 fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ 05089 res = store_xdir(&dj); 05090 } else 05091 #endif 05092 { 05093 dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ 05094 fs->wflag = 1; 05095 } 05096 if (res == FR_OK) { 05097 res = sync_fs(fs); 05098 } 05099 } 05100 FREE_NAMBUF(); 05101 } 05102 05103 LEAVE_FF(fs, res); 05104 } 05105 05106 05107 05108 05109 /*-----------------------------------------------------------------------*/ 05110 /* Change Timestamp */ 05111 /*-----------------------------------------------------------------------*/ 05112 05113 FRESULT f_utime ( 05114 const TCHAR* path, /* Pointer to the file/directory name */ 05115 const FILINFO* fno /* Pointer to the timestamp to be set */ 05116 ) 05117 { 05118 FRESULT res; 05119 FATFS_DIR dj; 05120 FATFS *fs; 05121 DEF_NAMBUF 05122 05123 05124 res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ 05125 if (res == FR_OK) { 05126 dj.obj.fs = fs; 05127 INIT_NAMBUF(fs); 05128 res = follow_path(&dj, path); /* Follow the file path */ 05129 if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ 05130 if (res == FR_OK) { 05131 #if FF_FS_EXFAT 05132 if (fs->fs_type == FS_EXFAT) { 05133 st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); 05134 res = store_xdir(&dj); 05135 } else 05136 #endif 05137 { 05138 st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); 05139 fs->wflag = 1; 05140 } 05141 if (res == FR_OK) { 05142 res = sync_fs(fs); 05143 } 05144 } 05145 FREE_NAMBUF(); 05146 } 05147 05148 LEAVE_FF(fs, res); 05149 } 05150 05151 #endif /* FF_USE_CHMOD && !FF_FS_READONLY */ 05152 05153 05154 05155 #if FF_USE_LABEL 05156 /*-----------------------------------------------------------------------*/ 05157 /* Get Volume Label */ 05158 /*-----------------------------------------------------------------------*/ 05159 05160 FRESULT f_getlabel ( 05161 const TCHAR* path, /* Logical drive number */ 05162 TCHAR* label, /* Buffer to store the volume label */ 05163 DWORD* vsn /* Variable to store the volume serial number */ 05164 ) 05165 { 05166 FRESULT res; 05167 FATFS_DIR dj; 05168 FATFS *fs; 05169 UINT si, di; 05170 WCHAR wc; 05171 05172 /* Get logical drive */ 05173 res = find_volume(&path, &fs, 0); 05174 05175 /* Get volume label */ 05176 if (res == FR_OK && label) { 05177 dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ 05178 res = dir_sdi(&dj, 0); 05179 if (res == FR_OK) { 05180 res = dir_read_label(&dj); /* Find a volume label entry */ 05181 if (res == FR_OK) { 05182 #if FF_FS_EXFAT 05183 if (fs->fs_type == FS_EXFAT) { 05184 WCHAR hs; 05185 05186 for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ 05187 wc = ld_word(dj.dir + XDIR_Label + si * 2); 05188 if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ 05189 hs = wc; continue; 05190 } 05191 wc = put_utf((DWORD)hs << 16 | wc, &label[di], 4); 05192 if (wc == 0) { di = 0; break; } 05193 di += wc; 05194 hs = 0; 05195 } 05196 if (hs != 0) di = 0; /* Broken surrogate pair? */ 05197 label[di] = 0; 05198 } else 05199 #endif 05200 { 05201 si = di = 0; /* Extract volume label from AM_VOL entry */ 05202 while (si < 11) { 05203 wc = dj.dir[si++]; 05204 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ 05205 if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ 05206 wc = ff_oem2uni(wc, CODEPAGE); 05207 if (wc != 0) wc = put_utf(wc, &label[di], 4); 05208 if (wc == 0) { di = 0; break; } 05209 di += wc; 05210 #else /* ANSI/OEM output */ 05211 label[di++] = (TCHAR)wc; 05212 #endif 05213 } 05214 do { /* Truncate trailing spaces */ 05215 label[di] = 0; 05216 if (di == 0) break; 05217 } while (label[--di] == ' '); 05218 } 05219 } 05220 } 05221 if (res == FR_NO_FILE) { /* No label entry and return nul string */ 05222 label[0] = 0; 05223 res = FR_OK; 05224 } 05225 } 05226 05227 /* Get volume serial number */ 05228 if (res == FR_OK && vsn) { 05229 res = move_window(fs, fs->volbase); 05230 if (res == FR_OK) { 05231 switch (fs->fs_type) { 05232 case FS_EXFAT: 05233 di = BPB_VolIDEx; break; 05234 05235 case FS_FAT32: 05236 di = BS_VolID32; break; 05237 05238 default: 05239 di = BS_VolID; 05240 } 05241 *vsn = ld_dword(fs->win + di); 05242 } 05243 } 05244 05245 LEAVE_FF(fs, res); 05246 } 05247 05248 05249 05250 #if !FF_FS_READONLY 05251 /*-----------------------------------------------------------------------*/ 05252 /* Set Volume Label */ 05253 /*-----------------------------------------------------------------------*/ 05254 05255 FRESULT f_setlabel ( 05256 const TCHAR* label /* Volume label to set with heading logical drive number */ 05257 ) 05258 { 05259 FRESULT res; 05260 FATFS_DIR dj; 05261 FATFS *fs; 05262 BYTE dirvn[22]; 05263 UINT di; 05264 WCHAR wc; 05265 static const char badchr[] = "+.,;=[]\"*:<>\?|\x7F"; /* [0..] for FAT, [7..] for exFAT */ 05266 #if FF_USE_LFN 05267 DWORD dc; 05268 #endif 05269 05270 /* Get logical drive */ 05271 res = find_volume(&label, &fs, FA_WRITE); 05272 if (res != FR_OK) LEAVE_FF(fs, res); 05273 05274 #if FF_FS_EXFAT 05275 if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ 05276 mem_set(dirvn, 0, 22); 05277 di = 0; 05278 while (*label) { /* Create volume label in directory form */ 05279 dc = tchar2uni(&label); /* Get a Unicode character */ 05280 if (dc >= 0x10000) { 05281 if (dc == 0xFFFFFFFF || di >= 10) { /* Wrong surrogate or buffer overflow */ 05282 dc = 0; 05283 } else { 05284 st_word(dirvn + di * 2, (WCHAR)(dc >> 16)); di++; 05285 } 05286 } 05287 if (dc == 0 || chk_chr(badchr + 7, (int)dc) || di >= 11) { /* Check validity of the volume label */ 05288 LEAVE_FF(fs, FR_INVALID_NAME); 05289 } 05290 st_word(dirvn + di * 2, (WCHAR)dc); di++; 05291 } 05292 } else 05293 #endif 05294 { /* On the FAT/FAT32 volume */ 05295 mem_set(dirvn, ' ', 11); 05296 di = 0; 05297 while (*label) { /* Create volume label in directory form */ 05298 #if FF_USE_LFN 05299 dc = tchar2uni(&label); 05300 wc = (dc < 0x10000) ? ff_uni2oem(ff_wtoupper(dc), CODEPAGE) : 0; 05301 #else /* ANSI/OEM input */ 05302 wc = (BYTE)*label++; 05303 if (dbc_1st((BYTE)wc)) wc = dbc_2nd((BYTE)*label) ? wc << 8 | (BYTE)*label++ : 0; 05304 if (IsLower(wc)) wc -= 0x20; /* To upper ASCII characters */ 05305 #if FF_CODE_PAGE == 0 05306 if (ExCvt && wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ 05307 #elif FF_CODE_PAGE < 900 05308 if (wc >= 0x80) wc = ExCvt[wc - 0x80]; /* To upper extended characters (SBCS cfg) */ 05309 #endif 05310 #endif 05311 if (wc == 0 || chk_chr(badchr + 0, (int)wc) || di >= (UINT)((wc >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ 05312 LEAVE_FF(fs, FR_INVALID_NAME); 05313 } 05314 if (wc >= 0x100) dirvn[di++] = (BYTE)(wc >> 8); 05315 dirvn[di++] = (BYTE)wc; 05316 } 05317 if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ 05318 while (di && dirvn[di - 1] == ' ') di--; /* Snip trailing spaces */ 05319 } 05320 05321 /* Set volume label */ 05322 dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ 05323 res = dir_sdi(&dj, 0); 05324 if (res == FR_OK) { 05325 res = dir_read_label(&dj); /* Get volume label entry */ 05326 if (res == FR_OK) { 05327 if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { 05328 dj.dir[XDIR_NumLabel] = (BYTE)di; /* Change the volume label */ 05329 mem_cpy(dj.dir + XDIR_Label, dirvn, 22); 05330 } else { 05331 if (di != 0) { 05332 mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ 05333 } else { 05334 dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ 05335 } 05336 } 05337 fs->wflag = 1; 05338 res = sync_fs(fs); 05339 } else { /* No volume label entry or an error */ 05340 if (res == FR_NO_FILE) { 05341 res = FR_OK; 05342 if (di != 0) { /* Create a volume label entry */ 05343 res = dir_alloc(&dj, 1); /* Allocate an entry */ 05344 if (res == FR_OK) { 05345 mem_set(dj.dir, 0, SZDIRE); /* Clean the entry */ 05346 if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { 05347 dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ 05348 dj.dir[XDIR_NumLabel] = (BYTE)di; 05349 mem_cpy(dj.dir + XDIR_Label, dirvn, 22); 05350 } else { 05351 dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ 05352 mem_cpy(dj.dir, dirvn, 11); 05353 } 05354 fs->wflag = 1; 05355 res = sync_fs(fs); 05356 } 05357 } 05358 } 05359 } 05360 } 05361 05362 LEAVE_FF(fs, res); 05363 } 05364 05365 #endif /* !FF_FS_READONLY */ 05366 #endif /* FF_USE_LABEL */ 05367 05368 05369 05370 #if FF_USE_EXPAND && !FF_FS_READONLY 05371 /*-----------------------------------------------------------------------*/ 05372 /* Allocate a Contiguous Blocks to the File */ 05373 /*-----------------------------------------------------------------------*/ 05374 05375 FRESULT f_expand ( 05376 FIL* fp, /* Pointer to the file object */ 05377 FSIZE_t fsz, /* File size to be expanded to */ 05378 BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ 05379 ) 05380 { 05381 FRESULT res; 05382 FATFS *fs; 05383 DWORD n, clst, stcl, scl, ncl, tcl, lclst; 05384 05385 05386 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 05387 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); 05388 if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); 05389 #if FF_FS_EXFAT 05390 if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ 05391 #endif 05392 n = (DWORD)fs->csize * SS(fs); /* Cluster size */ 05393 tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ 05394 stcl = fs->last_clst; lclst = 0; 05395 if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; 05396 05397 #if FF_FS_EXFAT 05398 if (fs->fs_type == FS_EXFAT) { 05399 scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ 05400 if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ 05401 if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; 05402 if (res == FR_OK) { /* A contiguous free area is found */ 05403 if (opt) { /* Allocate it now */ 05404 res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ 05405 lclst = scl + tcl - 1; 05406 } else { /* Set it as suggested point for next allocation */ 05407 lclst = scl - 1; 05408 } 05409 } 05410 } else 05411 #endif 05412 { 05413 scl = clst = stcl; ncl = 0; 05414 for (;;) { /* Find a contiguous cluster block */ 05415 n = get_fat(&fp->obj, clst); 05416 if (++clst >= fs->n_fatent) clst = 2; 05417 if (n == 1) { res = FR_INT_ERR; break; } 05418 if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } 05419 if (n == 0) { /* Is it a free cluster? */ 05420 if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ 05421 } else { 05422 scl = clst; ncl = 0; /* Not a free cluster */ 05423 } 05424 if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ 05425 } 05426 if (res == FR_OK) { /* A contiguous free area is found */ 05427 if (opt) { /* Allocate it now */ 05428 for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ 05429 res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); 05430 if (res != FR_OK) break; 05431 lclst = clst; 05432 } 05433 } else { /* Set it as suggested point for next allocation */ 05434 lclst = scl - 1; 05435 } 05436 } 05437 } 05438 05439 if (res == FR_OK) { 05440 fs->last_clst = lclst; /* Set suggested start cluster to start next */ 05441 if (opt) { /* Is it allocated now? */ 05442 fp->obj.sclust = scl; /* Update object allocation information */ 05443 fp->obj.objsize = fsz; 05444 if (FF_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ 05445 fp->flag |= FA_MODIFIED; 05446 if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ 05447 fs->free_clst -= tcl; 05448 fs->fsi_flag |= 1; 05449 } 05450 } 05451 } 05452 05453 LEAVE_FF(fs, res); 05454 } 05455 05456 #endif /* FF_USE_EXPAND && !FF_FS_READONLY */ 05457 05458 05459 05460 #if FF_USE_FORWARD 05461 /*-----------------------------------------------------------------------*/ 05462 /* Forward Data to the Stream Directly */ 05463 /*-----------------------------------------------------------------------*/ 05464 05465 FRESULT f_forward ( 05466 FIL* fp, /* Pointer to the file object */ 05467 UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ 05468 UINT btf, /* Number of bytes to forward */ 05469 UINT* bf /* Pointer to number of bytes forwarded */ 05470 ) 05471 { 05472 FRESULT res; 05473 FATFS *fs; 05474 DWORD clst, sect; 05475 FSIZE_t remain; 05476 UINT rcnt, csect; 05477 BYTE *dbuf; 05478 05479 05480 *bf = 0; /* Clear transfer byte counter */ 05481 res = validate(&fp->obj, &fs); /* Check validity of the file object */ 05482 if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); 05483 if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ 05484 05485 remain = fp->obj.objsize - fp->fptr; 05486 if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ 05487 05488 for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ 05489 fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { 05490 csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ 05491 if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ 05492 if (csect == 0) { /* On the cluster boundary? */ 05493 clst = (fp->fptr == 0) ? /* On the top of the file? */ 05494 fp->obj.sclust : get_fat(&fp->obj, fp->clust); 05495 if (clst <= 1) ABORT(fs, FR_INT_ERR); 05496 if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); 05497 fp->clust = clst; /* Update current cluster */ 05498 } 05499 } 05500 sect = clst2sect(fs, fp->clust); /* Get current data sector */ 05501 if (sect == 0) ABORT(fs, FR_INT_ERR); 05502 sect += csect; 05503 #if FF_FS_TINY 05504 if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ 05505 dbuf = fs->win; 05506 #else 05507 if (fp->sect != sect) { /* Fill sector cache with file data */ 05508 #if !FF_FS_READONLY 05509 if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ 05510 if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 05511 fp->flag &= (BYTE)~FA_DIRTY; 05512 } 05513 #endif 05514 if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); 05515 } 05516 dbuf = fp->buf; 05517 #endif 05518 fp->sect = sect; 05519 rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ 05520 if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ 05521 rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ 05522 if (rcnt == 0) ABORT(fs, FR_INT_ERR); 05523 } 05524 05525 LEAVE_FF(fs, FR_OK); 05526 } 05527 #endif /* FF_USE_FORWARD */ 05528 05529 05530 05531 #if FF_USE_MKFS && !FF_FS_READONLY 05532 /*-----------------------------------------------------------------------*/ 05533 /* Create an FAT/exFAT volume */ 05534 /*-----------------------------------------------------------------------*/ 05535 05536 FRESULT f_mkfs ( 05537 const TCHAR* path, /* Logical drive number */ 05538 BYTE opt, /* Format option */ 05539 DWORD au, /* Size of allocation unit (cluster) [byte] */ 05540 void* work, /* Pointer to working buffer (null: use heap memory) */ 05541 UINT len /* Size of working buffer [byte] */ 05542 ) 05543 { 05544 const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ 05545 const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ 05546 static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ 05547 static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ 05548 BYTE fmt, sys, *buf, *pte, pdrv, part; 05549 WORD ss; /* Sector size */ 05550 DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; 05551 DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ 05552 DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ 05553 UINT i; 05554 int vol; 05555 DSTATUS stat; 05556 #if FF_USE_TRIM || FF_FS_EXFAT 05557 DWORD tbl[3]; 05558 #endif 05559 05560 05561 /* Check mounted drive and clear work area */ 05562 vol = get_ldnumber(&path); /* Get target logical drive */ 05563 if (vol < 0) return FR_INVALID_DRIVE; 05564 if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume if mounted */ 05565 pdrv = LD2PD(vol); /* Physical drive */ 05566 part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ 05567 05568 /* Check physical drive status */ 05569 stat = disk_initialize(pdrv); 05570 if (stat & STA_NOINIT) return FR_NOT_READY; 05571 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 05572 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 */ 05573 #if FF_MAX_SS != FF_MIN_SS /* Get sector size of the medium if variable sector size cfg. */ 05574 if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; 05575 if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; 05576 #else 05577 ss = FF_MAX_SS; 05578 #endif 05579 if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ 05580 au /= ss; /* Cluster size in unit of sector */ 05581 05582 /* Get working buffer */ 05583 #if FF_USE_LFN == 3 || FF_FS_HEAPBUF 05584 if (!work) { /* Use heap memory for working buffer */ 05585 for (szb_buf = MAX_MALLOC, buf = 0; szb_buf >= ss && !(buf = (BYTE *)ff_memalloc(szb_buf)); szb_buf /= 2) ; 05586 sz_buf = szb_buf / ss; /* Size of working buffer (sector) */ 05587 } else 05588 #endif 05589 { 05590 buf = (BYTE*)work; /* Working buffer */ 05591 sz_buf = len / ss; /* Size of working buffer (sector) */ 05592 szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ 05593 } 05594 if (!buf || sz_buf == 0) return FR_NOT_ENOUGH_CORE; 05595 05596 /* Determine where the volume to be located (b_vol, sz_vol) */ 05597 if (FF_MULTI_PARTITION && part != 0) { 05598 /* Get partition information from partition table in the MBR */ 05599 if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Load MBR */ 05600 if (ld_word(buf + BS_55AA) != 0xAA55) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if MBR is valid */ 05601 pte = buf + (MBR_Table + (part - 1) * SZ_PTE); 05602 if (pte[PTE_System] == 0) LEAVE_MKFS(FR_MKFS_ABORTED); /* No partition? */ 05603 b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ 05604 sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ 05605 } else { 05606 /* Create a single-partition in this function */ 05607 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05608 b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ 05609 if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); 05610 sz_vol -= b_vol; /* Volume size */ 05611 } 05612 if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ 05613 05614 /* Pre-determine the FAT type */ 05615 do { 05616 if (FF_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ 05617 if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ 05618 fmt = FS_EXFAT; break; 05619 } 05620 } 05621 if (au > 128) LEAVE_MKFS(FR_INVALID_PARAMETER); /* Too large au for FAT/FAT32 */ 05622 if (opt & FM_FAT32) { /* FAT32 possible? */ 05623 if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ 05624 fmt = FS_FAT32; break; 05625 } 05626 } 05627 if (!(opt & FM_FAT)) LEAVE_MKFS(FR_INVALID_PARAMETER); /* no-FAT? */ 05628 fmt = FS_FAT16; 05629 } while (0); 05630 05631 #if FF_FS_EXFAT 05632 if (fmt == FS_EXFAT) { /* Create an exFAT volume */ 05633 DWORD szb_bit, szb_case, sum, nb, cl; 05634 WCHAR ch, si; 05635 UINT j, st; 05636 BYTE b; 05637 05638 if (sz_vol < 0x1000) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ 05639 #if FF_USE_TRIM 05640 tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ 05641 disk_ioctl(pdrv, CTRL_TRIM, tbl); 05642 #endif 05643 /* Determine FAT location, data location and number of clusters */ 05644 if (au == 0) { /* au auto-selection */ 05645 au = 8; 05646 if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ 05647 if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ 05648 } 05649 b_fat = b_vol + 32; /* FAT start at offset 32 */ 05650 sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ 05651 b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ 05652 if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ 05653 n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ 05654 if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ 05655 if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ 05656 05657 szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ 05658 tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ 05659 05660 /* Create a compressed up-case table */ 05661 sect = b_data + au * tbl[0]; /* Table start sector */ 05662 sum = 0; /* Table checksum to be stored in the 82 entry */ 05663 st = si = i = j = szb_case = 0; 05664 do { 05665 switch (st) { 05666 case 0: 05667 ch = (WCHAR)ff_wtoupper(si); /* Get an up-case char */ 05668 if (ch != si) { 05669 si++; break; /* Store the up-case char if exist */ 05670 } 05671 for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ 05672 if (j >= 128) { 05673 ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ 05674 } 05675 st = 1; /* Do not compress short run */ 05676 /* go to next case */ 05677 case 1: 05678 ch = si++; /* Fill the short run */ 05679 if (--j == 0) st = 0; 05680 break; 05681 05682 default: 05683 ch = (WCHAR)j; si += j; /* Number of chars to skip */ 05684 st = 0; 05685 } 05686 sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ 05687 sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); 05688 i += 2; szb_case += 2; 05689 if (si == 0 || i == szb_buf) { /* Write buffered data when buffer full or end of process */ 05690 n = (i + ss - 1) / ss; 05691 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05692 sect += n; i = 0; 05693 } 05694 } while (si); 05695 tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ 05696 tbl[2] = 1; /* Number of root dir clusters */ 05697 05698 /* Initialize the allocation bitmap */ 05699 sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ 05700 nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ 05701 do { 05702 mem_set(buf, 0, szb_buf); 05703 for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; 05704 for (b = 1; nb != 0 && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; 05705 n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ 05706 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05707 sect += n; nsect -= n; 05708 } while (nsect); 05709 05710 /* Initialize the FAT */ 05711 sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ 05712 j = nb = cl = 0; 05713 do { 05714 mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ 05715 if (cl == 0) { /* Set entry 0 and 1 */ 05716 st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; 05717 st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; 05718 } 05719 do { /* Create chains of bitmap, up-case and root dir */ 05720 while (nb != 0 && i < szb_buf) { /* Create a chain */ 05721 st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); 05722 i += 4; cl++; nb--; 05723 } 05724 if (nb == 0 && j < 3) nb = tbl[j++]; /* Next chain */ 05725 } while (nb != 0 && i < szb_buf); 05726 n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ 05727 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05728 sect += n; nsect -= n; 05729 } while (nsect); 05730 05731 /* Initialize the root directory */ 05732 mem_set(buf, 0, szb_buf); 05733 buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ 05734 buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ 05735 st_dword(buf + SZDIRE * 1 + 20, 2); 05736 st_dword(buf + SZDIRE * 1 + 24, szb_bit); 05737 buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ 05738 st_dword(buf + SZDIRE * 2 + 4, sum); 05739 st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); 05740 st_dword(buf + SZDIRE * 2 + 24, szb_case); 05741 sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ 05742 do { /* Fill root directory sectors */ 05743 n = (nsect > sz_buf) ? sz_buf : nsect; 05744 if (disk_write(pdrv, buf, sect, n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05745 mem_set(buf, 0, ss); 05746 sect += n; nsect -= n; 05747 } while (nsect); 05748 05749 /* Create two set of the exFAT VBR blocks */ 05750 sect = b_vol; 05751 for (n = 0; n < 2; n++) { 05752 /* Main record (+0) */ 05753 mem_set(buf, 0, ss); 05754 mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ 05755 st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ 05756 st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ 05757 st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ 05758 st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ 05759 st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ 05760 st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ 05761 st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ 05762 st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ 05763 st_word(buf + BPB_FSVerEx, 0x100); /* Filesystem version (1.00) */ 05764 for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ 05765 for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ 05766 buf[BPB_NumFATsEx] = 1; /* Number of FATs */ 05767 buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ 05768 st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ 05769 st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ 05770 for (i = sum = 0; i < ss; i++) { /* VBR checksum */ 05771 if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); 05772 } 05773 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05774 /* Extended bootstrap record (+1..+8) */ 05775 mem_set(buf, 0, ss); 05776 st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ 05777 for (j = 1; j < 9; j++) { 05778 for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ 05779 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05780 } 05781 /* OEM/Reserved record (+9..+10) */ 05782 mem_set(buf, 0, ss); 05783 for ( ; j < 11; j++) { 05784 for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ 05785 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05786 } 05787 /* Sum record (+11) */ 05788 for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ 05789 if (disk_write(pdrv, buf, sect++, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05790 } 05791 05792 } else 05793 #endif /* FF_FS_EXFAT */ 05794 { /* Create an FAT/FAT32 volume */ 05795 do { 05796 pau = au; 05797 /* Pre-determine number of clusters and FAT sub-type */ 05798 if (fmt == FS_FAT32) { /* FAT32 volume */ 05799 if (pau == 0) { /* au auto-selection */ 05800 n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ 05801 for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ 05802 } 05803 n_clst = sz_vol / pau; /* Number of clusters */ 05804 sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ 05805 sz_rsv = 32; /* Number of reserved sectors */ 05806 sz_dir = 0; /* No static directory */ 05807 if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) LEAVE_MKFS(FR_MKFS_ABORTED); 05808 } else { /* FAT volume */ 05809 if (pau == 0) { /* au auto-selection */ 05810 n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ 05811 for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ 05812 } 05813 n_clst = sz_vol / pau; 05814 if (n_clst > MAX_FAT12) { 05815 n = n_clst * 2 + 4; /* FAT size [byte] */ 05816 } else { 05817 fmt = FS_FAT12; 05818 n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ 05819 } 05820 sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ 05821 sz_rsv = 1; /* Number of reserved sectors */ 05822 sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ 05823 } 05824 b_fat = b_vol + sz_rsv; /* FAT base */ 05825 b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ 05826 05827 /* Align data base to erase block boundary (for flash memory media) */ 05828 n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ 05829 if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ 05830 sz_rsv += n; b_fat += n; 05831 } else { /* FAT: Expand FAT size */ 05832 sz_fat += n / n_fats; 05833 } 05834 05835 /* Determine number of clusters and final check of validity of the FAT sub-type */ 05836 if (sz_vol < b_data + pau * 16 - b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume */ 05837 n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; 05838 if (fmt == FS_FAT32) { 05839 if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ 05840 if (au == 0 && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ 05841 LEAVE_MKFS(FR_MKFS_ABORTED); 05842 } 05843 } 05844 if (fmt == FS_FAT16) { 05845 if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ 05846 if (au == 0 && (pau * 2) <= 64) { 05847 au = pau * 2; continue; /* Adjust cluster size and retry */ 05848 } 05849 if ((opt & FM_FAT32)) { 05850 fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ 05851 } 05852 if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ 05853 LEAVE_MKFS(FR_MKFS_ABORTED); 05854 } 05855 if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ 05856 if (au == 0 && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ 05857 LEAVE_MKFS(FR_MKFS_ABORTED); 05858 } 05859 } 05860 if (fmt == FS_FAT12 && n_clst > MAX_FAT12) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters for FAT12 */ 05861 05862 /* Ok, it is the valid cluster configuration */ 05863 break; 05864 } while (1); 05865 05866 #if FF_USE_TRIM 05867 tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ 05868 disk_ioctl(pdrv, CTRL_TRIM, tbl); 05869 #endif 05870 /* Create FAT VBR */ 05871 mem_set(buf, 0, ss); 05872 mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ 05873 st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ 05874 buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ 05875 st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ 05876 buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ 05877 st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ 05878 if (sz_vol < 0x10000) { 05879 st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ 05880 } else { 05881 st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ 05882 } 05883 buf[BPB_Media] = 0xF8; /* Media descriptor byte */ 05884 st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ 05885 st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ 05886 st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ 05887 if (fmt == FS_FAT32) { 05888 st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ 05889 st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ 05890 st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ 05891 st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ 05892 st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ 05893 buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ 05894 buf[BS_BootSig32] = 0x29; /* Extended boot signature */ 05895 mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ 05896 } else { 05897 st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ 05898 st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ 05899 buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ 05900 buf[BS_BootSig] = 0x29; /* Extended boot signature */ 05901 mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ 05902 } 05903 st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ 05904 if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ 05905 05906 /* Create FSINFO record if needed */ 05907 if (fmt == FS_FAT32) { 05908 disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ 05909 mem_set(buf, 0, ss); 05910 st_dword(buf + FSI_LeadSig, 0x41615252); 05911 st_dword(buf + FSI_StrucSig, 0x61417272); 05912 st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ 05913 st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ 05914 st_word(buf + BS_55AA, 0xAA55); 05915 disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ 05916 disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ 05917 } 05918 05919 /* Initialize FAT area */ 05920 mem_set(buf, 0, (UINT)szb_buf); 05921 sect = b_fat; /* FAT start sector */ 05922 for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ 05923 if (fmt == FS_FAT32) { 05924 st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ 05925 st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ 05926 st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ 05927 } else { 05928 st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ 05929 } 05930 nsect = sz_fat; /* Number of FAT sectors */ 05931 do { /* Fill FAT sectors */ 05932 n = (nsect > sz_buf) ? sz_buf : nsect; 05933 if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05934 mem_set(buf, 0, ss); 05935 sect += n; nsect -= n; 05936 } while (nsect); 05937 } 05938 05939 /* Initialize root directory (fill with zero) */ 05940 nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ 05941 do { 05942 n = (nsect > sz_buf) ? sz_buf : nsect; 05943 if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05944 sect += n; nsect -= n; 05945 } while (nsect); 05946 } 05947 05948 /* Determine system ID in the partition table */ 05949 if (FF_FS_EXFAT && fmt == FS_EXFAT) { 05950 sys = 0x07; /* HPFS/NTFS/exFAT */ 05951 } else { 05952 if (fmt == FS_FAT32) { 05953 sys = 0x0C; /* FAT32X */ 05954 } else { 05955 if (sz_vol >= 0x10000) { 05956 sys = 0x06; /* FAT12/16 (large) */ 05957 } else { 05958 sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ 05959 } 05960 } 05961 } 05962 05963 /* Update partition information */ 05964 if (FF_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ 05965 /* Update system ID in the partition table */ 05966 if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ 05967 buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ 05968 if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ 05969 } else { /* Created as a new single partition */ 05970 if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ 05971 mem_set(buf, 0, ss); 05972 st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ 05973 pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ 05974 pte[PTE_Boot] = 0; /* Boot indicator */ 05975 pte[PTE_StHead] = 1; /* Start head */ 05976 pte[PTE_StSec] = 1; /* Start sector */ 05977 pte[PTE_StCyl] = 0; /* Start cylinder */ 05978 pte[PTE_System] = sys; /* System type */ 05979 n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ 05980 pte[PTE_EdHead] = 254; /* End head */ 05981 pte[PTE_EdSec] = (BYTE)(((n >> 2) & 0xC0) | 63); /* End sector */ 05982 pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ 05983 st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ 05984 st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ 05985 if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the MBR */ 05986 } 05987 } 05988 05989 if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); 05990 05991 LEAVE_MKFS(FR_OK); 05992 } 05993 05994 05995 05996 #if FF_MULTI_PARTITION 05997 /*-----------------------------------------------------------------------*/ 05998 /* Create Partition Table on the Physical Drive */ 05999 /*-----------------------------------------------------------------------*/ 06000 06001 FRESULT f_fdisk ( 06002 BYTE pdrv, /* Physical drive number */ 06003 const DWORD* szt, /* Pointer to the size table for each partitions */ 06004 void* work /* Pointer to the working buffer (null: use heap memory) */ 06005 ) 06006 { 06007 UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; 06008 BYTE s_hd, e_hd, *p, *buf; = (BYTE*)work; 06009 DSTATUS stat; 06010 DWORD sz_disk, sz_part, s_part; 06011 FRESULT res; 06012 06013 06014 stat = disk_initialize(pdrv); 06015 if (stat & STA_NOINIT) return FR_NOT_READY; 06016 if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; 06017 if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; 06018 06019 buf = (BYTE*)work; 06020 #if FF_USE_LFN == 3 06021 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ 06022 #endif 06023 if (!buf) return FR_NOT_ENOUGH_CORE; 06024 06025 /* Determine the CHS without any consideration of the drive geometry */ 06026 for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; 06027 if (n == 256) n--; 06028 e_hd = n - 1; 06029 sz_cyl = 63 * n; 06030 tot_cyl = sz_disk / sz_cyl; 06031 06032 /* Create partition table */ 06033 mem_set(buf, 0, FF_MAX_SS); 06034 p = buf + MBR_Table; b_cyl = 0; 06035 for (i = 0; i < 4; i++, p += SZ_PTE) { 06036 p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ 06037 if (p_cyl == 0) continue; 06038 s_part = (DWORD)sz_cyl * b_cyl; 06039 sz_part = (DWORD)sz_cyl * p_cyl; 06040 if (i == 0) { /* Exclude first track of cylinder 0 */ 06041 s_hd = 1; 06042 s_part += 63; sz_part -= 63; 06043 } else { 06044 s_hd = 0; 06045 } 06046 e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ 06047 if (e_cyl >= tot_cyl) LEAVE_MKFS(FR_INVALID_PARAMETER); 06048 06049 /* Set partition table */ 06050 p[1] = s_hd; /* Start head */ 06051 p[2] = (BYTE)(((b_cyl >> 2) & 0xC0) | 1); /* Start sector */ 06052 p[3] = (BYTE)b_cyl; /* Start cylinder */ 06053 p[4] = 0x07; /* System type (temporary setting) */ 06054 p[5] = e_hd; /* End head */ 06055 p[6] = (BYTE)(((e_cyl >> 2) & 0xC0) | 63); /* End sector */ 06056 p[7] = (BYTE)e_cyl; /* End cylinder */ 06057 st_dword(p + 8, s_part); /* Start sector in LBA */ 06058 st_dword(p + 12, sz_part); /* Number of sectors */ 06059 06060 /* Next partition */ 06061 b_cyl += p_cyl; 06062 } 06063 st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ 06064 06065 /* Write it to the MBR */ 06066 res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; 06067 LEAVE_MKFS(res); 06068 } 06069 06070 #endif /* FF_MULTI_PARTITION */ 06071 #endif /* FF_USE_MKFS && !FF_FS_READONLY */ 06072 06073 06074 06075 06076 #if FF_USE_STRFUNC 06077 #if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) 06078 #error Wrong FF_STRF_ENCODE setting 06079 #endif 06080 /*-----------------------------------------------------------------------*/ 06081 /* Get a String from the File */ 06082 /*-----------------------------------------------------------------------*/ 06083 06084 TCHAR* f_gets ( 06085 TCHAR* buff, /* Pointer to the string buffer to read */ 06086 int len, /* Size of string buffer (items) */ 06087 FIL* fp /* Pointer to the file object */ 06088 ) 06089 { 06090 int nc = 0; 06091 TCHAR *p = buff; 06092 BYTE s[2]; 06093 UINT rc; 06094 WCHAR wc; 06095 #if FF_USE_LFN && ((FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3) || (FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3)) 06096 DWORD dc; 06097 #endif 06098 #if FF_USE_LFN && FF_LFN_UNICODE == 1 && FF_STRF_ENCODE == 3 06099 UINT ct; 06100 #endif 06101 06102 #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 output */ 06103 #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ 06104 while (nc < len - 1) { 06105 f_read(fp, s, 1, &rc); 06106 if (rc != 1) break; 06107 wc = s[0]; 06108 if (dbc_1st((BYTE)wc)) { 06109 f_read(fp, s, 1, &rc); 06110 if (rc != 1 || !dbc_2nd(s[0])) continue; 06111 wc = wc << 8 | s[0]; 06112 } 06113 wc = ff_oem2uni(wc, CODEPAGE); 06114 if (wc == 0) continue; 06115 #elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ 06116 while (nc < len - 1) { 06117 f_read(fp, s, 2, &rc); 06118 if (rc != 2) break; 06119 wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; 06120 #elif FF_STRF_ENCODE == 3 /* Read a character in UTF-8 */ 06121 while (nc < len - 2) { 06122 f_read(fp, s, 1, &rc); 06123 if (rc != 1) break; 06124 dc = s[0]; 06125 if (dc >= 0x80) { 06126 ct = 0; 06127 if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } 06128 if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } 06129 if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } 06130 if (ct == 0) continue; 06131 do { 06132 f_read(fp, s, 1, &rc); 06133 if (rc != 1 || (s[0] & 0xC0) != 0x80) break; 06134 dc = dc << 6 | (s[0] & 0x3F); 06135 } while (--ct); 06136 if (ct || dc < 0x80 || dc >= 0x110000) continue; 06137 } 06138 if (dc >= 0x10000) { 06139 wc = (WCHAR)(0xD800 | ((dc >> 10) - 0x40)); 06140 *p++ = wc; nc++; 06141 wc = (WCHAR)(0xDC00 | (dc & 0x3FF)); 06142 } else { 06143 wc = (WCHAR)dc; 06144 } 06145 #endif 06146 /* Output it in UTF-16 encoding */ 06147 if (FF_USE_STRFUNC == 2 && wc == '\r') continue; 06148 *p++ = wc; nc++; 06149 if (wc == '\n') break; 06150 } 06151 06152 #elif FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 /* UTF-8 output */ 06153 while (nc < len - 4) { 06154 #if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ 06155 f_read(fp, s, 1, &rc); 06156 if (rc != 1) break; 06157 wc = s[0]; 06158 if (dbc_1st((BYTE)wc)) { 06159 f_read(fp, s, 1, &rc); 06160 if (rc != 1 || !dbc_2nd(s[0])) continue; 06161 wc = wc << 8 | s[0]; 06162 } 06163 dc = ff_oem2uni(wc, CODEPAGE); 06164 if (dc == 0) continue; 06165 #else /* Read a character in UTF-16LE/BE */ 06166 f_read(fp, s, 2, &rc); 06167 if (rc != 2) break; 06168 dc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; 06169 if (IsSurrogate(dc)) { 06170 f_read(fp, s, 2, &rc); 06171 if (rc != 2) break; 06172 wc = (FF_STRF_ENCODE == 1) ? s[1] << 8 | s[0] : s[0] << 8 | s[1]; 06173 if (!IsSurrogateH(dc) || !IsSurrogateL(wc)) continue; 06174 dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); 06175 } 06176 #endif 06177 /* Output it in UTF-8 encoding */ 06178 if (FF_USE_STRFUNC == 2 && dc == '\r') continue; 06179 if (dc < 0x80) { /* 1-byte */ 06180 *p++ = (TCHAR)dc; 06181 nc++; 06182 if (dc == '\n') break; 06183 } else { 06184 if (dc < 0x800) { /* 2-byte */ 06185 *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); 06186 *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); 06187 nc += 2; 06188 } else { 06189 if (dc < 0x10000) { /* 3-byte */ 06190 *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); 06191 *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); 06192 *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); 06193 nc += 3; 06194 } else { /* 4-byte */ 06195 *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); 06196 *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); 06197 *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); 06198 *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); 06199 nc += 4; 06200 } 06201 } 06202 } 06203 } 06204 06205 #else /* Byte-by-byte without any conversion (ANSI/OEM API or UTF-8 to UTF-8) */ 06206 while (nc < len - 1) { 06207 f_read(fp, s, 1, &rc); 06208 if (rc != 1) break; 06209 wc = s[0]; 06210 if (FF_USE_STRFUNC == 2 && wc == '\r') continue; 06211 *p++ = (TCHAR)wc; nc++; 06212 if (wc == '\n') break; 06213 } 06214 #endif 06215 06216 *p = 0; 06217 return nc ? buff : 0; /* When no data read (EOF or error), return with error. */ 06218 } 06219 06220 06221 06222 06223 #if !FF_FS_READONLY 06224 #include <stdarg.h> 06225 /*-----------------------------------------------------------------------*/ 06226 /* Put a Character to the File */ 06227 /*-----------------------------------------------------------------------*/ 06228 06229 typedef struct { /* Putchar output buffer and work area */ 06230 FIL *fp; /* Ptr to the writing file */ 06231 int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ 06232 #if FF_USE_LFN && FF_LFN_UNICODE == 1 06233 WCHAR hs; 06234 #elif FF_USE_LFN && FF_LFN_UNICODE == 2 06235 BYTE bs[4]; 06236 UINT wi, ct; 06237 #endif 06238 BYTE buf[64]; /* Write buffer */ 06239 } putbuff; 06240 06241 06242 static 06243 void putc_bfd ( /* Buffered write with code conversion */ 06244 putbuff* pb, 06245 TCHAR c 06246 ) 06247 { 06248 UINT n; 06249 int i, nc; 06250 #if FF_USE_LFN && (FF_LFN_UNICODE == 1 || (FF_LFN_UNICODE == 2 && (FF_STRF_ENCODE != 3))) 06251 WCHAR hs, wc; 06252 #endif 06253 #if FF_USE_LFN && FF_LFN_UNICODE == 2 && FF_STRF_ENCODE != 3 06254 DWORD dc; 06255 TCHAR *tp; 06256 #endif 06257 06258 if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ 06259 putc_bfd(pb, '\r'); 06260 } 06261 06262 i = pb->idx; /* Write index of pb->buf[] */ 06263 if (i < 0) return; 06264 nc = pb->nchr; /* Write unit count */ 06265 06266 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 06267 #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* UTF-16 input */ 06268 if (IsSurrogateH(c)) { 06269 pb->hs = c; return; 06270 } 06271 wc = c; hs = pb->hs; pb->hs = 0; 06272 if (hs != 0) { 06273 if (!IsSurrogateL(wc)) hs = 0; 06274 } else { 06275 if (IsSurrogateL(wc)) return; 06276 } 06277 #if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ 06278 if (hs != 0) { /* 4-byte */ 06279 nc += 4; 06280 hs = (hs & 0x3FF) + 0x40; 06281 pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); 06282 pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); 06283 pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); 06284 pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); 06285 } else { 06286 if (wc < 0x80) { /* 1-byte */ 06287 nc++; 06288 pb->buf[i++] = (BYTE)wc; 06289 } else { 06290 if (wc < 0x800) { /* 2-byte */ 06291 nc += 2; 06292 pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); 06293 } else { /* 3-byte */ 06294 nc += 3; 06295 pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); 06296 pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); 06297 } 06298 pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); 06299 } 06300 } 06301 #endif 06302 #else /* UTF-8 input */ 06303 for (;;) { 06304 if (pb->ct == 0) { /* Out of multi-byte sequence? */ 06305 pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ 06306 if ((BYTE)c < 0x80) break; /* 1-byte? */ 06307 if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte? */ 06308 if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte? */ 06309 if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte? */ 06310 return; 06311 } else { /* In the multi-byte sequence */ 06312 if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ 06313 pb->ct = 0; continue; 06314 } 06315 pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ 06316 if (--pb->ct == 0) break; /* End of sequence? */ 06317 return; 06318 } 06319 } 06320 #if FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ 06321 pb->buf[i++] = pb->bs[0]; nc++; 06322 if (pb->bs[0] >= 0xC0) { 06323 pb->buf[i++] = pb->bs[1]; nc++; 06324 } 06325 if (pb->bs[0] >= 0xE0) { 06326 pb->buf[i++] = pb->bs[2]; nc++; 06327 } 06328 if (pb->bs[0] >= 0xF0) { 06329 pb->buf[i++] = pb->bs[3]; nc++; 06330 } 06331 #else /* Write it in UTF-16 or ANSI/OEM */ 06332 tp = (TCHAR*)pb->bs; 06333 dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ 06334 if (dc == 0xFFFFFFFF) return; 06335 wc = (WCHAR)dc; 06336 hs = (WCHAR)(dc >> 16); 06337 #endif 06338 #endif 06339 #if FF_USE_LFN && FF_LFN_UNICODE >= 1 && FF_STRF_ENCODE != 3 06340 #if FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ 06341 if (hs != 0) { 06342 pb->buf[i++] = (BYTE)(hs >> 8); 06343 pb->buf[i++] = (BYTE)hs; 06344 nc++; 06345 } 06346 pb->buf[i++] = (BYTE)(wc >> 8); 06347 pb->buf[i++] = (BYTE)wc; 06348 nc++; 06349 #elif FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ 06350 if (hs != 0) { 06351 pb->buf[i++] = (BYTE)hs; 06352 pb->buf[i++] = (BYTE)(hs >> 8); 06353 nc++; 06354 } 06355 pb->buf[i++] = (BYTE)wc; 06356 pb->buf[i++] = (BYTE)(wc >> 8); 06357 nc++; 06358 #else /* Write a character in ANSI/OEM */ 06359 if (hs != 0) return; 06360 wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ 06361 if (wc == 0) return;; 06362 if (wc >= 0x100) { 06363 pb->buf[i++] = (BYTE)(wc >> 8); nc++; 06364 } 06365 pb->buf[i++] = (BYTE)wc; nc++; 06366 #endif 06367 #endif 06368 06369 #else /* ANSI/OEM input */ 06370 pb->buf[i++] = (BYTE)c; 06371 nc++; 06372 #endif 06373 06374 if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ 06375 f_write(pb->fp, pb->buf, (UINT)i, &n); 06376 i = (n == (UINT)i) ? 0 : -1; 06377 } 06378 pb->idx = i; 06379 pb->nchr = nc; 06380 } 06381 06382 06383 static 06384 int putc_flush ( /* Flush left characters in the buffer */ 06385 putbuff* pb 06386 ) 06387 { 06388 UINT nw; 06389 06390 if ( pb->idx >= 0 /* Flush buffered characters to the file */ 06391 && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK 06392 && (UINT)pb->idx == nw) return pb->nchr; 06393 return EOF; 06394 } 06395 06396 06397 static 06398 void putc_init ( /* Initialize write buffer */ 06399 putbuff* pb, 06400 FIL* fp 06401 ) 06402 { 06403 mem_set(pb, 0, sizeof (putbuff)); 06404 pb->fp = fp; 06405 } 06406 06407 06408 06409 int f_putc ( 06410 TCHAR c, /* A character to be output */ 06411 FIL* fp /* Pointer to the file object */ 06412 ) 06413 { 06414 putbuff pb; 06415 06416 06417 putc_init(&pb, fp); 06418 putc_bfd(&pb, c); /* Put the character */ 06419 return putc_flush(&pb); 06420 } 06421 06422 06423 06424 06425 /*-----------------------------------------------------------------------*/ 06426 /* Put a String to the File */ 06427 /*-----------------------------------------------------------------------*/ 06428 06429 int f_puts ( 06430 const TCHAR* str, /* Pointer to the string to be output */ 06431 FIL* fp /* Pointer to the file object */ 06432 ) 06433 { 06434 putbuff pb; 06435 06436 06437 putc_init(&pb, fp); 06438 while (*str) putc_bfd(&pb, *str++); /* Put the string */ 06439 return putc_flush(&pb); 06440 } 06441 06442 06443 06444 06445 /*-----------------------------------------------------------------------*/ 06446 /* Put a Formatted String to the File */ 06447 /*-----------------------------------------------------------------------*/ 06448 06449 int f_printf ( 06450 FIL* fp, /* Pointer to the file object */ 06451 const TCHAR* fmt, /* Pointer to the format string */ 06452 ... /* Optional arguments... */ 06453 ) 06454 { 06455 va_list arp; 06456 putbuff pb; 06457 BYTE f, r; 06458 UINT i, j, w; 06459 DWORD v; 06460 TCHAR c, d, str[32], *p; 06461 06462 06463 putc_init(&pb, fp); 06464 06465 va_start(arp, fmt); 06466 06467 for (;;) { 06468 c = *fmt++; 06469 if (c == 0) break; /* End of string */ 06470 if (c != '%') { /* Non escape character */ 06471 putc_bfd(&pb, c); 06472 continue; 06473 } 06474 w = f = 0; 06475 c = *fmt++; 06476 if (c == '0') { /* Flag: '0' padding */ 06477 f = 1; c = *fmt++; 06478 } else { 06479 if (c == '-') { /* Flag: left justified */ 06480 f = 2; c = *fmt++; 06481 } 06482 } 06483 if (c == '*') { /* Minimum width by argument */ 06484 w = va_arg(arp, int); 06485 c = *fmt++; 06486 } else { 06487 while (IsDigit(c)) { /* Minimum width */ 06488 w = w * 10 + c - '0'; 06489 c = *fmt++; 06490 } 06491 } 06492 if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ 06493 f |= 4; c = *fmt++; 06494 } 06495 if (c == 0) break; 06496 d = c; 06497 if (IsLower(d)) d -= 0x20; 06498 switch (d) { /* Atgument type is... */ 06499 case 'S' : /* String */ 06500 p = va_arg(arp, TCHAR*); 06501 for (j = 0; p[j]; j++) ; 06502 if (!(f & 2)) { /* Right padded */ 06503 while (j++ < w) putc_bfd(&pb, ' ') ; 06504 } 06505 while (*p) putc_bfd(&pb, *p++) ; /* String body */ 06506 while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ 06507 continue; 06508 06509 case 'C' : /* Character */ 06510 putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; 06511 06512 case 'B' : /* Unsigned binary */ 06513 r = 2; break; 06514 06515 case 'O' : /* Unsigned octal */ 06516 r = 8; break; 06517 06518 case 'D' : /* Signed decimal */ 06519 case 'U' : /* Unsigned decimal */ 06520 r = 10; break; 06521 06522 case 'X' : /* Unsigned hexdecimal */ 06523 r = 16; break; 06524 06525 default: /* Unknown type (pass-through) */ 06526 putc_bfd(&pb, c); continue; 06527 } 06528 06529 /* Get an argument and put it in numeral */ 06530 v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); 06531 if (d == 'D' && (v & 0x80000000)) { 06532 v = 0 - v; 06533 f |= 8; 06534 } 06535 i = 0; 06536 do { 06537 d = (TCHAR)(v % r); v /= r; 06538 if (d > 9) d += (c == 'x') ? 0x27 : 0x07; 06539 str[i++] = d + '0'; 06540 } while (v && i < sizeof str / sizeof *str); 06541 if (f & 8) str[i++] = '-'; 06542 j = i; d = (f & 1) ? '0' : ' '; 06543 if (!(f & 2)) { 06544 while (j++ < w) putc_bfd(&pb, d); /* Right pad */ 06545 } 06546 do { 06547 putc_bfd(&pb, str[--i]); /* Number body */ 06548 } while (i); 06549 while (j++ < w) putc_bfd(&pb, d); /* Left pad */ 06550 } 06551 06552 va_end(arp); 06553 06554 return putc_flush(&pb); 06555 } 06556 06557 #endif /* !FF_FS_READONLY */ 06558 #endif /* FF_USE_STRFUNC */ 06559 06560 06561 06562 #if FF_CODE_PAGE == 0 06563 /*-----------------------------------------------------------------------*/ 06564 /* Set Active Codepage for the Path Name */ 06565 /*-----------------------------------------------------------------------*/ 06566 06567 FRESULT f_setcp ( 06568 WORD cp /* Value to be set as active code page */ 06569 ) 06570 { 06571 static const WORD validcp[] = { 437, 720, 737, 771, 775, 850, 852, 857, 860, 861, 862, 863, 864, 865, 866, 869, 0}; 06572 static const BYTE *const tables[] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, 0}; 06573 UINT i; 06574 06575 06576 for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ 06577 if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ 06578 06579 CodePage = cp; 06580 if (cp >= 900) { /* DBCS */ 06581 ExCvt = 0; 06582 DbcTbl = tables[i]; 06583 } else { /* SBCS */ 06584 ExCvt = tables[i]; 06585 DbcTbl = 0; 06586 } 06587 return FR_OK; 06588 } 06589 #endif /* FF_CODE_PAGE == 0 */ 06590
Generated on Tue Jul 12 2022 14:23:45 by
