Gleb Klochkov / Mbed OS Climatcontroll_Main

Dependencies:   esp8266-driver

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