takashi kadono / Mbed OS Nucleo446_SSD1331

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ff.cpp Source File

ff.cpp

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