]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Plugson/src/Lib/fat_io_lib/fat_filelib.c
1. Fix the blank item in the last of Language select menu
[Ventoy.git] / Plugson / src / Lib / fat_io_lib / fat_filelib.c
1 //-----------------------------------------------------------------------------
2 //-----------------------------------------------------------------------------
3 // FAT16/32 File IO Library
4 // V2.6
5 // Ultra-Embedded.com
6 // Copyright 2003 - 2012
7 //
8 // Email: admin@ultra-embedded.com
9 //
10 // License: GPL
11 // If you would like a version with a more permissive license for use in
12 // closed source commercial applications please contact me for details.
13 //-----------------------------------------------------------------------------
14 //
15 // This file is part of FAT File IO Library.
16 //
17 // FAT File IO Library is free software; you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation; either version 2 of the License, or
20 // (at your option) any later version.
21 //
22 // FAT File IO Library is distributed in the hope that it will be useful,
23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 // GNU General Public License for more details.
26 //
27 // You should have received a copy of the GNU General Public License
28 // along with FAT File IO Library; if not, write to the Free Software
29 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
32 #include <stdlib.h>
33 #include <string.h>
34 #include "fat_defs.h"
35 #include "fat_access.h"
36 #include "fat_table.h"
37 #include "fat_write.h"
38 #include "fat_misc.h"
39 #include "fat_string.h"
40 #include "fat_filelib.h"
41 #include "fat_cache.h"
42
43 //-----------------------------------------------------------------------------
44 // Locals
45 //-----------------------------------------------------------------------------
46 static FL_FILE _files[FATFS_MAX_OPEN_FILES];
47 static int _filelib_init = 0;
48 static int _filelib_valid = 0;
49 static struct fatfs _fs;
50 static struct fat_list _open_file_list;
51 static struct fat_list _free_file_list;
52
53 //-----------------------------------------------------------------------------
54 // Macros
55 //-----------------------------------------------------------------------------
56
57 // Macro for checking if file lib is initialised
58 #define CHECK_FL_INIT() { if (_filelib_init==0) fl_init(); }
59
60 #define FL_LOCK(a) do { if ((a)->fl_lock) (a)->fl_lock(); } while (0)
61 #define FL_UNLOCK(a) do { if ((a)->fl_unlock) (a)->fl_unlock(); } while (0)
62
63 //-----------------------------------------------------------------------------
64 // Local Functions
65 //-----------------------------------------------------------------------------
66 static void _fl_init();
67
68 //-----------------------------------------------------------------------------
69 // _allocate_file: Find a slot in the open files buffer for a new file
70 //-----------------------------------------------------------------------------
71 static FL_FILE* _allocate_file(void)
72 {
73 // Allocate free file
74 struct fat_node *node = fat_list_pop_head(&_free_file_list);
75
76 // Add to open list
77 if (node)
78 fat_list_insert_last(&_open_file_list, node);
79
80 return fat_list_entry(node, FL_FILE, list_node);
81 }
82 //-----------------------------------------------------------------------------
83 // _check_file_open: Returns true if the file is already open
84 //-----------------------------------------------------------------------------
85 static int _check_file_open(FL_FILE* file)
86 {
87 struct fat_node *node;
88
89 // Compare open files
90 fat_list_for_each(&_open_file_list, node)
91 {
92 FL_FILE* openFile = fat_list_entry(node, FL_FILE, list_node);
93
94 // If not the current file
95 if (openFile != file)
96 {
97 // Compare path and name
98 if ( (fatfs_compare_names(openFile->path,file->path)) && (fatfs_compare_names(openFile->filename,file->filename)) )
99 return 1;
100 }
101 }
102
103 return 0;
104 }
105 //-----------------------------------------------------------------------------
106 // _free_file: Free open file handle
107 //-----------------------------------------------------------------------------
108 static void _free_file(FL_FILE* file)
109 {
110 // Remove from open list
111 fat_list_remove(&_open_file_list, &file->list_node);
112
113 // Add to free list
114 fat_list_insert_last(&_free_file_list, &file->list_node);
115 }
116
117 //-----------------------------------------------------------------------------
118 // Low Level
119 //-----------------------------------------------------------------------------
120
121 //-----------------------------------------------------------------------------
122 // _open_directory: Cycle through path string to find the start cluster
123 // address of the highest subdir.
124 //-----------------------------------------------------------------------------
125 static int _open_directory(char *path, uint32 *pathCluster)
126 {
127 int levels;
128 int sublevel;
129 char currentfolder[FATFS_MAX_LONG_FILENAME];
130 struct fat_dir_entry sfEntry;
131 uint32 startcluster;
132
133 // Set starting cluster to root cluster
134 startcluster = fatfs_get_root_cluster(&_fs);
135
136 // Find number of levels
137 levels = fatfs_total_path_levels(path);
138
139 // Cycle through each level and get the start sector
140 for (sublevel=0;sublevel<(levels+1);sublevel++)
141 {
142 if (fatfs_get_substring(path, sublevel, currentfolder, sizeof(currentfolder)) == -1)
143 return 0;
144
145 // Find clusteraddress for folder (currentfolder)
146 if (fatfs_get_file_entry(&_fs, startcluster, currentfolder,&sfEntry))
147 {
148 // Check entry is folder
149 if (fatfs_entry_is_dir(&sfEntry))
150 startcluster = ((FAT_HTONS((uint32)sfEntry.FstClusHI))<<16) + FAT_HTONS(sfEntry.FstClusLO);
151 else
152 return 0;
153 }
154 else
155 return 0;
156 }
157
158 *pathCluster = startcluster;
159 return 1;
160 }
161 //-----------------------------------------------------------------------------
162 // _create_directory: Cycle through path string and create the end directory
163 //-----------------------------------------------------------------------------
164 #if FATFS_INC_WRITE_SUPPORT
165 static int _create_directory(char *path)
166 {
167 FL_FILE* file;
168 struct fat_dir_entry sfEntry;
169 char shortFilename[FAT_SFN_SIZE_FULL];
170 int tailNum = 0;
171 int i;
172
173 // Allocate a new file handle
174 file = _allocate_file();
175 if (!file)
176 return 0;
177
178 // Clear filename
179 memset(file->path, '\0', sizeof(file->path));
180 memset(file->filename, '\0', sizeof(file->filename));
181
182 // Split full path into filename and directory path
183 if (fatfs_split_path((char*)path, file->path, sizeof(file->path), file->filename, sizeof(file->filename)) == -1)
184 {
185 _free_file(file);
186 return 0;
187 }
188
189 // Check if file already open
190 if (_check_file_open(file))
191 {
192 _free_file(file);
193 return 0;
194 }
195
196 // If file is in the root dir
197 if (file->path[0] == 0)
198 file->parentcluster = fatfs_get_root_cluster(&_fs);
199 else
200 {
201 // Find parent directory start cluster
202 if (!_open_directory(file->path, &file->parentcluster))
203 {
204 _free_file(file);
205 return 0;
206 }
207 }
208
209 // Check if same filename exists in directory
210 if (fatfs_get_file_entry(&_fs, file->parentcluster, file->filename,&sfEntry) == 1)
211 {
212 _free_file(file);
213 return 0;
214 }
215
216 file->startcluster = 0;
217
218 // Create the file space for the folder (at least one clusters worth!)
219 if (!fatfs_allocate_free_space(&_fs, 1, &file->startcluster, 1))
220 {
221 _free_file(file);
222 return 0;
223 }
224
225 // Erase new directory cluster
226 memset(file->file_data_sector, 0x00, FAT_SECTOR_SIZE);
227 for (i=0;i<_fs.sectors_per_cluster;i++)
228 {
229 if (!fatfs_write_sector(&_fs, file->startcluster, i, file->file_data_sector))
230 {
231 _free_file(file);
232 return 0;
233 }
234 }
235
236 #if FATFS_INC_LFN_SUPPORT
237
238 // Generate a short filename & tail
239 tailNum = 0;
240 do
241 {
242 // Create a standard short filename (without tail)
243 fatfs_lfn_create_sfn(shortFilename, file->filename);
244
245 // If second hit or more, generate a ~n tail
246 if (tailNum != 0)
247 fatfs_lfn_generate_tail((char*)file->shortfilename, shortFilename, tailNum);
248 // Try with no tail if first entry
249 else
250 memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
251
252 // Check if entry exists already or not
253 if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename) == 0)
254 break;
255
256 tailNum++;
257 }
258 while (tailNum < 9999);
259
260 // We reached the max number of duplicate short file names (unlikely!)
261 if (tailNum == 9999)
262 {
263 // Delete allocated space
264 fatfs_free_cluster_chain(&_fs, file->startcluster);
265
266 _free_file(file);
267 return 0;
268 }
269 #else
270 // Create a standard short filename (without tail)
271 if (!fatfs_lfn_create_sfn(shortFilename, file->filename))
272 {
273 // Delete allocated space
274 fatfs_free_cluster_chain(&_fs, file->startcluster);
275
276 _free_file(file);
277 return 0;
278 }
279
280 // Copy to SFN space
281 memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
282
283 // Check if entry exists already
284 if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename))
285 {
286 // Delete allocated space
287 fatfs_free_cluster_chain(&_fs, file->startcluster);
288
289 _free_file(file);
290 return 0;
291 }
292 #endif
293
294 // Add file to disk
295 if (!fatfs_add_file_entry(&_fs, file->parentcluster, (char*)file->filename, (char*)file->shortfilename, file->startcluster, 0, 1))
296 {
297 // Delete allocated space
298 fatfs_free_cluster_chain(&_fs, file->startcluster);
299
300 _free_file(file);
301 return 0;
302 }
303
304 // General
305 file->filelength = 0;
306 file->bytenum = 0;
307 file->file_data_address = 0xFFFFFFFF;
308 file->file_data_dirty = 0;
309 file->filelength_changed = 0;
310
311 // Quick lookup for next link in the chain
312 file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
313 file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
314
315 fatfs_fat_purge(&_fs);
316
317 _free_file(file);
318 return 1;
319 }
320 #endif
321 //-----------------------------------------------------------------------------
322 // _open_file: Open a file for reading
323 //-----------------------------------------------------------------------------
324 static FL_FILE* _open_file(const char *path)
325 {
326 FL_FILE* file;
327 struct fat_dir_entry sfEntry;
328
329 // Allocate a new file handle
330 file = _allocate_file();
331 if (!file)
332 return NULL;
333
334 // Clear filename
335 memset(file->path, '\0', sizeof(file->path));
336 memset(file->filename, '\0', sizeof(file->filename));
337
338 // Split full path into filename and directory path
339 if (fatfs_split_path((char*)path, file->path, sizeof(file->path), file->filename, sizeof(file->filename)) == -1)
340 {
341 _free_file(file);
342 return NULL;
343 }
344
345 // Check if file already open
346 if (_check_file_open(file))
347 {
348 _free_file(file);
349 return NULL;
350 }
351
352 // If file is in the root dir
353 if (file->path[0]==0)
354 file->parentcluster = fatfs_get_root_cluster(&_fs);
355 else
356 {
357 // Find parent directory start cluster
358 if (!_open_directory(file->path, &file->parentcluster))
359 {
360 _free_file(file);
361 return NULL;
362 }
363 }
364
365 // Using dir cluster address search for filename
366 if (fatfs_get_file_entry(&_fs, file->parentcluster, file->filename,&sfEntry))
367 // Make sure entry is file not dir!
368 if (fatfs_entry_is_file(&sfEntry))
369 {
370 // Initialise file details
371 memcpy(file->shortfilename, sfEntry.Name, FAT_SFN_SIZE_FULL);
372 file->filelength = FAT_HTONL(sfEntry.FileSize);
373 file->bytenum = 0;
374 file->startcluster = ((FAT_HTONS((uint32)sfEntry.FstClusHI))<<16) + FAT_HTONS(sfEntry.FstClusLO);
375 file->file_data_address = 0xFFFFFFFF;
376 file->file_data_dirty = 0;
377 file->filelength_changed = 0;
378
379 // Quick lookup for next link in the chain
380 file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
381 file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
382
383 fatfs_cache_init(&_fs, file);
384
385 fatfs_fat_purge(&_fs);
386
387 return file;
388 }
389
390 _free_file(file);
391 return NULL;
392 }
393 //-----------------------------------------------------------------------------
394 // _create_file: Create a new file
395 //-----------------------------------------------------------------------------
396 #if FATFS_INC_WRITE_SUPPORT
397 static FL_FILE* _create_file(const char *filename)
398 {
399 FL_FILE* file;
400 struct fat_dir_entry sfEntry;
401 char shortFilename[FAT_SFN_SIZE_FULL];
402 int tailNum = 0;
403
404 // No write access?
405 if (!_fs.disk_io.write_media)
406 return NULL;
407
408 // Allocate a new file handle
409 file = _allocate_file();
410 if (!file)
411 return NULL;
412
413 // Clear filename
414 memset(file->path, '\0', sizeof(file->path));
415 memset(file->filename, '\0', sizeof(file->filename));
416
417 // Split full path into filename and directory path
418 if (fatfs_split_path((char*)filename, file->path, sizeof(file->path), file->filename, sizeof(file->filename)) == -1)
419 {
420 _free_file(file);
421 return NULL;
422 }
423
424 // Check if file already open
425 if (_check_file_open(file))
426 {
427 _free_file(file);
428 return NULL;
429 }
430
431 // If file is in the root dir
432 if (file->path[0] == 0)
433 file->parentcluster = fatfs_get_root_cluster(&_fs);
434 else
435 {
436 // Find parent directory start cluster
437 if (!_open_directory(file->path, &file->parentcluster))
438 {
439 _free_file(file);
440 return NULL;
441 }
442 }
443
444 // Check if same filename exists in directory
445 if (fatfs_get_file_entry(&_fs, file->parentcluster, file->filename,&sfEntry) == 1)
446 {
447 _free_file(file);
448 return NULL;
449 }
450
451 file->startcluster = 0;
452
453 // Create the file space for the file (at least one clusters worth!)
454 if (!fatfs_allocate_free_space(&_fs, 1, &file->startcluster, 1))
455 {
456 _free_file(file);
457 return NULL;
458 }
459
460 #if FATFS_INC_LFN_SUPPORT
461 // Generate a short filename & tail
462 tailNum = 0;
463 do
464 {
465 // Create a standard short filename (without tail)
466 fatfs_lfn_create_sfn(shortFilename, file->filename);
467
468 // If second hit or more, generate a ~n tail
469 if (tailNum != 0)
470 fatfs_lfn_generate_tail((char*)file->shortfilename, shortFilename, tailNum);
471 // Try with no tail if first entry
472 else
473 memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
474
475 // Check if entry exists already or not
476 if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename) == 0)
477 break;
478
479 tailNum++;
480 }
481 while (tailNum < 9999);
482
483 // We reached the max number of duplicate short file names (unlikely!)
484 if (tailNum == 9999)
485 {
486 // Delete allocated space
487 fatfs_free_cluster_chain(&_fs, file->startcluster);
488
489 _free_file(file);
490 return NULL;
491 }
492 #else
493 // Create a standard short filename (without tail)
494 if (!fatfs_lfn_create_sfn(shortFilename, file->filename))
495 {
496 // Delete allocated space
497 fatfs_free_cluster_chain(&_fs, file->startcluster);
498
499 _free_file(file);
500 return NULL;
501 }
502
503 // Copy to SFN space
504 memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
505
506 // Check if entry exists already
507 if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename))
508 {
509 // Delete allocated space
510 fatfs_free_cluster_chain(&_fs, file->startcluster);
511
512 _free_file(file);
513 return NULL;
514 }
515 #endif
516
517 // Add file to disk
518 if (!fatfs_add_file_entry(&_fs, file->parentcluster, (char*)file->filename, (char*)file->shortfilename, file->startcluster, 0, 0))
519 {
520 // Delete allocated space
521 fatfs_free_cluster_chain(&_fs, file->startcluster);
522
523 _free_file(file);
524 return NULL;
525 }
526
527 // General
528 file->filelength = 0;
529 file->bytenum = 0;
530 file->file_data_address = 0xFFFFFFFF;
531 file->file_data_dirty = 0;
532 file->filelength_changed = 0;
533
534 // Quick lookup for next link in the chain
535 file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
536 file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
537
538 fatfs_cache_init(&_fs, file);
539
540 fatfs_fat_purge(&_fs);
541
542 return file;
543 }
544 #endif
545 //-----------------------------------------------------------------------------
546 // _read_sectors: Read sector(s) from disk to file
547 //-----------------------------------------------------------------------------
548 static uint32 _read_sectors(FL_FILE* file, uint32 offset, uint8 *buffer, uint32 count)
549 {
550 uint32 Sector = 0;
551 uint32 ClusterIdx = 0;
552 uint32 Cluster = 0;
553 uint32 i;
554 uint32 lba;
555
556 // Find cluster index within file & sector with cluster
557 ClusterIdx = offset / _fs.sectors_per_cluster;
558 Sector = offset - (ClusterIdx * _fs.sectors_per_cluster);
559
560 // Limit number of sectors read to the number remaining in this cluster
561 if ((Sector + count) > _fs.sectors_per_cluster)
562 count = _fs.sectors_per_cluster - Sector;
563
564 // Quick lookup for next link in the chain
565 if (ClusterIdx == file->last_fat_lookup.ClusterIdx)
566 Cluster = file->last_fat_lookup.CurrentCluster;
567 // Else walk the chain
568 else
569 {
570 // Starting from last recorded cluster?
571 if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1)
572 {
573 i = file->last_fat_lookup.ClusterIdx;
574 Cluster = file->last_fat_lookup.CurrentCluster;
575 }
576 // Start searching from the beginning..
577 else
578 {
579 // Set start of cluster chain to initial value
580 i = 0;
581 Cluster = file->startcluster;
582 }
583
584 // Follow chain to find cluster to read
585 for ( ;i<ClusterIdx; i++)
586 {
587 uint32 nextCluster;
588
589 // Does the entry exist in the cache?
590 if (!fatfs_cache_get_next_cluster(&_fs, file, i, &nextCluster))
591 {
592 // Scan file linked list to find next entry
593 nextCluster = fatfs_find_next_cluster(&_fs, Cluster);
594
595 // Push entry into cache
596 fatfs_cache_set_next_cluster(&_fs, file, i, nextCluster);
597 }
598
599 Cluster = nextCluster;
600 }
601
602 // Record current cluster lookup details (if valid)
603 if (Cluster != FAT32_LAST_CLUSTER)
604 {
605 file->last_fat_lookup.CurrentCluster = Cluster;
606 file->last_fat_lookup.ClusterIdx = ClusterIdx;
607 }
608 }
609
610 // If end of cluster chain then return false
611 if (Cluster == FAT32_LAST_CLUSTER)
612 return 0;
613
614 // Calculate sector address
615 lba = fatfs_lba_of_cluster(&_fs, Cluster) + Sector;
616
617 // Read sector of file
618 if (fatfs_sector_read(&_fs, lba, buffer, count))
619 return count;
620 else
621 return 0;
622 }
623
624 //-----------------------------------------------------------------------------
625 // External API
626 //-----------------------------------------------------------------------------
627
628 //-----------------------------------------------------------------------------
629 // fl_init: Initialise library
630 //-----------------------------------------------------------------------------
631 void fl_init(void)
632 {
633 int i;
634
635 fat_list_init(&_free_file_list);
636 fat_list_init(&_open_file_list);
637
638 // Add all file objects to free list
639 for (i=0;i<FATFS_MAX_OPEN_FILES;i++)
640 fat_list_insert_last(&_free_file_list, &_files[i].list_node);
641
642 _filelib_init = 1;
643 }
644 //-----------------------------------------------------------------------------
645 // fl_attach_locks:
646 //-----------------------------------------------------------------------------
647 void fl_attach_locks(void (*lock)(void), void (*unlock)(void))
648 {
649 _fs.fl_lock = lock;
650 _fs.fl_unlock = unlock;
651 }
652 //-----------------------------------------------------------------------------
653 // fl_attach_media:
654 //-----------------------------------------------------------------------------
655 int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr)
656 {
657 int res;
658
659 // If first call to library, initialise
660 CHECK_FL_INIT();
661
662 _fs.disk_io.read_media = rd;
663 _fs.disk_io.write_media = wr;
664
665 // Initialise FAT parameters
666 if ((res = fatfs_init(&_fs)) != FAT_INIT_OK)
667 {
668 FAT_PRINTF(("FAT_FS: Error could not load FAT details (%d)!\r\n", res));
669 return res;
670 }
671
672 _filelib_valid = 1;
673 return FAT_INIT_OK;
674 }
675 //-----------------------------------------------------------------------------
676 // fl_shutdown: Call before shutting down system
677 //-----------------------------------------------------------------------------
678 void fl_shutdown(void)
679 {
680 // If first call to library, initialise
681 CHECK_FL_INIT();
682
683 FL_LOCK(&_fs);
684 fatfs_fat_purge(&_fs);
685 FL_UNLOCK(&_fs);
686 }
687 //-----------------------------------------------------------------------------
688 // fopen: Open or Create a file for reading or writing
689 //-----------------------------------------------------------------------------
690 void* fl_fopen(const char *path, const char *mode)
691 {
692 int i;
693 FL_FILE* file;
694 uint8 flags = 0;
695
696 // If first call to library, initialise
697 CHECK_FL_INIT();
698
699 if (!_filelib_valid)
700 return NULL;
701
702 if (!path || !mode)
703 return NULL;
704
705 // Supported Modes:
706 // "r" Open a file for reading.
707 // The file must exist.
708 // "w" Create an empty file for writing.
709 // If a file with the same name already exists its content is erased and the file is treated as a new empty file.
710 // "a" Append to a file.
711 // Writing operations append data at the end of the file.
712 // The file is created if it does not exist.
713 // "r+" Open a file for update both reading and writing.
714 // The file must exist.
715 // "w+" Create an empty file for both reading and writing.
716 // If a file with the same name already exists its content is erased and the file is treated as a new empty file.
717 // "a+" Open a file for reading and appending.
718 // All writing operations are performed at the end of the file, protecting the previous content to be overwritten.
719 // You can reposition (fseek, rewind) the internal pointer to anywhere in the file for reading, but writing operations
720 // will move it back to the end of file.
721 // The file is created if it does not exist.
722
723 for (i=0;i<(int)strlen(mode);i++)
724 {
725 switch (mode[i])
726 {
727 case 'r':
728 case 'R':
729 flags |= FILE_READ;
730 break;
731 case 'w':
732 case 'W':
733 flags |= FILE_WRITE;
734 flags |= FILE_ERASE;
735 flags |= FILE_CREATE;
736 break;
737 case 'a':
738 case 'A':
739 flags |= FILE_WRITE;
740 flags |= FILE_APPEND;
741 flags |= FILE_CREATE;
742 break;
743 case '+':
744 if (flags & FILE_READ)
745 flags |= FILE_WRITE;
746 else if (flags & FILE_WRITE)
747 {
748 flags |= FILE_READ;
749 flags |= FILE_ERASE;
750 flags |= FILE_CREATE;
751 }
752 else if (flags & FILE_APPEND)
753 {
754 flags |= FILE_READ;
755 flags |= FILE_WRITE;
756 flags |= FILE_APPEND;
757 flags |= FILE_CREATE;
758 }
759 break;
760 case 'b':
761 case 'B':
762 flags |= FILE_BINARY;
763 break;
764 }
765 }
766
767 file = NULL;
768
769 #if FATFS_INC_WRITE_SUPPORT == 0
770 // No write support!
771 flags &= ~(FILE_CREATE | FILE_WRITE | FILE_APPEND);
772 #endif
773
774 // No write access - remove write/modify flags
775 if (!_fs.disk_io.write_media)
776 flags &= ~(FILE_CREATE | FILE_WRITE | FILE_APPEND);
777
778 FL_LOCK(&_fs);
779
780 // Read
781 if (flags & FILE_READ)
782 file = _open_file(path);
783
784 // Create New
785 #if FATFS_INC_WRITE_SUPPORT
786 if (!file && (flags & FILE_CREATE))
787 file = _create_file(path);
788 #endif
789
790 // Write Existing (and not open due to read or create)
791 if (!(flags & FILE_READ))
792 if ((flags & FILE_CREATE) && !file)
793 if (flags & (FILE_WRITE | FILE_APPEND))
794 file = _open_file(path);
795
796 if (file)
797 file->flags = flags;
798
799 FL_UNLOCK(&_fs);
800 return file;
801 }
802 //-----------------------------------------------------------------------------
803 // _write_sectors: Write sector(s) to disk
804 //-----------------------------------------------------------------------------
805 #if FATFS_INC_WRITE_SUPPORT
806 static uint32 _write_sectors(FL_FILE* file, uint32 offset, uint8 *buf, uint32 count)
807 {
808 uint32 SectorNumber = 0;
809 uint32 ClusterIdx = 0;
810 uint32 Cluster = 0;
811 uint32 LastCluster = FAT32_LAST_CLUSTER;
812 uint32 i;
813 uint32 lba;
814 uint32 TotalWriteCount = count;
815
816 // Find values for Cluster index & sector within cluster
817 ClusterIdx = offset / _fs.sectors_per_cluster;
818 SectorNumber = offset - (ClusterIdx * _fs.sectors_per_cluster);
819
820 // Limit number of sectors written to the number remaining in this cluster
821 if ((SectorNumber + count) > _fs.sectors_per_cluster)
822 count = _fs.sectors_per_cluster - SectorNumber;
823
824 // Quick lookup for next link in the chain
825 if (ClusterIdx == file->last_fat_lookup.ClusterIdx)
826 Cluster = file->last_fat_lookup.CurrentCluster;
827 // Else walk the chain
828 else
829 {
830 // Starting from last recorded cluster?
831 if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1)
832 {
833 i = file->last_fat_lookup.ClusterIdx;
834 Cluster = file->last_fat_lookup.CurrentCluster;
835 }
836 // Start searching from the beginning..
837 else
838 {
839 // Set start of cluster chain to initial value
840 i = 0;
841 Cluster = file->startcluster;
842 }
843
844 // Follow chain to find cluster to read
845 for ( ;i<ClusterIdx; i++)
846 {
847 uint32 nextCluster;
848
849 // Does the entry exist in the cache?
850 if (!fatfs_cache_get_next_cluster(&_fs, file, i, &nextCluster))
851 {
852 // Scan file linked list to find next entry
853 nextCluster = fatfs_find_next_cluster(&_fs, Cluster);
854
855 // Push entry into cache
856 fatfs_cache_set_next_cluster(&_fs, file, i, nextCluster);
857 }
858
859 LastCluster = Cluster;
860 Cluster = nextCluster;
861
862 // Dont keep following a dead end
863 if (Cluster == FAT32_LAST_CLUSTER)
864 break;
865 }
866
867 // If we have reached the end of the chain, allocate more!
868 if (Cluster == FAT32_LAST_CLUSTER)
869 {
870 // Add some more cluster(s) to the last good cluster chain
871 if (!fatfs_add_free_space(&_fs, &LastCluster, (TotalWriteCount + _fs.sectors_per_cluster -1) / _fs.sectors_per_cluster))
872 return 0;
873
874 Cluster = LastCluster;
875 }
876
877 // Record current cluster lookup details
878 file->last_fat_lookup.CurrentCluster = Cluster;
879 file->last_fat_lookup.ClusterIdx = ClusterIdx;
880 }
881
882 // Calculate write address
883 lba = fatfs_lba_of_cluster(&_fs, Cluster) + SectorNumber;
884
885 if (fatfs_sector_write(&_fs, lba, buf, count))
886 return count;
887 else
888 return 0;
889 }
890 #endif
891 //-----------------------------------------------------------------------------
892 // fl_fflush: Flush un-written data to the file
893 //-----------------------------------------------------------------------------
894 int fl_fflush(void *f)
895 {
896 #if FATFS_INC_WRITE_SUPPORT
897 FL_FILE *file = (FL_FILE *)f;
898
899 // If first call to library, initialise
900 CHECK_FL_INIT();
901
902 if (file)
903 {
904 FL_LOCK(&_fs);
905
906 // If some write data still in buffer
907 if (file->file_data_dirty)
908 {
909 // Write back current sector before loading next
910 if (_write_sectors(file, file->file_data_address, file->file_data_sector, 1))
911 file->file_data_dirty = 0;
912 }
913
914 FL_UNLOCK(&_fs);
915 }
916 #endif
917 return 0;
918 }
919 //-----------------------------------------------------------------------------
920 // fl_fclose: Close an open file
921 //-----------------------------------------------------------------------------
922 void fl_fclose(void *f)
923 {
924 FL_FILE *file = (FL_FILE *)f;
925
926 // If first call to library, initialise
927 CHECK_FL_INIT();
928
929 if (file)
930 {
931 FL_LOCK(&_fs);
932
933 // Flush un-written data to file
934 fl_fflush(f);
935
936 // File size changed?
937 if (file->filelength_changed)
938 {
939 #if FATFS_INC_WRITE_SUPPORT
940 // Update filesize in directory
941 fatfs_update_file_length(&_fs, file->parentcluster, (char*)file->shortfilename, file->filelength);
942 #endif
943 file->filelength_changed = 0;
944 }
945
946 file->bytenum = 0;
947 file->filelength = 0;
948 file->startcluster = 0;
949 file->file_data_address = 0xFFFFFFFF;
950 file->file_data_dirty = 0;
951 file->filelength_changed = 0;
952
953 // Free file handle
954 _free_file(file);
955
956 fatfs_fat_purge(&_fs);
957
958 FL_UNLOCK(&_fs);
959 }
960 }
961 //-----------------------------------------------------------------------------
962 // fl_fgetc: Get a character in the stream
963 //-----------------------------------------------------------------------------
964 int fl_fgetc(void *f)
965 {
966 int res;
967 uint8 data = 0;
968
969 res = fl_fread(&data, 1, 1, f);
970 if (res == 1)
971 return (int)data;
972 else
973 return res;
974 }
975 //-----------------------------------------------------------------------------
976 // fl_fgets: Get a string from a stream
977 //-----------------------------------------------------------------------------
978 char *fl_fgets(char *s, int n, void *f)
979 {
980 int idx = 0;
981
982 // Space for null terminator?
983 if (n > 0)
984 {
985 // While space (+space for null terminator)
986 while (idx < (n-1))
987 {
988 int ch = fl_fgetc(f);
989
990 // EOF / Error?
991 if (ch < 0)
992 break;
993
994 // Store character read from stream
995 s[idx++] = (char)ch;
996
997 // End of line?
998 if (ch == '\n')
999 break;
1000 }
1001
1002 if (idx > 0)
1003 s[idx] = '\0';
1004 }
1005
1006 return (idx > 0) ? s : 0;
1007 }
1008 //-----------------------------------------------------------------------------
1009 // fl_fread: Read a block of data from the file
1010 //-----------------------------------------------------------------------------
1011 int fl_fread(void * buffer, int size, int length, void *f )
1012 {
1013 uint32 sector;
1014 uint32 offset;
1015 int copyCount;
1016 int count = size * length;
1017 int bytesRead = 0;
1018
1019 FL_FILE *file = (FL_FILE *)f;
1020
1021 // If first call to library, initialise
1022 CHECK_FL_INIT();
1023
1024 if (buffer==NULL || file==NULL)
1025 return -1;
1026
1027 // No read permissions
1028 if (!(file->flags & FILE_READ))
1029 return -1;
1030
1031 // Nothing to be done
1032 if (!count)
1033 return 0;
1034
1035 // Check if read starts past end of file
1036 if (file->bytenum >= file->filelength)
1037 return -1;
1038
1039 // Limit to file size
1040 if ( (file->bytenum + count) > file->filelength )
1041 count = file->filelength - file->bytenum;
1042
1043 // Calculate start sector
1044 sector = file->bytenum / FAT_SECTOR_SIZE;
1045
1046 // Offset to start copying data from first sector
1047 offset = file->bytenum % FAT_SECTOR_SIZE;
1048
1049 while (bytesRead < count)
1050 {
1051 // Read whole sector, read from media directly into target buffer
1052 if ((offset == 0) && ((count - bytesRead) >= FAT_SECTOR_SIZE))
1053 {
1054 // Read as many sectors as possible into target buffer
1055 uint32 sectorsRead = _read_sectors(file, sector, (uint8*)((uint8*)buffer + bytesRead), (count - bytesRead) / FAT_SECTOR_SIZE);
1056 if (sectorsRead)
1057 {
1058 // We have upto one sector to copy
1059 copyCount = FAT_SECTOR_SIZE * sectorsRead;
1060
1061 // Move onto next sector and reset copy offset
1062 sector+= sectorsRead;
1063 offset = 0;
1064 }
1065 else
1066 break;
1067 }
1068 else
1069 {
1070 // Do we need to re-read the sector?
1071 if (file->file_data_address != sector)
1072 {
1073 // Flush un-written data to file
1074 if (file->file_data_dirty)
1075 fl_fflush(file);
1076
1077 // Get LBA of sector offset within file
1078 if (!_read_sectors(file, sector, file->file_data_sector, 1))
1079 // Read failed - out of range (probably)
1080 break;
1081
1082 file->file_data_address = sector;
1083 file->file_data_dirty = 0;
1084 }
1085
1086 // We have upto one sector to copy
1087 copyCount = FAT_SECTOR_SIZE - offset;
1088
1089 // Only require some of this sector?
1090 if (copyCount > (count - bytesRead))
1091 copyCount = (count - bytesRead);
1092
1093 // Copy to application buffer
1094 memcpy( (uint8*)((uint8*)buffer + bytesRead), (uint8*)(file->file_data_sector + offset), copyCount);
1095
1096 // Move onto next sector and reset copy offset
1097 sector++;
1098 offset = 0;
1099 }
1100
1101 // Increase total read count
1102 bytesRead += copyCount;
1103
1104 // Increment file pointer
1105 file->bytenum += copyCount;
1106 }
1107
1108 return bytesRead;
1109 }
1110 //-----------------------------------------------------------------------------
1111 // fl_fseek: Seek to a specific place in the file
1112 //-----------------------------------------------------------------------------
1113 int fl_fseek( void *f, long offset, int origin )
1114 {
1115 FL_FILE *file = (FL_FILE *)f;
1116 int res = -1;
1117
1118 // If first call to library, initialise
1119 CHECK_FL_INIT();
1120
1121 if (!file)
1122 return -1;
1123
1124 if (origin == SEEK_END && offset != 0)
1125 return -1;
1126
1127 FL_LOCK(&_fs);
1128
1129 // Invalidate file buffer
1130 file->file_data_address = 0xFFFFFFFF;
1131 file->file_data_dirty = 0;
1132
1133 if (origin == SEEK_SET)
1134 {
1135 file->bytenum = (uint32)offset;
1136
1137 if (file->bytenum > file->filelength)
1138 file->bytenum = file->filelength;
1139
1140 res = 0;
1141 }
1142 else if (origin == SEEK_CUR)
1143 {
1144 // Positive shift
1145 if (offset >= 0)
1146 {
1147 file->bytenum += offset;
1148
1149 if (file->bytenum > file->filelength)
1150 file->bytenum = file->filelength;
1151 }
1152 // Negative shift
1153 else
1154 {
1155 // Make shift positive
1156 offset = -offset;
1157
1158 // Limit to negative shift to start of file
1159 if ((uint32)offset > file->bytenum)
1160 file->bytenum = 0;
1161 else
1162 file->bytenum-= offset;
1163 }
1164
1165 res = 0;
1166 }
1167 else if (origin == SEEK_END)
1168 {
1169 file->bytenum = file->filelength;
1170 res = 0;
1171 }
1172 else
1173 res = -1;
1174
1175 FL_UNLOCK(&_fs);
1176
1177 return res;
1178 }
1179 //-----------------------------------------------------------------------------
1180 // fl_fgetpos: Get the current file position
1181 //-----------------------------------------------------------------------------
1182 int fl_fgetpos(void *f , uint32 * position)
1183 {
1184 FL_FILE *file = (FL_FILE *)f;
1185
1186 if (!file)
1187 return -1;
1188
1189 FL_LOCK(&_fs);
1190
1191 // Get position
1192 *position = file->bytenum;
1193
1194 FL_UNLOCK(&_fs);
1195
1196 return 0;
1197 }
1198 //-----------------------------------------------------------------------------
1199 // fl_ftell: Get the current file position
1200 //-----------------------------------------------------------------------------
1201 long fl_ftell(void *f)
1202 {
1203 uint32 pos = 0;
1204
1205 fl_fgetpos(f, &pos);
1206
1207 return (long)pos;
1208 }
1209 //-----------------------------------------------------------------------------
1210 // fl_feof: Is the file pointer at the end of the stream?
1211 //-----------------------------------------------------------------------------
1212 int fl_feof(void *f)
1213 {
1214 FL_FILE *file = (FL_FILE *)f;
1215 int res;
1216
1217 if (!file)
1218 return -1;
1219
1220 FL_LOCK(&_fs);
1221
1222 if (file->bytenum == file->filelength)
1223 res = EOF;
1224 else
1225 res = 0;
1226
1227 FL_UNLOCK(&_fs);
1228
1229 return res;
1230 }
1231 //-----------------------------------------------------------------------------
1232 // fl_fputc: Write a character to the stream
1233 //-----------------------------------------------------------------------------
1234 #if FATFS_INC_WRITE_SUPPORT
1235 int fl_fputc(int c, void *f)
1236 {
1237 uint8 data = (uint8)c;
1238 int res;
1239
1240 res = fl_fwrite(&data, 1, 1, f);
1241 if (res == 1)
1242 return c;
1243 else
1244 return res;
1245 }
1246 #endif
1247 //-----------------------------------------------------------------------------
1248 // fl_fwrite: Write a block of data to the stream
1249 //-----------------------------------------------------------------------------
1250 #if FATFS_INC_WRITE_SUPPORT
1251 int fl_fwrite(const void * data, int size, int count, void *f )
1252 {
1253 FL_FILE *file = (FL_FILE *)f;
1254 uint32 sector;
1255 uint32 offset;
1256 uint32 length = (size*count);
1257 uint8 *buffer = (uint8 *)data;
1258 uint32 bytesWritten = 0;
1259 uint32 copyCount;
1260
1261 // If first call to library, initialise
1262 CHECK_FL_INIT();
1263
1264 if (!file)
1265 return -1;
1266
1267 FL_LOCK(&_fs);
1268
1269 // No write permissions
1270 if (!(file->flags & FILE_WRITE))
1271 {
1272 FL_UNLOCK(&_fs);
1273 return -1;
1274 }
1275
1276 // Append writes to end of file
1277 if (file->flags & FILE_APPEND)
1278 file->bytenum = file->filelength;
1279 // Else write to current position
1280
1281 // Calculate start sector
1282 sector = file->bytenum / FAT_SECTOR_SIZE;
1283
1284 // Offset to start copying data from first sector
1285 offset = file->bytenum % FAT_SECTOR_SIZE;
1286
1287 while (bytesWritten < length)
1288 {
1289 // Whole sector or more to be written?
1290 if ((offset == 0) && ((length - bytesWritten) >= FAT_SECTOR_SIZE))
1291 {
1292 uint32 sectorsWrote;
1293
1294 // Buffered sector, flush back to disk
1295 if (file->file_data_address != 0xFFFFFFFF)
1296 {
1297 // Flush un-written data to file
1298 if (file->file_data_dirty)
1299 fl_fflush(file);
1300
1301 file->file_data_address = 0xFFFFFFFF;
1302 file->file_data_dirty = 0;
1303 }
1304
1305 // Write as many sectors as possible
1306 sectorsWrote = _write_sectors(file, sector, (uint8*)(buffer + bytesWritten), (length - bytesWritten) / FAT_SECTOR_SIZE);
1307 copyCount = FAT_SECTOR_SIZE * sectorsWrote;
1308
1309 // Increase total read count
1310 bytesWritten += copyCount;
1311
1312 // Increment file pointer
1313 file->bytenum += copyCount;
1314
1315 // Move onto next sector and reset copy offset
1316 sector+= sectorsWrote;
1317 offset = 0;
1318
1319 if (!sectorsWrote)
1320 break;
1321 }
1322 else
1323 {
1324 // We have upto one sector to copy
1325 copyCount = FAT_SECTOR_SIZE - offset;
1326
1327 // Only require some of this sector?
1328 if (copyCount > (length - bytesWritten))
1329 copyCount = (length - bytesWritten);
1330
1331 // Do we need to read a new sector?
1332 if (file->file_data_address != sector)
1333 {
1334 // Flush un-written data to file
1335 if (file->file_data_dirty)
1336 fl_fflush(file);
1337
1338 // If we plan to overwrite the whole sector, we don't need to read it first!
1339 if (copyCount != FAT_SECTOR_SIZE)
1340 {
1341 // NOTE: This does not have succeed; if last sector of file
1342 // reached, no valid data will be read in, but write will
1343 // allocate some more space for new data.
1344
1345 // Get LBA of sector offset within file
1346 if (!_read_sectors(file, sector, file->file_data_sector, 1))
1347 memset(file->file_data_sector, 0x00, FAT_SECTOR_SIZE);
1348 }
1349
1350 file->file_data_address = sector;
1351 file->file_data_dirty = 0;
1352 }
1353
1354 // Copy from application buffer into sector buffer
1355 memcpy((uint8*)(file->file_data_sector + offset), (uint8*)(buffer + bytesWritten), copyCount);
1356
1357 // Mark buffer as dirty
1358 file->file_data_dirty = 1;
1359
1360 // Increase total read count
1361 bytesWritten += copyCount;
1362
1363 // Increment file pointer
1364 file->bytenum += copyCount;
1365
1366 // Move onto next sector and reset copy offset
1367 sector++;
1368 offset = 0;
1369 }
1370 }
1371
1372 // Write increased extent of the file?
1373 if (file->bytenum > file->filelength)
1374 {
1375 // Increase file size to new point
1376 file->filelength = file->bytenum;
1377
1378 // We are changing the file length and this
1379 // will need to be writen back at some point
1380 file->filelength_changed = 1;
1381 }
1382
1383 #if FATFS_INC_TIME_DATE_SUPPORT
1384 // If time & date support is enabled, always force directory entry to be
1385 // written in-order to update file modify / access time & date.
1386 file->filelength_changed = 1;
1387 #endif
1388
1389 FL_UNLOCK(&_fs);
1390
1391 return (size*count);
1392 }
1393 #endif
1394 //-----------------------------------------------------------------------------
1395 // fl_fputs: Write a character string to the stream
1396 //-----------------------------------------------------------------------------
1397 #if FATFS_INC_WRITE_SUPPORT
1398 int fl_fputs(const char * str, void *f)
1399 {
1400 int len = (int)strlen(str);
1401 int res = fl_fwrite(str, 1, len, f);
1402
1403 if (res == len)
1404 return len;
1405 else
1406 return res;
1407 }
1408 #endif
1409 //-----------------------------------------------------------------------------
1410 // fl_remove: Remove a file from the filesystem
1411 //-----------------------------------------------------------------------------
1412 #if FATFS_INC_WRITE_SUPPORT
1413 int fl_remove( const char * filename )
1414 {
1415 FL_FILE* file;
1416 int res = -1;
1417
1418 FL_LOCK(&_fs);
1419
1420 // Use read_file as this will check if the file is already open!
1421 file = fl_fopen((char*)filename, "r");
1422 if (file)
1423 {
1424 // Delete allocated space
1425 if (fatfs_free_cluster_chain(&_fs, file->startcluster))
1426 {
1427 // Remove directory entries
1428 if (fatfs_mark_file_deleted(&_fs, file->parentcluster, (char*)file->shortfilename))
1429 {
1430 // Close the file handle (this should not write anything to the file
1431 // as we have not changed the file since opening it!)
1432 fl_fclose(file);
1433
1434 res = 0;
1435 }
1436 }
1437 }
1438
1439 FL_UNLOCK(&_fs);
1440
1441 return res;
1442 }
1443 #endif
1444 //-----------------------------------------------------------------------------
1445 // fl_createdirectory: Create a directory based on a path
1446 //-----------------------------------------------------------------------------
1447 #if FATFS_INC_WRITE_SUPPORT
1448 int fl_createdirectory(const char *path)
1449 {
1450 int res;
1451
1452 // If first call to library, initialise
1453 CHECK_FL_INIT();
1454
1455 FL_LOCK(&_fs);
1456 res =_create_directory((char*)path);
1457 FL_UNLOCK(&_fs);
1458
1459 return res;
1460 }
1461 #endif
1462 //-----------------------------------------------------------------------------
1463 // fl_listdirectory: List a directory based on a path
1464 //-----------------------------------------------------------------------------
1465 #if FATFS_DIR_LIST_SUPPORT
1466 void fl_listdirectory(const char *path)
1467 {
1468 FL_DIR dirstat;
1469
1470 // If first call to library, initialise
1471 CHECK_FL_INIT();
1472
1473 FL_LOCK(&_fs);
1474
1475 FAT_PRINTF(("\r\nDirectory %s\r\n", path));
1476
1477 if (fl_opendir(path, &dirstat))
1478 {
1479 struct fs_dir_ent dirent;
1480
1481 while (fl_readdir(&dirstat, &dirent) == 0)
1482 {
1483 #if FATFS_INC_TIME_DATE_SUPPORT
1484 int d,m,y,h,mn,s;
1485 fatfs_convert_from_fat_time(dirent.write_time, &h,&m,&s);
1486 fatfs_convert_from_fat_date(dirent.write_date, &d,&mn,&y);
1487 FAT_PRINTF(("%02d/%02d/%04d %02d:%02d ", d,mn,y,h,m));
1488 #endif
1489
1490 if (dirent.is_dir)
1491 {
1492 FAT_PRINTF(("%s <DIR>\r\n", dirent.filename));
1493 }
1494 else
1495 {
1496 FAT_PRINTF(("%s [%d bytes]\r\n", dirent.filename, dirent.size));
1497 }
1498 }
1499
1500 fl_closedir(&dirstat);
1501 }
1502
1503 FL_UNLOCK(&_fs);
1504 }
1505 #endif
1506 //-----------------------------------------------------------------------------
1507 // fl_opendir: Opens a directory for listing
1508 //-----------------------------------------------------------------------------
1509 #if FATFS_DIR_LIST_SUPPORT
1510 FL_DIR* fl_opendir(const char* path, FL_DIR *dir)
1511 {
1512 int levels;
1513 int res = 1;
1514 uint32 cluster = FAT32_INVALID_CLUSTER;
1515
1516 // If first call to library, initialise
1517 CHECK_FL_INIT();
1518
1519 FL_LOCK(&_fs);
1520
1521 levels = fatfs_total_path_levels((char*)path) + 1;
1522
1523 // If path is in the root dir
1524 if (levels == 0)
1525 cluster = fatfs_get_root_cluster(&_fs);
1526 // Find parent directory start cluster
1527 else
1528 res = _open_directory((char*)path, &cluster);
1529
1530 if (res)
1531 fatfs_list_directory_start(&_fs, dir, cluster);
1532
1533 FL_UNLOCK(&_fs);
1534
1535 return cluster != FAT32_INVALID_CLUSTER ? dir : 0;
1536 }
1537 #endif
1538 //-----------------------------------------------------------------------------
1539 // fl_readdir: Get next item in directory
1540 //-----------------------------------------------------------------------------
1541 #if FATFS_DIR_LIST_SUPPORT
1542 int fl_readdir(FL_DIR *dirls, fl_dirent *entry)
1543 {
1544 int res = 0;
1545
1546 // If first call to library, initialise
1547 CHECK_FL_INIT();
1548
1549 FL_LOCK(&_fs);
1550
1551 res = fatfs_list_directory_next(&_fs, dirls, entry);
1552
1553 FL_UNLOCK(&_fs);
1554
1555 return res ? 0 : -1;
1556 }
1557 #endif
1558 //-----------------------------------------------------------------------------
1559 // fl_closedir: Close directory after listing
1560 //-----------------------------------------------------------------------------
1561 #if FATFS_DIR_LIST_SUPPORT
1562 int fl_closedir(FL_DIR* dir)
1563 {
1564 // Not used
1565 return 0;
1566 }
1567 #endif
1568 //-----------------------------------------------------------------------------
1569 // fl_is_dir: Is this a directory?
1570 //-----------------------------------------------------------------------------
1571 #if FATFS_DIR_LIST_SUPPORT
1572 int fl_is_dir(const char *path)
1573 {
1574 int res = 0;
1575 FL_DIR dir;
1576
1577 if (fl_opendir(path, &dir))
1578 {
1579 res = 1;
1580 fl_closedir(&dir);
1581 }
1582
1583 return res;
1584 }
1585 #endif
1586 //-----------------------------------------------------------------------------
1587 // fl_format: Format a partition with either FAT16 or FAT32 based on size
1588 //-----------------------------------------------------------------------------
1589 #if FATFS_INC_FORMAT_SUPPORT
1590 int fl_format(uint32 volume_sectors, const char *name)
1591 {
1592 return fatfs_format(&_fs, volume_sectors, name);
1593 }
1594 #endif /*FATFS_INC_FORMAT_SUPPORT*/
1595 //-----------------------------------------------------------------------------
1596 // fl_get_fs:
1597 //-----------------------------------------------------------------------------
1598 #ifdef FATFS_INC_TEST_HOOKS
1599 struct fatfs* fl_get_fs(void)
1600 {
1601 return &_fs;
1602 }
1603 #endif