Newer
Older
int i;
/* Initialize unicode characters 1-nchunk */
for (i = 0; i < nchunk; i++)
{
/* The write the 16-bit 0xffff character into the directory entry. */
fat_putuint16((uint8_t *)chunk, (uint16_t)0xffff);
chunk += sizeof(wchar_t);
}
}
#endif
/****************************************************************************
* Name: fat_putlfnchunk
*
* Desciption: There are 13 characters per LFN entry, broken up into three
* chunks for characts 1-5, 6-11, and 12-13. This function will put the
* file name characters into one chunk.
*
****************************************************************************/
#ifdef CONFIG_FAT_LFN
static void fat_putlfnchunk(uint8_t *chunk, const uint8_t *src, int nchunk)
{
uint16_t wch;
int i;
/* Write bytes 1-nchunk */
for (i = 0; i < nchunk; i++)
{
/* Get the next ascii character from the name substring and convert it
* to unicode. The upper byte should be zero and the lower should be
* the ASCII code. The write the unicode character into the directory
* entry.
*/
wch = (uint16_t)*src++;
fat_putuint16(chunk, wch);
chunk += sizeof(wchar_t);
}
}
#endif
/****************************************************************************
* Name: fat_putlfname
*
* Desciption: Write the long filename into a sequence of directory entries.
* On entry, the "last" long file name entry is in the cache. Returns with
* the short file name entry in the cache.
*
****************************************************************************/
#ifdef CONFIG_FAT_LFN
static int fat_putlfname(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
uint16_t diroffset;
uint8_t *direntry;
uint8_t nfullentries;
uint8_t nentries;
uint8_t remainder;
uint8_t offset;
uint8_t seqno;
uint8_t checksum;
int namelen;
int ret;
patacongo
committed
/* Some special handling in case we are writing the first entry of the
* root directory in a freshly formatted volume.
*/
(void)fat_dirverify(fs, dirinfo, dirinfo->fd_seq.ds_lfnoffset);
/* Get the length of the long file name (size of the fd_lfname array is
* LDIR_MAXFNAME+1 we do not have to check the length of the string).
* NOTE that remainder is conditionally incremented to include the NUL
* terminating character that may also need be written to the directory
* entry. NUL terminating is not required if length is multiple of
* LDIR_MAXLFNCHARS (13).
namelen = strlen((char*)dirinfo->fd_lfname);
DEBUGASSERT(namelen <= LDIR_MAXFNAME+1);
/* How many LFN directory entries do we need to write? */
nfullentries = namelen / LDIR_MAXLFNCHARS;
remainder = namelen - nfullentries * LDIR_MAXLFNCHARS;
nentries = nfullentries;
if (remainder > 0)
{
nentries++;
remainder++;
}
DEBUGASSERT(nentries > 0 && nentries <= LDIR_MAXLFNS);
/* Create the short file name alias */
ret = fat_createalias(dirinfo);
if (ret < 0)
{
return ret;
}
/* Set up the initial positional data */
dirinfo->dir.fd_currcluster = dirinfo->fd_seq.ds_lfncluster;
dirinfo->dir.fd_currsector = dirinfo->fd_seq.ds_lfnsector;
dirinfo->dir.fd_index = dirinfo->fd_seq.ds_lfnoffset / DIR_SIZE;
/* Make sure that the alias is unique in this directory*/
ret = fat_uniquealias(fs, dirinfo);
if (ret < 0)
{
return ret;
}
/* Get the short file name checksum */
checksum = fat_lfnchecksum(dirinfo->fd_name);
/* Setup the starting sequence number */
seqno = LDIR0_LAST | nentries;
patacongo
committed
/* Now loop, writing each long file name entry. We know that the sector
* is in the sector cache because fat_dirverify() assures us that that is
* so.
*/
for (;;)
{
/* Get the string offset associated with the directory entry. */
/* Get a reference to the current directory entry */
diroffset = (dirinfo->dir.fd_index & DIRSEC_NDXMASK(fs)) * DIR_SIZE;
direntry = &fs->fs_buffer[diroffset];
/* Is this the "last" LFN directory entry? */
if ((seqno & LDIR0_LAST) != 0 && remainder != 0)
{
int nbytes;
/* Initialize the "last" directory entry name to all 0xffff */
fat_initlfname(LDIR_PTRWCHAR1_5(direntry), 5);
fat_initlfname(LDIR_PTRWCHAR6_11(direntry), 6);
fat_initlfname(LDIR_PTRWCHAR12_13(direntry), 2);
/* Store the tail portion of the long file name in directory entry */
nbytes = MIN(5, remainder);
fat_putlfnchunk(LDIR_PTRWCHAR1_5(direntry),
&dirinfo->fd_lfname[offset], nbytes);
remainder -= nbytes;
if (remainder > 0)
{
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
fat_putlfnchunk(LDIR_PTRWCHAR6_11(direntry),
&dirinfo->fd_lfname[offset+5], nbytes);
remainder -= nbytes;
}
if (remainder > 0)
{
nbytes = MIN(2, remainder);
fat_putlfnchunk(LDIR_PTRWCHAR12_13(direntry),
&dirinfo->fd_lfname[offset+11], nbytes);
remainder -= nbytes;
}
/* The remainder should now be zero */
DEBUGASSERT(remainder == 0);
}
else
{
/* Store a portion long file name in this directory entry */
fat_putlfnchunk(LDIR_PTRWCHAR1_5(direntry),
&dirinfo->fd_lfname[offset], 5);
fat_putlfnchunk(LDIR_PTRWCHAR6_11(direntry),
&dirinfo->fd_lfname[offset+5], 6);
fat_putlfnchunk(LDIR_PTRWCHAR12_13(direntry),
&dirinfo->fd_lfname[offset+11], 2);
}
/* Write the remaining directory entries */
LDIR_PUTSEQ(direntry, seqno);
LDIR_PUTATTRIBUTES(direntry, LDDIR_LFNATTR);
LDIR_PUTNTRES(direntry, 0);
LDIR_PUTCHECKSUM(direntry, checksum);
fs->fs_dirty = true;
/* Read next directory entry */
if (fat_nextdirentry(fs, &dirinfo->dir) != OK)
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
{
return -ENOENT;
}
/* Make sure that the sector containing the directory entry is in the
* sector cache
*/
ret = fat_fscacheread(fs, dirinfo->dir.fd_currsector);
if (ret < 0)
{
return ret;
}
/* Decrement the number of entries and get the next sequence number. */
if (--nentries <= 0)
{
/* We have written all of the long file name entries to the media
* and we have the short file name entry in the cache. We can
* just return success.
*/
return OK;
}
/* The sequence number is just the number of entries left to be
* written.
*/
seqno = nentries;
}
}
#endif
/****************************************************************************
* Name: fat_putsfdirentry
*
* Desciption: Write a short file name directory entry
*
* Assumption: The directory sector is in the cache. The caller will write
* sector information.
*
****************************************************************************/
static int fat_putsfdirentry(struct fat_mountpt_s *fs,
struct fat_dirinfo_s *dirinfo,
uint8_t attributes, uint32_t fattime)
{
uint8_t *direntry;
patacongo
committed
/* Some special handling in case we are writing the first entry of the
* root directory in a freshly formatted volume.
*/
(void)fat_dirverify(fs, dirinfo, dirinfo->fd_seq.ds_offset);
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
/* Initialize the 32-byte directory entry */
direntry = &fs->fs_buffer[dirinfo->fd_seq.ds_offset];
memset(direntry, 0, DIR_SIZE);
/* Directory name info */
(void)fat_putsfname(fs, dirinfo);
/* Set the attribute attribute, write time, creation time */
DIR_PUTATTRIBUTES(direntry, attributes);
/* Set the time information */
DIR_PUTWRTTIME(direntry, fattime & 0xffff);
DIR_PUTCRTIME(direntry, fattime & 0xffff);
DIR_PUTWRTDATE(direntry, fattime >> 16);
DIR_PUTCRDATE(direntry, fattime >> 16);
fs->fs_dirty = true;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: fat_finddirentry
*
* Desciption: Given a path to something that may or may not be in the file
* system, return the description of the directory entry of the requested
* item.
*
* NOTE: As a side effect, this function returns with the sector containing
* the short file name directory entry in the cache.
*
****************************************************************************/
int fat_finddirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
const char *path)
{
off_t cluster;
uint8_t *direntry;
char terminator;
int ret;
/* Initialize to traverse the chain. Set it to the cluster of the root
* directory
*/
cluster = fs->fs_rootbase;
if (fs->fs_type == FSTYPE_FAT32)
{
/* For FAT32, the root directory is variable sized and is a cluster
* chain like any other directory. fs_rootbase holds the first
* cluster of the root directory.
*/
dirinfo->dir.fd_startcluster = cluster;
dirinfo->dir.fd_currcluster = cluster;
dirinfo->dir.fd_currsector = fat_cluster2sector(fs, cluster);
}
else
{
/* For FAT12/16, the first sector of the root directory is a sector
* relative to the first sector of the fat volume.
*/
dirinfo->dir.fd_startcluster = 0;
dirinfo->dir.fd_currcluster = 0;
dirinfo->dir.fd_currsector = cluster;
}
patacongo
committed
/* fd_index is the index into the current directory table. It is set to one
* to skip over the first, unused entry in the root directory.
patacongo
committed
dirinfo->dir.fd_index = 1;
/* If no path was provided, then the root directory must be exactly what
* the caller is looking for.
*/
if (*path == '\0')
{
dirinfo->fd_root = true;
return OK;
}
/* This is not the root directory */
dirinfo->fd_root = false;
/* Now loop until the directory entry corresponding to the path is found */
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
for (;;)
{
/* Convert the next the path segment name into the kind of name that
* we would see in the directory entry.
*/
ret = fat_path2dirname(&path, dirinfo, &terminator);
if (ret < 0)
{
/* ERROR: The filename contains invalid characters or is
* too long.
*/
return ret;
}
/* Is this a path segment a long or a short file. Was a long file
* name parsed?
*/
#ifdef CONFIG_FAT_LFN
if (dirinfo->fd_lfname[0] != '\0')
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
{
/* Yes.. Search for the sequence of long file name directory
* entries. NOTE: As a side effect, this function returns with
* the sector containing the short file name directory entry
* in the cache.
*/
ret = fat_findlfnentry(fs, dirinfo);
}
else
#endif
{
/* No.. Search for the single short file name directory entry */
ret = fat_findsfnentry(fs, dirinfo);
}
/* Did we find the directory entries? */
if (ret < 0)
{
return ret;
}
/* If the terminator character in the path was the end of the string
* then we have successfully found the directory entry that describes
* the path.
*/
if (!terminator)
{
/* Return success meaning that the description the matching
* directory entry is in dirinfo.
*/
return OK;
}
/* No.. then we have found one of the intermediate directories on
* the way to the final path target. In this case, make sure
* the thing that we found is, indeed, a directory.
*/
direntry = &fs->fs_buffer[dirinfo->fd_seq.ds_offset];
if (!(DIR_GETATTRIBUTES(direntry) & FATATTR_DIRECTORY))
{
/* Ooops.. we found something else */
return -ENOTDIR;
}
/* Get the cluster number of this directory */
cluster =
((uint32_t)DIR_GETFSTCLUSTHI(direntry) << 16) |
DIR_GETFSTCLUSTLO(direntry);
patacongo
committed
/* Then restart scanning at the new directory, skipping over both the
* '.' and '..' entries that exist in all directories EXCEPT the root
* directory.
*/
dirinfo->dir.fd_startcluster = cluster;
dirinfo->dir.fd_currcluster = cluster;
dirinfo->dir.fd_currsector = fat_cluster2sector(fs, cluster);
dirinfo->dir.fd_index = 2;
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
}
}
/****************************************************************************
* Name: fat_allocatedirentry
*
* Desciption: Find a free directory entry
*
****************************************************************************/
int fat_allocatedirentry(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
int32_t cluster;
off_t sector;
int ret;
int i;
/* Re-initialize directory object */
cluster = dirinfo->dir.fd_startcluster;
/* Loop until we successfully allocate the sequence of directory entries
* or until to fail to extend the directory cluster chain.
*/
for (;;)
{
/* Can this cluster chain be extended */
dirinfo->dir.fd_currcluster = cluster;
dirinfo->dir.fd_currsector = fat_cluster2sector(fs, cluster);
}
else
{
/* Fixed size FAT12/16 root directory is at fixed offset/size */
dirinfo->dir.fd_currsector = fs->fs_rootbase;
}
patacongo
committed
/* Skip over the first, unused entry in the root directory. */
patacongo
committed
dirinfo->dir.fd_index = 1;
/* Is this a path segment a long or a short file. Was a long file
* name parsed?
*/
if (dirinfo->fd_lfname[0] != '\0')
/* Yes.. Allocate for the sequence of long file name directory
* entries plus a short file name directory entry.
*/
ret = fat_allocatelfnentry(fs, dirinfo);
}
/* No.. Allocate only a short file name directory entry */
else
#endif
{
ret = fat_allocatesfnentry(fs, dirinfo);
/* Did we successfully allocate the directory entries? If the error
* value is -ENOSPC, then we can try to extend the directory cluster
* (we can't handle other return values)
*/
if (ret == OK || ret != -ENOSPC)
{
return ret;
}
/* If we get here, then we have reached the end of the directory table
* in this sector without finding a free directory entry.
*
* It this is a fixed size directory entry, then this is an error.
* Otherwise, we can try to extend the directory cluster chain to
* make space for the new directory entry.
*/
if (!cluster)
{
/* The size is fixed */
/* Try to extend the cluster chain for this directory */
cluster = fat_extendchain(fs, dirinfo->dir.fd_currcluster);
if (cluster < 0)
{
return cluster;
}
/* Flush out any cached data in fs_buffer.. we are going to use
* it to initialize the new directory cluster.
*/
ret = fat_fscacheflush(fs);
if (ret < 0)
{
return ret;
}
/* Clear all sectors comprising the new directory cluster */
fs->fs_currentsector = fat_cluster2sector(fs, cluster);
memset(fs->fs_buffer, 0, fs->fs_hwsectorsize);
sector = fs->fs_currentsector;
ret = fat_hwwrite(fs, fs->fs_buffer, sector, 1);
}
}
}
/****************************************************************************
* Name: fat_freedirentry
*
* Desciption: Free the directory entry.
*
* NOTE: As a side effect, this function returns with the sector containing
* the deleted short file name directory entry in the cache.
*
****************************************************************************/
int fat_freedirentry(struct fat_mountpt_s *fs, struct fat_dirseq_s *seq)
struct fs_fatdir_s dir;
uint8_t *direntry;
int ret;
/* Set it to the cluster containing the "last" LFN entry (that appears
* first on the media).
*/
dir.fd_currcluster = seq->ds_lfncluster;
dir.fd_currsector = seq->ds_lfnsector;
dir.fd_index = seq->ds_lfnoffset / DIR_SIZE;
/* Free all of the directory entries used for the sequence of long file name
* and for the single short file name entry.
*/
for (;;)
{
/* Read the directory sector into the sector cache */
ret = fat_fscacheread(fs, dir.fd_currsector);
if (ret < 0)
{
return ret;
}
/* Get a pointer to the directory entry */
diroffset = (dir.fd_index & DIRSEC_NDXMASK(fs)) * DIR_SIZE;
direntry = &fs->fs_buffer[diroffset];
/* Then mark the entry as deleted */
direntry[DIR_NAME] = DIR0_EMPTY;
fs->fs_dirty = true;
/* Did we just free the single short file name entry? */
if (dir.fd_currsector == seq->ds_sector &&
diroffset == seq->ds_offset)
{
/* Yes.. then we are finished. flush anything remaining in the
* cache and return, probably successfully.
*/
return fat_fscacheflush(fs);
}
/* There are more entries to go.. Try the next directory entry */
ret = fat_nextdirentry(fs, &dir);
if (ret < 0)
{
return ret;
}
}
#else
uint8_t *direntry;
int ret;
/* Free the single short file name entry.
*
* Make sure that the sector containing the directory entry is in the
* cache.
*/
ret = fat_fscacheread(fs, seq->ds_sector);
if (ret == OK)
{
/* Then mark the entry as deleted */
direntry = &fs->fs_buffer[seq->ds_offset];
direntry[DIR_NAME] = DIR0_EMPTY;
fs->fs_dirty = true;
}
return ret;
}
/****************************************************************************
* Name: fat_dirname2path
*
* Desciption: Convert a filename in a raw directory entry into a user
* filename. This is essentially the inverse operation of that performed
* by fat_path2dirname. See that function for more details.
*
****************************************************************************/
int fat_dirname2path(struct fat_mountpt_s *fs, struct fs_dirent_s *dir)
uint16_t diroffset;
uint8_t *direntry;
uint8_t attribute;
#endif
/* Get a reference to the current directory entry */
diroffset = (dir->u.fat.fd_index & DIRSEC_NDXMASK(fs)) * DIR_SIZE;
direntry = &fs->fs_buffer[diroffset];
/* Does this entry refer to the last entry of a long file name? */
#ifdef CONFIG_FAT_LFN
attribute = DIR_GETATTRIBUTES(direntry);
if (((*direntry & LDIR0_LAST) != 0 && attribute == LDDIR_LFNATTR))
{
/* Yes.. Get the name from a sequence of long file name directory
* entries.
*/
return fat_getlfname(fs, dir);
{
/* No.. Get the name from a short file name directory entries */
return fat_getsfname(direntry, dir->fd_dir.d_name, NAME_MAX+1);
}
}
/****************************************************************************
* Name: fat_dirnamewrite
*
* Desciption: Write the (possibly long) directory entry name. This function
* is called only from fat_rename to write the new file name.
* Assumption: The directory sector containing the short file name entry
* is in the cache. *NOT* the sector containing the last long file name
* entry!
*
****************************************************************************/
int fat_dirnamewrite(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
#ifdef CONFIG_FAT_LFN
int ret;
/* Is this a long file name? */
if (dirinfo->fd_lfname[0] != '\0')
{
/* Write the sequence of long file name directory entries (this function
* also creates the short file name alias).
*/
ret = fat_putlfname(fs, dirinfo);
if (ret != OK)
{
return ret;
}
}
/* On return, fat_lfsfname() will leave the short file name entry in the
* cache. So we can just fall throught to write that directory entry, perhaps
* using the short file name alias for the long file name.
*/
return fat_putsfname(fs, dirinfo);
}
/****************************************************************************
* Name: fat_dirwrite
*
* Desciption: Write a directory entry, possibly with a long file name.
* Called from:
*
* fat_mkdir() to write the new FAT directory entry.
* fat_dircreate() to create any new directory entry.
*
* Assumption: The directory sector is in the cache. The caller will write
* sector information.
*
****************************************************************************/
int fat_dirwrite(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo,
uint8_t attributes, uint32_t fattime)
{
#ifdef CONFIG_FAT_LFN
int ret;
/* Does this directory entry have a long file name? */
if (dirinfo->fd_lfname[0] != '\0')
/* Write the sequence of long file name directory entries (this function
* also creates the short file name alias).
*/
ret = fat_putlfname(fs, dirinfo);
if (ret != OK)
{
return ret;
}
}
/* On return, fat_lfsfname() will leave the short file name entry in the
* cache. So we can just fall throught to write that directory entry, perhaps
* using the short file name alias for the long file name.
*/
#endif
/* Put the short file name entry data */
return fat_putsfdirentry(fs, dirinfo, attributes, fattime);
}
/****************************************************************************
* Name: fat_dircreate
*
* Desciption: Create a directory entry for a new file
*
****************************************************************************/
int fat_dircreate(struct fat_mountpt_s *fs, struct fat_dirinfo_s *dirinfo)
{
uint32_t fattime;
int ret;
/* Allocate a directory entry. If long file name support is enabled, then
* this might, in fact, allocate a sequence of directory entries.
*/
ret = fat_allocatedirentry(fs, dirinfo);
if (ret != OK)
{
/* Failed to allocate the required directory entry or entries. */
return ret;
}
/* Write the directory entry (or entries) with the current time and the
* ARCHIVE attribute.
*/
fattime = fat_systime2fattime();
return fat_dirwrite(fs, dirinfo, FATATTR_ARCHIVE, fattime);
}
/****************************************************************************
* Name: fat_remove
*
* Desciption: Remove a directory or file from the file system. This
* implements both rmdir() and unlink().
*
****************************************************************************/
int fat_remove(struct fat_mountpt_s *fs, const char *relpath, bool directory)
{
struct fat_dirinfo_s dirinfo;
uint32_t dircluster;
uint8_t *direntry;
int ret;
/* Find the directory entry referring to the entry to be deleted */
ret = fat_finddirentry(fs, &dirinfo, relpath);
if (ret != OK)
{
/* No such path */
return -ENOENT;
}
/* Check if this is a FAT12/16 root directory */
if (dirinfo.fd_root)
{
/* The root directory cannot be removed */
return -EPERM;
}
/* The object has to have write access to be deleted */
direntry = &fs->fs_buffer[dirinfo.fd_seq.ds_offset];
if ((DIR_GETATTRIBUTES(direntry) & FATATTR_READONLY) != 0)
{
/* It is a read-only entry */
return -EACCES;
}
/* Get the directory sector and cluster containing the entry to be deleted. */
((uint32_t)DIR_GETFSTCLUSTHI(direntry) << 16) |
DIR_GETFSTCLUSTLO(direntry);
/* Is this entry a directory? */
if (DIR_GETATTRIBUTES(direntry) & FATATTR_DIRECTORY)
{
/* It is a sub-directory. Check if we are be asked to remove
* a directory or a file.
*/
if (!directory)
{
/* We are asked to delete a file */
return -EISDIR;
}
patacongo
committed
/* We are asked to delete a directory. Check if this sub-directory is
* empty (i.e., that there are no valid entries other than the initial
* '.' and '..' entries).
*/
dirinfo.dir.fd_currcluster = dircluster;
dirinfo.dir.fd_currsector = fat_cluster2sector(fs, dircluster);
dirinfo.dir.fd_index = 2;
/* Loop until either (1) an entry is found in the directory (error),
* (2) the directory is found to be empty, or (3) some error occurs.
*/
for (;;)
{
unsigned int subdirindex;
uint8_t *subdirentry;
/* Make sure that the sector containing the of the subdirectory
* sector is in the cache
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
*/
ret = fat_fscacheread(fs, dirinfo.dir.fd_currsector);
if (ret < 0)
{
return ret;
}
/* Get a reference to the next entry in the directory */
subdirindex = (dirinfo.dir.fd_index & DIRSEC_NDXMASK(fs)) * DIR_SIZE;
subdirentry = &fs->fs_buffer[subdirindex];
/* Is this the last entry in the direcory? */
if (subdirentry[DIR_NAME] == DIR0_ALLEMPTY)
{
/* Yes then the directory is empty. Break out of the
* loop and delete the directory.
*/
break;
}
/* Check if the next entry refers to a file or directory */
if (subdirentry[DIR_NAME] != DIR0_EMPTY &&
!(DIR_GETATTRIBUTES(subdirentry) & FATATTR_VOLUMEID))
{
/* The directory is not empty */
return -ENOTEMPTY;
}
/* Get the next directory entry */
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
ret = fat_nextdirentry(fs, &dirinfo.dir);
if (ret < 0)
{
return ret;
}
}
}
else
{
/* It is a file. Check if we are be asked to remove a directory
* or a file.
*/
if (directory)
{
/* We are asked to remove a directory */
return -ENOTDIR;
}
}
/* Mark the directory entry 'deleted'. If long file name support is
* enabled, then multiple directory entries may be freed.
*/
ret = fat_freedirentry(fs, &dirinfo.fd_seq);
if (ret < 0)
{
return ret;
}
/* And remove the cluster chain making up the subdirectory */
ret = fat_removechain(fs, dircluster);
if (ret < 0)
{
return ret;
}
/* Update the FSINFO sector (FAT32) */
ret = fat_updatefsinfo(fs);
if (ret < 0)
{