fat: use uart from aversive
[protos/imu.git] / fat.c
1
2 /*
3  * Copyright (c) 2006-2012 by Roland Riegel <feedback@roland-riegel.de>
4  *
5  * This file is free software; you can redistribute it and/or modify
6  * it under the terms of either the GNU General Public License version 2
7  * or the GNU Lesser General Public License version 2.1, both as
8  * published by the Free Software Foundation.
9  */
10
11 #include "byteordering.h"
12 #include "partition.h"
13 #include "fat.h"
14 #include "fat_config.h"
15 #include "sd-reader_config.h"
16
17 #include <string.h>
18
19 #if USE_DYNAMIC_MEMORY
20     #include <stdlib.h>
21 #endif
22
23 /**
24  * \addtogroup fat FAT support
25  *
26  * This module implements FAT16/FAT32 read and write access.
27  *
28  * The following features are supported:
29  * - File names up to 31 characters long.
30  * - Unlimited depth of subdirectories.
31  * - Short 8.3 and long filenames.
32  * - Creating and deleting files.
33  * - Reading and writing from and to files.
34  * - File resizing.
35  * - File sizes of up to 4 gigabytes.
36  *
37  * @{
38  */
39 /**
40  * \file
41  * FAT implementation (license: GPLv2 or LGPLv2.1)
42  *
43  * \author Roland Riegel
44  */
45
46 /**
47  * \addtogroup fat_config FAT configuration
48  * Preprocessor defines to configure the FAT implementation.
49  */
50
51 /**
52  * \addtogroup fat_fs FAT access
53  * Basic functions for handling a FAT filesystem.
54  */
55
56 /**
57  * \addtogroup fat_file FAT file functions
58  * Functions for managing files.
59  */
60
61 /**
62  * \addtogroup fat_dir FAT directory functions
63  * Functions for managing directories.
64  */
65
66 /**
67  * @}
68  */
69
70 #define FAT16_CLUSTER_FREE 0x0000
71 #define FAT16_CLUSTER_RESERVED_MIN 0xfff0
72 #define FAT16_CLUSTER_RESERVED_MAX 0xfff6
73 #define FAT16_CLUSTER_BAD 0xfff7
74 #define FAT16_CLUSTER_LAST_MIN 0xfff8
75 #define FAT16_CLUSTER_LAST_MAX 0xffff
76
77 #define FAT32_CLUSTER_FREE 0x00000000
78 #define FAT32_CLUSTER_RESERVED_MIN 0x0ffffff0
79 #define FAT32_CLUSTER_RESERVED_MAX 0x0ffffff6
80 #define FAT32_CLUSTER_BAD 0x0ffffff7
81 #define FAT32_CLUSTER_LAST_MIN 0x0ffffff8
82 #define FAT32_CLUSTER_LAST_MAX 0x0fffffff
83
84 #define FAT_DIRENTRY_DELETED 0xe5
85 #define FAT_DIRENTRY_LFNLAST (1 << 6)
86 #define FAT_DIRENTRY_LFNSEQMASK ((1 << 6) - 1)
87
88 /* Each entry within the directory table has a size of 32 bytes
89  * and either contains a 8.3 DOS-style file name or a part of a
90  * long file name, which may consist of several directory table
91  * entries at once.
92  *
93  * multi-byte integer values are stored little-endian!
94  *
95  * 8.3 file name entry:
96  * ====================
97  * offset  length  description
98  *      0       8  name (space padded)
99  *      8       3  extension (space padded)
100  *     11       1  attributes (FAT_ATTRIB_*)
101  *
102  * long file name (lfn) entry ordering for a single file name:
103  * ===========================================================
104  * LFN entry n
105  *     ...
106  * LFN entry 2
107  * LFN entry 1
108  * 8.3 entry (see above)
109  *
110  * lfn entry:
111  * ==========
112  * offset  length  description
113  *      0       1  ordinal field
114  *      1       2  unicode character 1
115  *      3       3  unicode character 2
116  *      5       3  unicode character 3
117  *      7       3  unicode character 4
118  *      9       3  unicode character 5
119  *     11       1  attribute (always 0x0f)
120  *     12       1  type (reserved, always 0)
121  *     13       1  checksum
122  *     14       2  unicode character 6
123  *     16       2  unicode character 7
124  *     18       2  unicode character 8
125  *     20       2  unicode character 9
126  *     22       2  unicode character 10
127  *     24       2  unicode character 11
128  *     26       2  cluster (unused, always 0)
129  *     28       2  unicode character 12
130  *     30       2  unicode character 13
131  *
132  * The ordinal field contains a descending number, from n to 1.
133  * For the n'th lfn entry the ordinal field is or'ed with 0x40.
134  * For deleted lfn entries, the ordinal field is set to 0xe5.
135  */
136
137 struct fat_header_struct
138 {
139     offset_t size;
140
141     offset_t fat_offset;
142     uint32_t fat_size;
143
144     uint16_t sector_size;
145     uint16_t cluster_size;
146
147     offset_t cluster_zero_offset;
148
149     offset_t root_dir_offset;
150 #if FAT_FAT32_SUPPORT
151     cluster_t root_dir_cluster;
152 #endif
153 };
154
155 struct fat_fs_struct
156 {
157     struct partition_struct* partition;
158     struct fat_header_struct header;
159     cluster_t cluster_free;
160 };
161
162 struct fat_file_struct
163 {
164     struct fat_fs_struct* fs;
165     struct fat_dir_entry_struct dir_entry;
166     offset_t pos;
167     cluster_t pos_cluster;
168 };
169
170 struct fat_dir_struct
171 {
172     struct fat_fs_struct* fs;
173     struct fat_dir_entry_struct dir_entry;
174     cluster_t entry_cluster;
175     uint16_t entry_offset;
176 };
177
178 struct fat_read_dir_callback_arg
179 {
180     struct fat_dir_entry_struct* dir_entry;
181     uintptr_t bytes_read;
182 #if FAT_LFN_SUPPORT
183     uint8_t checksum;
184 #endif
185     uint8_t finished;
186 };
187
188 struct fat_usage_count_callback_arg
189 {
190     cluster_t cluster_count;
191     uintptr_t buffer_size;
192 };
193
194 #if !USE_DYNAMIC_MEMORY
195 static struct fat_fs_struct fat_fs_handles[FAT_FS_COUNT];
196 static struct fat_file_struct fat_file_handles[FAT_FILE_COUNT];
197 static struct fat_dir_struct fat_dir_handles[FAT_DIR_COUNT];
198 #endif
199
200 static uint8_t fat_read_header(struct fat_fs_struct* fs);
201 static cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num);
202 static offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num);
203 static uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p);
204 #if FAT_LFN_SUPPORT
205 static uint8_t fat_calc_83_checksum(const uint8_t* file_name_83);
206 #endif
207
208 static uint8_t fat_get_fs_free_16_callback(uint8_t* buffer, offset_t offset, void* p);
209 #if FAT_FAT32_SUPPORT
210 static uint8_t fat_get_fs_free_32_callback(uint8_t* buffer, offset_t offset, void* p);
211 #endif
212
213 #if FAT_WRITE_SUPPORT
214 static cluster_t fat_append_clusters(struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count);
215 static uint8_t fat_free_clusters(struct fat_fs_struct* fs, cluster_t cluster_num);
216 static uint8_t fat_terminate_clusters(struct fat_fs_struct* fs, cluster_t cluster_num);
217 static uint8_t fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num);
218 static uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p);
219 static offset_t fat_find_offset_for_dir_entry(struct fat_fs_struct* fs, const struct fat_dir_struct* parent, const struct fat_dir_entry_struct* dir_entry);
220 static uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry);
221 #if FAT_DATETIME_SUPPORT
222 static void fat_set_file_modification_date(struct fat_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day);
223 static void fat_set_file_modification_time(struct fat_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec);
224 #endif
225 #endif
226
227 /**
228  * \ingroup fat_fs
229  * Opens a FAT filesystem.
230  *
231  * \param[in] partition Discriptor of partition on which the filesystem resides.
232  * \returns 0 on error, a FAT filesystem descriptor on success.
233  * \see fat_close
234  */
235 struct fat_fs_struct* fat_open(struct partition_struct* partition)
236 {
237     if(!partition ||
238 #if FAT_WRITE_SUPPORT
239        !partition->device_write ||
240        !partition->device_write_interval
241 #else
242        0
243 #endif
244       )
245         return 0;
246
247 #if USE_DYNAMIC_MEMORY
248     struct fat_fs_struct* fs = malloc(sizeof(*fs));
249     if(!fs)
250         return 0;
251 #else
252     struct fat_fs_struct* fs = fat_fs_handles;
253     uint8_t i;
254     for(i = 0; i < FAT_FS_COUNT; ++i)
255     {
256         if(!fs->partition)
257             break;
258
259         ++fs;
260     }
261     if(i >= FAT_FS_COUNT)
262         return 0;
263 #endif
264
265     memset(fs, 0, sizeof(*fs));
266
267     fs->partition = partition;
268     if(!fat_read_header(fs))
269     {
270 #if USE_DYNAMIC_MEMORY
271         free(fs);
272 #else
273         fs->partition = 0;
274 #endif
275         return 0;
276     }
277
278     return fs;
279 }
280
281 /**
282  * \ingroup fat_fs
283  * Closes a FAT filesystem.
284  *
285  * When this function returns, the given filesystem descriptor
286  * will be invalid.
287  *
288  * \param[in] fs The filesystem to close.
289  * \see fat_open
290  */
291 void fat_close(struct fat_fs_struct* fs)
292 {
293     if(!fs)
294         return;
295
296 #if USE_DYNAMIC_MEMORY
297     free(fs);
298 #else
299     fs->partition = 0;
300 #endif
301 }
302
303 /**
304  * \ingroup fat_fs
305  * Reads and parses the header of a FAT filesystem.
306  *
307  * \param[in,out] fs The filesystem for which to parse the header.
308  * \returns 0 on failure, 1 on success.
309  */
310 uint8_t fat_read_header(struct fat_fs_struct* fs)
311 {
312     if(!fs)
313         return 0;
314
315     struct partition_struct* partition = fs->partition;
316     if(!partition)
317         return 0;
318
319     /* read fat parameters */
320 #if FAT_FAT32_SUPPORT
321     uint8_t buffer[37];
322 #else
323     uint8_t buffer[25];
324 #endif
325     offset_t partition_offset = (offset_t) partition->offset * 512;
326     if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer)))
327         return 0;
328
329     uint16_t bytes_per_sector = read16(&buffer[0x00]);
330     uint16_t reserved_sectors = read16(&buffer[0x03]);
331     uint8_t sectors_per_cluster = buffer[0x02];
332     uint8_t fat_copies = buffer[0x05];
333     uint16_t max_root_entries = read16(&buffer[0x06]);
334     uint16_t sector_count_16 = read16(&buffer[0x08]);
335     uint16_t sectors_per_fat = read16(&buffer[0x0b]);
336     uint32_t sector_count = read32(&buffer[0x15]);
337 #if FAT_FAT32_SUPPORT
338     uint32_t sectors_per_fat32 = read32(&buffer[0x19]);
339     uint32_t cluster_root_dir = read32(&buffer[0x21]);
340 #endif
341
342     if(sector_count == 0)
343     {
344         if(sector_count_16 == 0)
345             /* illegal volume size */
346             return 0;
347         else
348             sector_count = sector_count_16;
349     }
350 #if FAT_FAT32_SUPPORT
351     if(sectors_per_fat != 0)
352         sectors_per_fat32 = sectors_per_fat;
353     else if(sectors_per_fat32 == 0)
354         /* this is neither FAT16 nor FAT32 */
355         return 0;
356 #else
357     if(sectors_per_fat == 0)
358         /* this is not a FAT16 */
359         return 0;
360 #endif
361
362     /* determine the type of FAT we have here */
363     uint32_t data_sector_count = sector_count
364                                  - reserved_sectors
365 #if FAT_FAT32_SUPPORT
366                                  - sectors_per_fat32 * fat_copies
367 #else
368                                  - (uint32_t) sectors_per_fat * fat_copies
369 #endif
370                                  - ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector);
371     uint32_t data_cluster_count = data_sector_count / sectors_per_cluster;
372     if(data_cluster_count < 4085)
373         /* this is a FAT12, not supported */
374         return 0;
375     else if(data_cluster_count < 65525)
376         /* this is a FAT16 */
377         partition->type = PARTITION_TYPE_FAT16;
378     else
379         /* this is a FAT32 */
380         partition->type = PARTITION_TYPE_FAT32;
381
382     /* fill header information */
383     struct fat_header_struct* header = &fs->header;
384     memset(header, 0, sizeof(*header));
385
386     header->size = (offset_t) sector_count * bytes_per_sector;
387
388     header->fat_offset = /* jump to partition */
389                          partition_offset +
390                          /* jump to fat */
391                          (offset_t) reserved_sectors * bytes_per_sector;
392     header->fat_size = (data_cluster_count + 2) * (partition->type == PARTITION_TYPE_FAT16 ? 2 : 4);
393
394     header->sector_size = bytes_per_sector;
395     header->cluster_size = (uint16_t) bytes_per_sector * sectors_per_cluster;
396
397 #if FAT_FAT32_SUPPORT
398     if(partition->type == PARTITION_TYPE_FAT16)
399 #endif
400     {
401         header->root_dir_offset = /* jump to fats */
402                                   header->fat_offset +
403                                   /* jump to root directory entries */
404                                   (offset_t) fat_copies * sectors_per_fat * bytes_per_sector;
405
406         header->cluster_zero_offset = /* jump to root directory entries */
407                                       header->root_dir_offset +
408                                       /* skip root directory entries */
409                                       (offset_t) max_root_entries * 32;
410     }
411 #if FAT_FAT32_SUPPORT
412     else
413     {
414         header->cluster_zero_offset = /* jump to fats */
415                                       header->fat_offset +
416                                       /* skip fats */
417                                       (offset_t) fat_copies * sectors_per_fat32 * bytes_per_sector;
418
419         header->root_dir_cluster = cluster_root_dir;
420     }
421 #endif
422
423     return 1;
424 }
425
426 /**
427  * \ingroup fat_fs
428  * Retrieves the next following cluster of a given cluster.
429  *
430  * Using the filesystem file allocation table, this function returns
431  * the number of the cluster containing the data directly following
432  * the data within the cluster with the given number.
433  *
434  * \param[in] fs The filesystem for which to determine the next cluster.
435  * \param[in] cluster_num The number of the cluster for which to determine its successor.
436  * \returns The wanted cluster number, or 0 on error.
437  */
438 cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num)
439 {
440     if(!fs || cluster_num < 2)
441         return 0;
442
443 #if FAT_FAT32_SUPPORT
444     if(fs->partition->type == PARTITION_TYPE_FAT32)
445     {
446         /* read appropriate fat entry */
447         uint32_t fat_entry;
448         if(!fs->partition->device_read(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
449             return 0;
450
451         /* determine next cluster from fat */
452         cluster_num = ltoh32(fat_entry);
453
454         if(cluster_num == FAT32_CLUSTER_FREE ||
455            cluster_num == FAT32_CLUSTER_BAD ||
456            (cluster_num >= FAT32_CLUSTER_RESERVED_MIN && cluster_num <= FAT32_CLUSTER_RESERVED_MAX) ||
457            (cluster_num >= FAT32_CLUSTER_LAST_MIN && cluster_num <= FAT32_CLUSTER_LAST_MAX))
458             return 0;
459     }
460     else
461 #endif
462     {
463         /* read appropriate fat entry */
464         uint16_t fat_entry;
465         if(!fs->partition->device_read(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
466             return 0;
467
468         /* determine next cluster from fat */
469         cluster_num = ltoh16(fat_entry);
470
471         if(cluster_num == FAT16_CLUSTER_FREE ||
472            cluster_num == FAT16_CLUSTER_BAD ||
473            (cluster_num >= FAT16_CLUSTER_RESERVED_MIN && cluster_num <= FAT16_CLUSTER_RESERVED_MAX) ||
474            (cluster_num >= FAT16_CLUSTER_LAST_MIN && cluster_num <= FAT16_CLUSTER_LAST_MAX))
475             return 0;
476     }
477
478     return cluster_num;
479 }
480
481 #if DOXYGEN || FAT_WRITE_SUPPORT
482 /**
483  * \ingroup fat_fs
484  * Appends a new cluster chain to an existing one.
485  *
486  * Set cluster_num to zero to create a completely new one.
487  *
488  * \param[in] fs The file system on which to operate.
489  * \param[in] cluster_num The cluster to which to append the new chain.
490  * \param[in] count The number of clusters to allocate.
491  * \returns 0 on failure, the number of the first new cluster on success.
492  */
493 cluster_t fat_append_clusters(struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count)
494 {
495     if(!fs)
496         return 0;
497
498     device_read_t device_read = fs->partition->device_read;
499     device_write_t device_write = fs->partition->device_write;
500     offset_t fat_offset = fs->header.fat_offset;
501     cluster_t count_left = count;
502     cluster_t cluster_current = fs->cluster_free;
503     cluster_t cluster_next = 0;
504     cluster_t cluster_count;
505     uint16_t fat_entry16;
506 #if FAT_FAT32_SUPPORT
507     uint32_t fat_entry32;
508     uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32);
509
510     if(is_fat32)
511         cluster_count = fs->header.fat_size / sizeof(fat_entry32);
512     else
513 #endif
514         cluster_count = fs->header.fat_size / sizeof(fat_entry16);
515
516     fs->cluster_free = 0;
517     for(cluster_t cluster_left = cluster_count; cluster_left > 0; --cluster_left, ++cluster_current)
518     {
519         if(cluster_current < 2 || cluster_current >= cluster_count)
520             cluster_current = 2;
521
522 #if FAT_FAT32_SUPPORT
523         if(is_fat32)
524         {
525             if(!device_read(fat_offset + (offset_t) cluster_current * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32)))
526                 return 0;
527         }
528         else
529 #endif
530         {
531             if(!device_read(fat_offset + (offset_t) cluster_current * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16)))
532                 return 0;
533         }
534
535 #if FAT_FAT32_SUPPORT
536         if(is_fat32)
537         {
538             /* check if this is a free cluster */
539             if(fat_entry32 != HTOL32(FAT32_CLUSTER_FREE))
540                 continue;
541
542             /* If we don't need this free cluster for the
543              * current allocation, we keep it in mind for
544              * the next time.
545              */
546             if(count_left == 0)
547             {
548                 fs->cluster_free = cluster_current;
549                 break;
550             }
551
552             /* allocate cluster */
553             if(cluster_next == 0)
554                 fat_entry32 = HTOL32(FAT32_CLUSTER_LAST_MAX);
555             else
556                 fat_entry32 = htol32(cluster_next);
557
558             if(!device_write(fat_offset + (offset_t) cluster_current * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32)))
559                 break;
560         }
561         else
562 #endif
563         {
564             /* check if this is a free cluster */
565             if(fat_entry16 != HTOL16(FAT16_CLUSTER_FREE))
566                 continue;
567
568             /* If we don't need this free cluster for the
569              * current allocation, we keep it in mind for
570              * the next time.
571              */
572             if(count_left == 0)
573             {
574                 fs->cluster_free = cluster_current;
575                 break;
576             }
577
578             /* allocate cluster */
579             if(cluster_next == 0)
580                 fat_entry16 = HTOL16(FAT16_CLUSTER_LAST_MAX);
581             else
582                 fat_entry16 = htol16((uint16_t) cluster_next);
583
584             if(!device_write(fat_offset + (offset_t) cluster_current * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16)))
585                 break;
586         }
587
588         cluster_next = cluster_current;
589         --count_left;
590     }
591
592     do
593     {
594         if(count_left > 0)
595             break;
596
597         /* We allocated a new cluster chain. Now join
598          * it with the existing one (if any).
599          */
600         if(cluster_num >= 2)
601         {
602 #if FAT_FAT32_SUPPORT
603             if(is_fat32)
604             {
605                 fat_entry32 = htol32(cluster_next);
606
607                 if(!device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32)))
608                     break;
609             }
610             else
611 #endif
612             {
613                 fat_entry16 = htol16((uint16_t) cluster_next);
614
615                 if(!device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16)))
616                     break;
617             }
618         }
619
620         return cluster_next;
621
622     } while(0);
623
624     /* No space left on device or writing error.
625      * Free up all clusters already allocated.
626      */
627     fat_free_clusters(fs, cluster_next);
628
629     return 0;
630 }
631 #endif
632
633 #if DOXYGEN || FAT_WRITE_SUPPORT
634 /**
635  * \ingroup fat_fs
636  * Frees a cluster chain, or a part thereof.
637  *
638  * Marks the specified cluster and all clusters which are sequentially
639  * referenced by it as free. They may then be used again for future
640  * file allocations.
641  *
642  * \note If this function is used for freeing just a part of a cluster
643  *       chain, the new end of the chain is not correctly terminated
644  *       within the FAT. Use fat_terminate_clusters() instead.
645  *
646  * \param[in] fs The filesystem on which to operate.
647  * \param[in] cluster_num The starting cluster of the chain which to free.
648  * \returns 0 on failure, 1 on success.
649  * \see fat_terminate_clusters
650  */
651 uint8_t fat_free_clusters(struct fat_fs_struct* fs, cluster_t cluster_num)
652 {
653     if(!fs || cluster_num < 2)
654         return 0;
655
656     offset_t fat_offset = fs->header.fat_offset;
657 #if FAT_FAT32_SUPPORT
658     if(fs->partition->type == PARTITION_TYPE_FAT32)
659     {
660         uint32_t fat_entry;
661         while(cluster_num)
662         {
663             if(!fs->partition->device_read(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
664                 return 0;
665
666             /* get next cluster of current cluster before freeing current cluster */
667             uint32_t cluster_num_next = ltoh32(fat_entry);
668
669             if(cluster_num_next == FAT32_CLUSTER_FREE)
670                 return 1;
671             if(cluster_num_next == FAT32_CLUSTER_BAD ||
672                (cluster_num_next >= FAT32_CLUSTER_RESERVED_MIN &&
673                 cluster_num_next <= FAT32_CLUSTER_RESERVED_MAX
674                )
675               )
676                 return 0;
677             if(cluster_num_next >= FAT32_CLUSTER_LAST_MIN && cluster_num_next <= FAT32_CLUSTER_LAST_MAX)
678                 cluster_num_next = 0;
679
680             /* We know we will free the cluster, so remember it as
681              * free for the next allocation.
682              */
683             if(!fs->cluster_free)
684                 fs->cluster_free = cluster_num;
685
686             /* free cluster */
687             fat_entry = HTOL32(FAT32_CLUSTER_FREE);
688             fs->partition->device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry));
689
690             /* We continue in any case here, even if freeing the cluster failed.
691              * The cluster is lost, but maybe we can still free up some later ones.
692              */
693
694             cluster_num = cluster_num_next;
695         }
696     }
697     else
698 #endif
699     {
700         uint16_t fat_entry;
701         while(cluster_num)
702         {
703             if(!fs->partition->device_read(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
704                 return 0;
705
706             /* get next cluster of current cluster before freeing current cluster */
707             uint16_t cluster_num_next = ltoh16(fat_entry);
708
709             if(cluster_num_next == FAT16_CLUSTER_FREE)
710                 return 1;
711             if(cluster_num_next == FAT16_CLUSTER_BAD ||
712                (cluster_num_next >= FAT16_CLUSTER_RESERVED_MIN &&
713                 cluster_num_next <= FAT16_CLUSTER_RESERVED_MAX
714                )
715               )
716                 return 0;
717             if(cluster_num_next >= FAT16_CLUSTER_LAST_MIN && cluster_num_next <= FAT16_CLUSTER_LAST_MAX)
718                 cluster_num_next = 0;
719
720             /* free cluster */
721             fat_entry = HTOL16(FAT16_CLUSTER_FREE);
722             fs->partition->device_write(fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry));
723
724             /* We continue in any case here, even if freeing the cluster failed.
725              * The cluster is lost, but maybe we can still free up some later ones.
726              */
727
728             cluster_num = cluster_num_next;
729         }
730     }
731
732     return 1;
733 }
734 #endif
735
736 #if DOXYGEN || FAT_WRITE_SUPPORT
737 /**
738  * \ingroup fat_fs
739  * Frees a part of a cluster chain and correctly terminates the rest.
740  *
741  * Marks the specified cluster as the new end of a cluster chain and
742  * frees all following clusters.
743  *
744  * \param[in] fs The filesystem on which to operate.
745  * \param[in] cluster_num The new end of the cluster chain.
746  * \returns 0 on failure, 1 on success.
747  * \see fat_free_clusters
748  */
749 uint8_t fat_terminate_clusters(struct fat_fs_struct* fs, cluster_t cluster_num)
750 {
751     if(!fs || cluster_num < 2)
752         return 0;
753
754     /* fetch next cluster before overwriting the cluster entry */
755     cluster_t cluster_num_next = fat_get_next_cluster(fs, cluster_num);
756
757     /* mark cluster as the last one */
758 #if FAT_FAT32_SUPPORT
759     if(fs->partition->type == PARTITION_TYPE_FAT32)
760     {
761         uint32_t fat_entry = HTOL32(FAT32_CLUSTER_LAST_MAX);
762         if(!fs->partition->device_write(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
763             return 0;
764     }
765     else
766 #endif
767     {
768         uint16_t fat_entry = HTOL16(FAT16_CLUSTER_LAST_MAX);
769         if(!fs->partition->device_write(fs->header.fat_offset + (offset_t) cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)))
770             return 0;
771     }
772
773     /* free remaining clusters */
774     if(cluster_num_next)
775         return fat_free_clusters(fs, cluster_num_next);
776     else
777         return 1;
778 }
779 #endif
780
781 #if DOXYGEN || FAT_WRITE_SUPPORT
782 /**
783  * \ingroup fat_fs
784  * Clears a single cluster.
785  *
786  * The complete cluster is filled with zeros.
787  *
788  * \param[in] fs The filesystem on which to operate.
789  * \param[in] cluster_num The cluster to clear.
790  * \returns 0 on failure, 1 on success.
791  */
792 uint8_t fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num)
793 {
794     if(cluster_num < 2)
795         return 0;
796
797     offset_t cluster_offset = fat_cluster_offset(fs, cluster_num);
798
799     uint8_t zero[16];
800     memset(zero, 0, sizeof(zero));
801     return fs->partition->device_write_interval(cluster_offset,
802                                                 zero,
803                                                 fs->header.cluster_size,
804                                                 fat_clear_cluster_callback,
805                                                 0
806                                                );
807 }
808 #endif
809
810 #if DOXYGEN || FAT_WRITE_SUPPORT
811 /**
812  * \ingroup fat_fs
813  * Callback function for clearing a cluster.
814  */
815 uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p)
816 {
817         (void)buffer;
818         (void)offset;
819         (void)p;
820     return 16;
821 }
822 #endif
823
824 /**
825  * \ingroup fat_fs
826  * Calculates the offset of the specified cluster.
827  *
828  * \param[in] fs The filesystem on which to operate.
829  * \param[in] cluster_num The cluster whose offset to calculate.
830  * \returns The cluster offset.
831  */
832 offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num)
833 {
834     if(!fs || cluster_num < 2)
835         return 0;
836
837     return fs->header.cluster_zero_offset + (offset_t) (cluster_num - 2) * fs->header.cluster_size;
838 }
839
840 /**
841  * \ingroup fat_file
842  * Retrieves the directory entry of a path.
843  *
844  * The given path may both describe a file or a directory.
845  *
846  * \param[in] fs The FAT filesystem on which to search.
847  * \param[in] path The path of which to read the directory entry.
848  * \param[out] dir_entry The directory entry to fill.
849  * \returns 0 on failure, 1 on success.
850  * \see fat_read_dir
851  */
852 uint8_t fat_get_dir_entry_of_path(struct fat_fs_struct* fs, const char* path, struct fat_dir_entry_struct* dir_entry)
853 {
854     if(!fs || !path || path[0] == '\0' || !dir_entry)
855         return 0;
856
857     if(path[0] == '/')
858         ++path;
859
860     /* begin with the root directory */
861     memset(dir_entry, 0, sizeof(*dir_entry));
862     dir_entry->attributes = FAT_ATTRIB_DIR;
863
864     while(1)
865     {
866         if(path[0] == '\0')
867             return 1;
868
869         struct fat_dir_struct* dd = fat_open_dir(fs, dir_entry);
870         if(!dd)
871             break;
872
873         /* extract the next hierarchy we will search for */
874         const char* sub_path = strchr(path, '/');
875         uint8_t length_to_sep;
876         if(sub_path)
877         {
878             length_to_sep = sub_path - path;
879             ++sub_path;
880         }
881         else
882         {
883             length_to_sep = strlen(path);
884             sub_path = path + length_to_sep;
885         }
886
887         /* read directory entries */
888         while(fat_read_dir(dd, dir_entry))
889         {
890             /* check if we have found the next hierarchy */
891             if((strlen(dir_entry->long_name) != length_to_sep ||
892                 strncmp(path, dir_entry->long_name, length_to_sep) != 0))
893                 continue;
894
895             fat_close_dir(dd);
896             dd = 0;
897
898             if(path[length_to_sep] == '\0')
899                 /* we iterated through the whole path and have found the file */
900                 return 1;
901
902             if(dir_entry->attributes & FAT_ATTRIB_DIR)
903             {
904                 /* we found a parent directory of the file we are searching for */
905                 path = sub_path;
906                 break;
907             }
908
909             /* a parent of the file exists, but not the file itself */
910             return 0;
911         }
912
913         fat_close_dir(dd);
914     }
915
916     return 0;
917 }
918
919 /**
920  * \ingroup fat_file
921  * Opens a file on a FAT filesystem.
922  *
923  * \param[in] fs The filesystem on which the file to open lies.
924  * \param[in] dir_entry The directory entry of the file to open.
925  * \returns The file handle, or 0 on failure.
926  * \see fat_close_file
927  */
928 struct fat_file_struct* fat_open_file(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry)
929 {
930     if(!fs || !dir_entry || (dir_entry->attributes & FAT_ATTRIB_DIR))
931         return 0;
932
933 #if USE_DYNAMIC_MEMORY
934     struct fat_file_struct* fd = malloc(sizeof(*fd));
935     if(!fd)
936         return 0;
937 #else
938     struct fat_file_struct* fd = fat_file_handles;
939     uint8_t i;
940     for(i = 0; i < FAT_FILE_COUNT; ++i)
941     {
942         if(!fd->fs)
943             break;
944
945         ++fd;
946     }
947     if(i >= FAT_FILE_COUNT)
948         return 0;
949 #endif
950
951     memcpy(&fd->dir_entry, dir_entry, sizeof(*dir_entry));
952     fd->fs = fs;
953     fd->pos = 0;
954     fd->pos_cluster = dir_entry->cluster;
955
956     return fd;
957 }
958
959 /**
960  * \ingroup fat_file
961  * Closes a file.
962  *
963  * \param[in] fd The file handle of the file to close.
964  * \see fat_open_file
965  */
966 void fat_close_file(struct fat_file_struct* fd)
967 {
968     if(fd)
969     {
970 #if FAT_DELAY_DIRENTRY_UPDATE
971         /* write directory entry */
972         fat_write_dir_entry(fd->fs, &fd->dir_entry);
973 #endif
974
975 #if USE_DYNAMIC_MEMORY
976         free(fd);
977 #else
978         fd->fs = 0;
979 #endif
980     }
981 }
982
983 /**
984  * \ingroup fat_file
985  * Reads data from a file.
986  *
987  * The data requested is read from the current file location.
988  *
989  * \param[in] fd The file handle of the file from which to read.
990  * \param[out] buffer The buffer into which to write.
991  * \param[in] buffer_len The amount of data to read.
992  * \returns The number of bytes read, 0 on end of file, or -1 on failure.
993  * \see fat_write_file
994  */
995 intptr_t fat_read_file(struct fat_file_struct* fd, uint8_t* buffer, uintptr_t buffer_len)
996 {
997     /* check arguments */
998     if(!fd || !buffer || buffer_len < 1)
999         return -1;
1000
1001     /* determine number of bytes to read */
1002     if(fd->pos + buffer_len > fd->dir_entry.file_size)
1003         buffer_len = fd->dir_entry.file_size - fd->pos;
1004     if(buffer_len == 0)
1005         return 0;
1006
1007     uint16_t cluster_size = fd->fs->header.cluster_size;
1008     cluster_t cluster_num = fd->pos_cluster;
1009     uintptr_t buffer_left = buffer_len;
1010     uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1));
1011
1012     /* find cluster in which to start reading */
1013     if(!cluster_num)
1014     {
1015         cluster_num = fd->dir_entry.cluster;
1016
1017         if(!cluster_num)
1018         {
1019             if(!fd->pos)
1020                 return 0;
1021             else
1022                 return -1;
1023         }
1024
1025         if(fd->pos)
1026         {
1027             uint32_t pos = fd->pos;
1028             while(pos >= cluster_size)
1029             {
1030                 pos -= cluster_size;
1031                 cluster_num = fat_get_next_cluster(fd->fs, cluster_num);
1032                 if(!cluster_num)
1033                     return -1;
1034             }
1035         }
1036     }
1037
1038     /* read data */
1039     do
1040     {
1041         /* calculate data size to copy from cluster */
1042         offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset;
1043         uint16_t copy_length = cluster_size - first_cluster_offset;
1044         if(copy_length > buffer_left)
1045             copy_length = buffer_left;
1046
1047         /* read data */
1048         if(!fd->fs->partition->device_read(cluster_offset, buffer, copy_length))
1049             return buffer_len - buffer_left;
1050
1051         /* calculate new file position */
1052         buffer += copy_length;
1053         buffer_left -= copy_length;
1054         fd->pos += copy_length;
1055
1056         if(first_cluster_offset + copy_length >= cluster_size)
1057         {
1058             /* we are on a cluster boundary, so get the next cluster */
1059             if((cluster_num = fat_get_next_cluster(fd->fs, cluster_num)))
1060             {
1061                 first_cluster_offset = 0;
1062             }
1063             else
1064             {
1065                 fd->pos_cluster = 0;
1066                 return buffer_len - buffer_left;
1067             }
1068         }
1069
1070         fd->pos_cluster = cluster_num;
1071
1072     } while(buffer_left > 0); /* check if we are done */
1073
1074     return buffer_len;
1075 }
1076
1077 #if DOXYGEN || FAT_WRITE_SUPPORT
1078 /**
1079  * \ingroup fat_file
1080  * Writes data to a file.
1081  *
1082  * The data is written to the current file location.
1083  *
1084  * \param[in] fd The file handle of the file to which to write.
1085  * \param[in] buffer The buffer from which to read the data to be written.
1086  * \param[in] buffer_len The amount of data to write.
1087  * \returns The number of bytes written (0 or something less than \c buffer_len on disk full) or -1 on failure.
1088  * \see fat_read_file
1089  */
1090 intptr_t fat_write_file(struct fat_file_struct* fd, const uint8_t* buffer, uintptr_t buffer_len)
1091 {
1092     /* check arguments */
1093     if(!fd || !buffer || buffer_len < 1)
1094         return -1;
1095     if(fd->pos > fd->dir_entry.file_size)
1096         return -1;
1097
1098     uint16_t cluster_size = fd->fs->header.cluster_size;
1099     cluster_t cluster_num = fd->pos_cluster;
1100     uintptr_t buffer_left = buffer_len;
1101     uint16_t first_cluster_offset = (uint16_t) (fd->pos & (cluster_size - 1));
1102
1103     /* find cluster in which to start writing */
1104     if(!cluster_num)
1105     {
1106         cluster_num = fd->dir_entry.cluster;
1107
1108         if(!cluster_num)
1109         {
1110             if(!fd->pos)
1111             {
1112                 /* empty file */
1113                 fd->dir_entry.cluster = cluster_num = fat_append_clusters(fd->fs, 0, 1);
1114                 if(!cluster_num)
1115                     return 0;
1116             }
1117             else
1118             {
1119                 return -1;
1120             }
1121         }
1122
1123         if(fd->pos)
1124         {
1125             uint32_t pos = fd->pos;
1126             cluster_t cluster_num_next;
1127             while(pos >= cluster_size)
1128             {
1129                 pos -= cluster_size;
1130                 cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
1131                 if(!cluster_num_next)
1132                 {
1133                     if(pos != 0)
1134                         return -1; /* current file position points beyond end of file */
1135
1136                     /* the file exactly ends on a cluster boundary, and we append to it */
1137                     cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1);
1138                     if(!cluster_num_next)
1139                         return 0;
1140                 }
1141
1142                 cluster_num = cluster_num_next;
1143             }
1144         }
1145     }
1146
1147     /* write data */
1148     do
1149     {
1150         /* calculate data size to write to cluster */
1151         offset_t cluster_offset = fat_cluster_offset(fd->fs, cluster_num) + first_cluster_offset;
1152         uint16_t write_length = cluster_size - first_cluster_offset;
1153         if(write_length > buffer_left)
1154             write_length = buffer_left;
1155
1156         /* write data which fits into the current cluster */
1157         if(!fd->fs->partition->device_write(cluster_offset, buffer, write_length))
1158             break;
1159
1160         /* calculate new file position */
1161         buffer += write_length;
1162         buffer_left -= write_length;
1163         fd->pos += write_length;
1164
1165         if(first_cluster_offset + write_length >= cluster_size)
1166         {
1167             /* we are on a cluster boundary, so get the next cluster */
1168             cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
1169             if(!cluster_num_next && buffer_left > 0)
1170                 /* we reached the last cluster, append a new one */
1171                 cluster_num_next = fat_append_clusters(fd->fs, cluster_num, 1);
1172             if(!cluster_num_next)
1173             {
1174                 fd->pos_cluster = 0;
1175                 break;
1176             }
1177
1178             cluster_num = cluster_num_next;
1179             first_cluster_offset = 0;
1180         }
1181
1182         fd->pos_cluster = cluster_num;
1183
1184     } while(buffer_left > 0); /* check if we are done */
1185
1186     /* update directory entry */
1187     if(fd->pos > fd->dir_entry.file_size)
1188     {
1189 #if !FAT_DELAY_DIRENTRY_UPDATE
1190         uint32_t size_old = fd->dir_entry.file_size;
1191 #endif
1192
1193         /* update file size */
1194         fd->dir_entry.file_size = fd->pos;
1195
1196 #if !FAT_DELAY_DIRENTRY_UPDATE
1197         /* write directory entry */
1198         if(!fat_write_dir_entry(fd->fs, &fd->dir_entry))
1199         {
1200             /* We do not return an error here since we actually wrote
1201              * some data to disk. So we calculate the amount of data
1202              * we wrote to disk and which lies within the old file size.
1203              */
1204             buffer_left = fd->pos - size_old;
1205             fd->pos = size_old;
1206         }
1207 #endif
1208     }
1209
1210     return buffer_len - buffer_left;
1211 }
1212 #endif
1213
1214 /**
1215  * \ingroup fat_file
1216  * Repositions the read/write file offset.
1217  *
1218  * Changes the file offset where the next call to fat_read_file()
1219  * or fat_write_file() starts reading/writing.
1220  *
1221  * If the new offset is beyond the end of the file, fat_resize_file()
1222  * is implicitly called, i.e. the file is expanded.
1223  *
1224  * The new offset can be given in different ways determined by
1225  * the \c whence parameter:
1226  * - \b FAT_SEEK_SET: \c *offset is relative to the beginning of the file.
1227  * - \b FAT_SEEK_CUR: \c *offset is relative to the current file position.
1228  * - \b FAT_SEEK_END: \c *offset is relative to the end of the file.
1229  *
1230  * The resulting absolute offset is written to the location the \c offset
1231  * parameter points to.
1232  *
1233  * Calling this function can also be used to retrieve the current file position:
1234    \code
1235    int32_t file_pos = 0;
1236    if(!fat_seek_file(fd, &file_pos, FAT_SEEK_CUR))
1237    {
1238        // error
1239    }
1240    // file_pos now contains the absolute file position
1241    \endcode
1242  *
1243  * \param[in] fd The file decriptor of the file on which to seek.
1244  * \param[in,out] offset A pointer to the new offset, as affected by the \c whence
1245  *                   parameter. The function writes the new absolute offset
1246  *                   to this location before it returns.
1247  * \param[in] whence Affects the way \c offset is interpreted, see above.
1248  * \returns 0 on failure, 1 on success.
1249  */
1250 uint8_t fat_seek_file(struct fat_file_struct* fd, int32_t* offset, uint8_t whence)
1251 {
1252     if(!fd || !offset)
1253         return 0;
1254
1255     uint32_t new_pos = fd->pos;
1256     switch(whence)
1257     {
1258         case FAT_SEEK_SET:
1259             new_pos = *offset;
1260             break;
1261         case FAT_SEEK_CUR:
1262             new_pos += *offset;
1263             break;
1264         case FAT_SEEK_END:
1265             new_pos = fd->dir_entry.file_size + *offset;
1266             break;
1267         default:
1268             return 0;
1269     }
1270
1271     if(new_pos > fd->dir_entry.file_size
1272 #if FAT_WRITE_SUPPORT
1273        && !fat_resize_file(fd, new_pos)
1274 #endif
1275        )
1276         return 0;
1277
1278     fd->pos = new_pos;
1279     fd->pos_cluster = 0;
1280
1281     *offset = (int32_t) new_pos;
1282     return 1;
1283 }
1284
1285 #if DOXYGEN || FAT_WRITE_SUPPORT
1286 /**
1287  * \ingroup fat_file
1288  * Resizes a file to have a specific size.
1289  *
1290  * Enlarges or shrinks the file pointed to by the file descriptor to have
1291  * exactly the specified size.
1292  *
1293  * If the file is truncated, all bytes having an equal or larger offset
1294  * than the given size are lost. If the file is expanded, the additional
1295  * bytes are allocated.
1296  *
1297  * \note Please be aware that this function just allocates or deallocates disk
1298  * space, it does not explicitely clear it. To avoid data leakage, this
1299  * must be done manually.
1300  *
1301  * \param[in] fd The file decriptor of the file which to resize.
1302  * \param[in] size The new size of the file.
1303  * \returns 0 on failure, 1 on success.
1304  */
1305 uint8_t fat_resize_file(struct fat_file_struct* fd, uint32_t size)
1306 {
1307     if(!fd)
1308         return 0;
1309
1310     cluster_t cluster_num = fd->dir_entry.cluster;
1311     uint16_t cluster_size = fd->fs->header.cluster_size;
1312     uint32_t size_new = size;
1313
1314     do
1315     {
1316         if(cluster_num == 0 && size_new == 0)
1317             /* the file stays empty */
1318             break;
1319
1320         /* seek to the next cluster as long as we need the space */
1321         while(size_new > cluster_size)
1322         {
1323             /* get next cluster of file */
1324             cluster_t cluster_num_next = fat_get_next_cluster(fd->fs, cluster_num);
1325             if(cluster_num_next)
1326             {
1327                 cluster_num = cluster_num_next;
1328                 size_new -= cluster_size;
1329             }
1330             else
1331             {
1332                 break;
1333             }
1334         }
1335
1336         if(size_new > cluster_size || cluster_num == 0)
1337         {
1338             /* Allocate new cluster chain and append
1339              * it to the existing one, if available.
1340              */
1341             cluster_t cluster_count = (size_new + cluster_size - 1) / cluster_size;
1342             cluster_t cluster_new_chain = fat_append_clusters(fd->fs, cluster_num, cluster_count);
1343             if(!cluster_new_chain)
1344                 return 0;
1345
1346             if(!cluster_num)
1347             {
1348                 cluster_num = cluster_new_chain;
1349                 fd->dir_entry.cluster = cluster_num;
1350             }
1351         }
1352
1353         /* write new directory entry */
1354         fd->dir_entry.file_size = size;
1355         if(size == 0)
1356             fd->dir_entry.cluster = 0;
1357         if(!fat_write_dir_entry(fd->fs, &fd->dir_entry))
1358             return 0;
1359
1360         if(size == 0)
1361         {
1362             /* free all clusters of file */
1363             fat_free_clusters(fd->fs, cluster_num);
1364         }
1365         else if(size_new <= cluster_size)
1366         {
1367             /* free all clusters no longer needed */
1368             fat_terminate_clusters(fd->fs, cluster_num);
1369         }
1370
1371     } while(0);
1372
1373     /* correct file position */
1374     if(size < fd->pos)
1375     {
1376         fd->pos = size;
1377         fd->pos_cluster = 0;
1378     }
1379
1380     return 1;
1381 }
1382 #endif
1383
1384 /**
1385  * \ingroup fat_dir
1386  * Opens a directory.
1387  *
1388  * \param[in] fs The filesystem on which the directory to open resides.
1389  * \param[in] dir_entry The directory entry which stands for the directory to open.
1390  * \returns An opaque directory descriptor on success, 0 on failure.
1391  * \see fat_close_dir
1392  */
1393 struct fat_dir_struct* fat_open_dir(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry)
1394 {
1395     if(!fs || !dir_entry || !(dir_entry->attributes & FAT_ATTRIB_DIR))
1396         return 0;
1397
1398 #if USE_DYNAMIC_MEMORY
1399     struct fat_dir_struct* dd = malloc(sizeof(*dd));
1400     if(!dd)
1401         return 0;
1402 #else
1403     struct fat_dir_struct* dd = fat_dir_handles;
1404     uint8_t i;
1405     for(i = 0; i < FAT_DIR_COUNT; ++i)
1406     {
1407         if(!dd->fs)
1408             break;
1409
1410         ++dd;
1411     }
1412     if(i >= FAT_DIR_COUNT)
1413         return 0;
1414 #endif
1415
1416     memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry));
1417     dd->fs = fs;
1418     dd->entry_cluster = dir_entry->cluster;
1419     dd->entry_offset = 0;
1420
1421     return dd;
1422 }
1423
1424 /**
1425  * \ingroup fat_dir
1426  * Closes a directory descriptor.
1427  *
1428  * This function destroys a directory descriptor which was
1429  * previously obtained by calling fat_open_dir(). When this
1430  * function returns, the given descriptor will be invalid.
1431  *
1432  * \param[in] dd The directory descriptor to close.
1433  * \see fat_open_dir
1434  */
1435 void fat_close_dir(struct fat_dir_struct* dd)
1436 {
1437     if(dd)
1438 #if USE_DYNAMIC_MEMORY
1439         free(dd);
1440 #else
1441         dd->fs = 0;
1442 #endif
1443 }
1444
1445 /**
1446  * \ingroup fat_dir
1447  * Reads the next directory entry contained within a parent directory.
1448  *
1449  * \param[in] dd The descriptor of the parent directory from which to read the entry.
1450  * \param[out] dir_entry Pointer to a buffer into which to write the directory entry information.
1451  * \returns 0 on failure, 1 on success.
1452  * \see fat_reset_dir
1453  */
1454 uint8_t fat_read_dir(struct fat_dir_struct* dd, struct fat_dir_entry_struct* dir_entry)
1455 {
1456     if(!dd || !dir_entry)
1457         return 0;
1458
1459     /* get current position of directory handle */
1460     struct fat_fs_struct* fs = dd->fs;
1461     const struct fat_header_struct* header = &fs->header;
1462     uint16_t cluster_size = header->cluster_size;
1463     cluster_t cluster_num = dd->entry_cluster;
1464     uint16_t cluster_offset = dd->entry_offset;
1465     struct fat_read_dir_callback_arg arg;
1466
1467     if(cluster_offset >= cluster_size)
1468     {
1469         /* The latest call hit the border of the last cluster in
1470          * the chain, but it still returned a directory entry.
1471          * So we now reset the handle and signal the caller the
1472          * end of the listing.
1473          */
1474         fat_reset_dir(dd);
1475         return 0;
1476     }
1477
1478     /* reset callback arguments */
1479     memset(&arg, 0, sizeof(arg));
1480     memset(dir_entry, 0, sizeof(*dir_entry));
1481     arg.dir_entry = dir_entry;
1482
1483     /* check if we read from the root directory */
1484     if(cluster_num == 0)
1485     {
1486 #if FAT_FAT32_SUPPORT
1487         if(fs->partition->type == PARTITION_TYPE_FAT32)
1488             cluster_num = header->root_dir_cluster;
1489         else
1490 #endif
1491             cluster_size = header->cluster_zero_offset - header->root_dir_offset;
1492     }
1493
1494     /* read entries */
1495     uint8_t buffer[32];
1496     while(!arg.finished)
1497     {
1498         /* read directory entries up to the cluster border */
1499         uint16_t cluster_left = cluster_size - cluster_offset;
1500         offset_t pos = cluster_offset;
1501         if(cluster_num == 0)
1502             pos += header->root_dir_offset;
1503         else
1504             pos += fat_cluster_offset(fs, cluster_num);
1505
1506         arg.bytes_read = 0;
1507         if(!fs->partition->device_read_interval(pos,
1508                                                 buffer,
1509                                                 sizeof(buffer),
1510                                                 cluster_left,
1511                                                 fat_dir_entry_read_callback,
1512                                                 &arg)
1513           )
1514             return 0;
1515
1516         cluster_offset += arg.bytes_read;
1517
1518         if(cluster_offset >= cluster_size)
1519         {
1520             /* we reached the cluster border and switch to the next cluster */
1521
1522             /* get number of next cluster */
1523             if((cluster_num = fat_get_next_cluster(fs, cluster_num)) != 0)
1524             {
1525                 cluster_offset = 0;
1526                 continue;
1527             }
1528
1529             /* we are at the end of the cluster chain */
1530             if(!arg.finished)
1531             {
1532                 /* directory entry not found, reset directory handle */
1533                 fat_reset_dir(dd);
1534                 return 0;
1535             }
1536             else
1537             {
1538                 /* The current execution of the function has been successful,
1539                  * so we can not signal an end of the directory listing to
1540                  * the caller, but must wait for the next call. So we keep an
1541                  * invalid cluster offset to mark this directory handle's
1542                  * traversal as finished.
1543                  */
1544             }
1545
1546             break;
1547         }
1548     }
1549
1550     dd->entry_cluster = cluster_num;
1551     dd->entry_offset = cluster_offset;
1552
1553     return arg.finished;
1554 }
1555
1556 /**
1557  * \ingroup fat_dir
1558  * Resets a directory handle.
1559  *
1560  * Resets the directory handle such that reading restarts
1561  * with the first directory entry.
1562  *
1563  * \param[in] dd The directory handle to reset.
1564  * \returns 0 on failure, 1 on success.
1565  * \see fat_read_dir
1566  */
1567 uint8_t fat_reset_dir(struct fat_dir_struct* dd)
1568 {
1569     if(!dd)
1570         return 0;
1571
1572     dd->entry_cluster = dd->dir_entry.cluster;
1573     dd->entry_offset = 0;
1574     return 1;
1575 }
1576
1577 /**
1578  * \ingroup fat_fs
1579  * Callback function for reading a directory entry.
1580  *
1581  * Interprets a raw directory entry and puts the contained
1582  * information into a fat_dir_entry_struct structure.
1583  *
1584  * For a single file there may exist multiple directory
1585  * entries. All except the last one are lfn entries, which
1586  * contain parts of the long filename. The last directory
1587  * entry is a traditional 8.3 style one. It contains all
1588  * other information like size, cluster, date and time.
1589  *
1590  * \param[in] buffer A pointer to 32 bytes of raw data.
1591  * \param[in] offset The absolute offset of the raw data.
1592  * \param[in,out] p An argument structure controlling operation.
1593  * \returns 0 on failure or completion, 1 if reading has
1594  *          to be continued
1595  */
1596 uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p)
1597 {
1598     struct fat_read_dir_callback_arg* arg = p;
1599     struct fat_dir_entry_struct* dir_entry = arg->dir_entry;
1600
1601     arg->bytes_read += 32;
1602
1603     /* skip deleted or empty entries */
1604     if(buffer[0] == FAT_DIRENTRY_DELETED || !buffer[0])
1605     {
1606 #if FAT_LFN_SUPPORT
1607         arg->checksum = 0;
1608 #endif
1609         return 1;
1610     }
1611
1612 #if !FAT_LFN_SUPPORT
1613     /* skip lfn entries */
1614     if(buffer[11] == 0x0f)
1615         return 1;
1616 #endif
1617
1618     char* long_name = dir_entry->long_name;
1619 #if FAT_LFN_SUPPORT
1620     if(buffer[11] == 0x0f)
1621     {
1622         /* checksum validation */
1623         if(arg->checksum == 0 || arg->checksum != buffer[13])
1624         {
1625             /* reset directory entry */
1626             memset(dir_entry, 0, sizeof(*dir_entry));
1627
1628             arg->checksum = buffer[13];
1629             dir_entry->entry_offset = offset;
1630         }
1631
1632         /* lfn supports unicode, but we do not, for now.
1633          * So we assume pure ascii and read only every
1634          * second byte.
1635          */
1636         uint16_t char_offset = ((buffer[0] & 0x3f) - 1) * 13;
1637         const uint8_t char_mapping[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
1638         for(uint8_t i = 0; i <= 12 && char_offset + i < sizeof(dir_entry->long_name) - 1; ++i)
1639             long_name[char_offset + i] = buffer[char_mapping[i]];
1640
1641         return 1;
1642     }
1643     else
1644 #endif
1645     {
1646 #if FAT_LFN_SUPPORT
1647         /* if we do not have a long name or the previous lfn does not match, take the 8.3 name */
1648         if(long_name[0] == '\0' || arg->checksum != fat_calc_83_checksum(buffer))
1649 #endif
1650         {
1651             /* reset directory entry */
1652             memset(dir_entry, 0, sizeof(*dir_entry));
1653             dir_entry->entry_offset = offset;
1654
1655             uint8_t i;
1656             for(i = 0; i < 8; ++i)
1657             {
1658                 if(buffer[i] == ' ')
1659                     break;
1660                 long_name[i] = buffer[i];
1661
1662                 /* Windows NT and later versions do not store lfn entries
1663                  * for 8.3 names which have a lowercase basename, extension
1664                  * or both when everything else is uppercase. They use two
1665                  * extra bits to signal a lowercase basename or extension.
1666                  */
1667                 if((buffer[12] & 0x08) && buffer[i] >= 'A' && buffer[i] <= 'Z')
1668                     long_name[i] += 'a' - 'A';
1669             }
1670             if(long_name[0] == 0x05)
1671                 long_name[0] = (char) FAT_DIRENTRY_DELETED;
1672
1673             if(buffer[8] != ' ')
1674             {
1675                 long_name[i++] = '.';
1676
1677                 uint8_t j = 8;
1678                 for(; j < 11; ++j)
1679                 {
1680                     if(buffer[j] == ' ')
1681                         break;
1682                     long_name[i] = buffer[j];
1683
1684                     /* See above for the lowercase 8.3 name handling of
1685                      * Windows NT and later.
1686                      */
1687                     if((buffer[12] & 0x10) && buffer[j] >= 'A' && buffer[j] <= 'Z')
1688                         long_name[i] += 'a' - 'A';
1689
1690                     ++i;
1691                 }
1692             }
1693
1694             long_name[i] = '\0';
1695         }
1696
1697         /* extract properties of file and store them within the structure */
1698         dir_entry->attributes = buffer[11];
1699         dir_entry->cluster = read16(&buffer[26]);
1700 #if FAT_FAT32_SUPPORT
1701         dir_entry->cluster |= ((cluster_t) read16(&buffer[20])) << 16;
1702 #endif
1703         dir_entry->file_size = read32(&buffer[28]);
1704
1705 #if FAT_DATETIME_SUPPORT
1706         dir_entry->modification_time = read16(&buffer[22]);
1707         dir_entry->modification_date = read16(&buffer[24]);
1708 #endif
1709
1710         arg->finished = 1;
1711         return 0;
1712     }
1713 }
1714
1715 #if DOXYGEN || FAT_LFN_SUPPORT
1716 /**
1717  * \ingroup fat_fs
1718  * Calculates the checksum for 8.3 names used within the
1719  * corresponding lfn directory entries.
1720  *
1721  * \param[in] file_name_83 The 11-byte file name buffer.
1722  * \returns The checksum of the given file name.
1723  */
1724 uint8_t fat_calc_83_checksum(const uint8_t* file_name_83)
1725 {
1726     uint8_t checksum = file_name_83[0];
1727     for(uint8_t i = 1; i < 11; ++i)
1728         checksum = ((checksum >> 1) | (checksum << 7)) + file_name_83[i];
1729
1730     return checksum;
1731 }
1732 #endif
1733
1734 #if DOXYGEN || FAT_WRITE_SUPPORT
1735 /**
1736  * \ingroup fat_fs
1737  * Searches for space where to store a directory entry.
1738  *
1739  * \param[in] fs The filesystem on which to operate.
1740  * \param[in] parent The directory in which to search.
1741  * \param[in] dir_entry The directory entry for which to search space.
1742  * \returns 0 on failure, a device offset on success.
1743  */
1744 offset_t fat_find_offset_for_dir_entry(struct fat_fs_struct* fs, const struct fat_dir_struct* parent, const struct fat_dir_entry_struct* dir_entry)
1745 {
1746     if(!fs || !dir_entry)
1747         return 0;
1748
1749     /* search for a place where to write the directory entry to disk */
1750 #if FAT_LFN_SUPPORT
1751     uint8_t free_dir_entries_needed = (strlen(dir_entry->long_name) + 12) / 13 + 1;
1752     uint8_t free_dir_entries_found = 0;
1753 #endif
1754     cluster_t cluster_num = parent->dir_entry.cluster;
1755     offset_t dir_entry_offset = 0;
1756     offset_t offset = 0;
1757     offset_t offset_to = 0;
1758 #if FAT_FAT32_SUPPORT
1759     uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32);
1760 #endif
1761
1762     if(cluster_num == 0)
1763     {
1764 #if FAT_FAT32_SUPPORT
1765         if(is_fat32)
1766         {
1767             cluster_num = fs->header.root_dir_cluster;
1768         }
1769         else
1770 #endif
1771         {
1772             /* we read/write from the root directory entry */
1773             offset = fs->header.root_dir_offset;
1774             offset_to = fs->header.cluster_zero_offset;
1775             dir_entry_offset = offset;
1776         }
1777     }
1778
1779     while(1)
1780     {
1781         if(offset == offset_to)
1782         {
1783             if(cluster_num == 0)
1784                 /* We iterated through the whole root directory and
1785                  * could not find enough space for the directory entry.
1786                  */
1787                 return 0;
1788
1789             if(offset)
1790             {
1791                 /* We reached a cluster boundary and have to
1792                  * switch to the next cluster.
1793                  */
1794
1795                 cluster_t cluster_next = fat_get_next_cluster(fs, cluster_num);
1796                 if(!cluster_next)
1797                 {
1798                     cluster_next = fat_append_clusters(fs, cluster_num, 1);
1799                     if(!cluster_next)
1800                         return 0;
1801
1802                     /* we appended a new cluster and know it is free */
1803                     dir_entry_offset = fs->header.cluster_zero_offset +
1804                                        (offset_t) (cluster_next - 2) * fs->header.cluster_size;
1805
1806                     /* clear cluster to avoid garbage directory entries */
1807                     fat_clear_cluster(fs, cluster_next);
1808
1809                     break;
1810                 }
1811                 cluster_num = cluster_next;
1812             }
1813
1814             offset = fat_cluster_offset(fs, cluster_num);
1815             offset_to = offset + fs->header.cluster_size;
1816             dir_entry_offset = offset;
1817 #if FAT_LFN_SUPPORT
1818             free_dir_entries_found = 0;
1819 #endif
1820         }
1821
1822         /* read next lfn or 8.3 entry */
1823         uint8_t first_char;
1824         if(!fs->partition->device_read(offset, &first_char, sizeof(first_char)))
1825             return 0;
1826
1827         /* check if we found a free directory entry */
1828         if(first_char == FAT_DIRENTRY_DELETED || !first_char)
1829         {
1830             /* check if we have the needed number of available entries */
1831 #if FAT_LFN_SUPPORT
1832             ++free_dir_entries_found;
1833             if(free_dir_entries_found >= free_dir_entries_needed)
1834 #endif
1835                 break;
1836
1837             offset += 32;
1838         }
1839         else
1840         {
1841             offset += 32;
1842             dir_entry_offset = offset;
1843 #if FAT_LFN_SUPPORT
1844             free_dir_entries_found = 0;
1845 #endif
1846         }
1847     }
1848
1849     return dir_entry_offset;
1850 }
1851 #endif
1852
1853 #if DOXYGEN || FAT_WRITE_SUPPORT
1854 /**
1855  * \ingroup fat_fs
1856  * Writes a directory entry to disk.
1857  *
1858  * \note The file name is not checked for invalid characters.
1859  *
1860  * \note The generation of the short 8.3 file name is quite
1861  * simple. The first eight characters are used for the filename.
1862  * The extension, if any, is made up of the first three characters
1863  * following the last dot within the long filename. If the
1864  * filename (without the extension) is longer than eight characters,
1865  * the lower byte of the cluster number replaces the last two
1866  * characters to avoid name clashes. In any other case, it is your
1867  * responsibility to avoid name clashes.
1868  *
1869  * \param[in] fs The filesystem on which to operate.
1870  * \param[in] dir_entry The directory entry to write.
1871  * \returns 0 on failure, 1 on success.
1872  */
1873 uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry)
1874 {
1875     if(!fs || !dir_entry)
1876         return 0;
1877
1878 #if FAT_DATETIME_SUPPORT
1879     {
1880         uint16_t year;
1881         uint8_t month;
1882         uint8_t day;
1883         uint8_t hour;
1884         uint8_t min;
1885         uint8_t sec;
1886
1887         fat_get_datetime(&year, &month, &day, &hour, &min, &sec);
1888         fat_set_file_modification_date(dir_entry, year, month, day);
1889         fat_set_file_modification_time(dir_entry, hour, min, sec);
1890     }
1891 #endif
1892
1893     device_write_t device_write = fs->partition->device_write;
1894     offset_t offset = dir_entry->entry_offset;
1895     const char* name = dir_entry->long_name;
1896     uint8_t name_len = strlen(name);
1897 #if FAT_LFN_SUPPORT
1898     uint8_t lfn_entry_count = (name_len + 12) / 13;
1899 #endif
1900     uint8_t buffer[32];
1901
1902     /* write 8.3 entry */
1903
1904     /* generate 8.3 file name */
1905     memset(&buffer[0], ' ', 11);
1906     char* name_ext = strrchr(name, '.');
1907     if(name_ext && *++name_ext)
1908     {
1909         uint8_t name_ext_len = strlen(name_ext);
1910         name_len -= name_ext_len + 1;
1911
1912         if(name_ext_len > 3)
1913 #if FAT_LFN_SUPPORT
1914             name_ext_len = 3;
1915 #else
1916             return 0;
1917 #endif
1918
1919         memcpy(&buffer[8], name_ext, name_ext_len);
1920     }
1921
1922     if(name_len <= 8)
1923     {
1924         memcpy(buffer, name, name_len);
1925
1926 #if FAT_LFN_SUPPORT
1927         /* For now, we create lfn entries for all files,
1928          * except the "." and ".." directory references.
1929          * This is to avoid difficulties with capitalization,
1930          * as 8.3 filenames allow uppercase letters only.
1931          *
1932          * Theoretically it would be possible to leave
1933          * the 8.3 entry alone if the basename and the
1934          * extension have no mixed capitalization.
1935          */
1936         if(name[0] == '.' &&
1937            ((name[1] == '.' && name[2] == '\0') ||
1938             name[1] == '\0')
1939           )
1940             lfn_entry_count = 0;
1941 #endif
1942     }
1943     else
1944     {
1945 #if FAT_LFN_SUPPORT
1946         memcpy(buffer, name, 8);
1947
1948         /* Minimize 8.3 name clashes by appending
1949          * the lower byte of the cluster number.
1950          */
1951         uint8_t num = dir_entry->cluster & 0xff;
1952
1953         buffer[6] = (num < 0xa0) ? ('0' + (num >> 4)) : ('a' + (num >> 4));
1954         num &= 0x0f;
1955         buffer[7] = (num < 0x0a) ? ('0' + num) : ('a' + num);
1956 #else
1957         return 0;
1958 #endif
1959     }
1960     if(buffer[0] == FAT_DIRENTRY_DELETED)
1961         buffer[0] = 0x05;
1962
1963     /* fill directory entry buffer */
1964     memset(&buffer[11], 0, sizeof(buffer) - 11);
1965     buffer[0x0b] = dir_entry->attributes;
1966 #if FAT_DATETIME_SUPPORT
1967     write16(&buffer[0x16], dir_entry->modification_time);
1968     write16(&buffer[0x18], dir_entry->modification_date);
1969 #endif
1970 #if FAT_FAT32_SUPPORT
1971     write16(&buffer[0x14], (uint16_t) (dir_entry->cluster >> 16));
1972 #endif
1973     write16(&buffer[0x1a], dir_entry->cluster);
1974     write32(&buffer[0x1c], dir_entry->file_size);
1975
1976     /* write to disk */
1977 #if FAT_LFN_SUPPORT
1978     if(!device_write(offset + (uint16_t) lfn_entry_count * 32, buffer, sizeof(buffer)))
1979 #else
1980     if(!device_write(offset, buffer, sizeof(buffer)))
1981 #endif
1982         return 0;
1983
1984 #if FAT_LFN_SUPPORT
1985     /* calculate checksum of 8.3 name */
1986     uint8_t checksum = fat_calc_83_checksum(buffer);
1987
1988     /* write lfn entries */
1989     for(uint8_t lfn_entry = lfn_entry_count; lfn_entry > 0; --lfn_entry)
1990     {
1991         memset(buffer, 0xff, sizeof(buffer));
1992
1993         /* set file name */
1994         const char* long_name_curr = name + (lfn_entry - 1) * 13;
1995         uint8_t i = 1;
1996         while(i < 0x1f)
1997         {
1998             buffer[i++] = *long_name_curr;
1999             buffer[i++] = 0;
2000
2001             switch(i)
2002             {
2003                 case 0x0b:
2004                     i = 0x0e;
2005                     break;
2006                 case 0x1a:
2007                     i = 0x1c;
2008                     break;
2009             }
2010
2011             if(!*long_name_curr++)
2012                 break;
2013         }
2014
2015         /* set index of lfn entry */
2016         buffer[0x00] = lfn_entry;
2017         if(lfn_entry == lfn_entry_count)
2018             buffer[0x00] |= FAT_DIRENTRY_LFNLAST;
2019
2020         /* mark as lfn entry */
2021         buffer[0x0b] = 0x0f;
2022
2023         /* set 8.3 checksum */
2024         buffer[0x0d] = checksum;
2025
2026         /* clear reserved bytes */
2027         buffer[0x0c] = 0;
2028         buffer[0x1a] = 0;
2029         buffer[0x1b] = 0;
2030
2031         /* write entry */
2032         device_write(offset, buffer, sizeof(buffer));
2033
2034         offset += sizeof(buffer);
2035     }
2036 #endif
2037
2038     return 1;
2039 }
2040 #endif
2041
2042 #if DOXYGEN || FAT_WRITE_SUPPORT
2043 /**
2044  * \ingroup fat_file
2045  * Creates a file.
2046  *
2047  * Creates a file and obtains the directory entry of the
2048  * new file. If the file to create already exists, the
2049  * directory entry of the existing file will be returned
2050  * within the dir_entry parameter.
2051  *
2052  * \note The file name is not checked for invalid characters.
2053  *
2054  * \note The generation of the short 8.3 file name is quite
2055  * simple. The first eight characters are used for the filename.
2056  * The extension, if any, is made up of the first three characters
2057  * following the last dot within the long filename. If the
2058  * filename (without the extension) is longer than eight characters,
2059  * the lower byte of the cluster number replaces the last two
2060  * characters to avoid name clashes. In any other case, it is your
2061  * responsibility to avoid name clashes.
2062  *
2063  * \param[in] parent The handle of the directory in which to create the file.
2064  * \param[in] file The name of the file to create.
2065  * \param[out] dir_entry The directory entry to fill for the new (or existing) file.
2066  * \returns 0 on failure, 1 on success, 2 if the file already existed.
2067  * \see fat_delete_file
2068  */
2069 uint8_t fat_create_file(struct fat_dir_struct* parent, const char* file, struct fat_dir_entry_struct* dir_entry)
2070 {
2071     if(!parent || !file || !file[0] || !dir_entry)
2072         return 0;
2073
2074     /* check if the file already exists */
2075     while(1)
2076     {
2077         if(!fat_read_dir(parent, dir_entry))
2078             break;
2079
2080         if(strcmp(file, dir_entry->long_name) == 0)
2081         {
2082             fat_reset_dir(parent);
2083             return 2;
2084         }
2085     }
2086
2087     struct fat_fs_struct* fs = parent->fs;
2088
2089     /* prepare directory entry with values already known */
2090     memset(dir_entry, 0, sizeof(*dir_entry));
2091     strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name) - 1);
2092
2093     /* find place where to store directory entry */
2094     if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))
2095         return 0;
2096
2097     /* write directory entry to disk */
2098     if(!fat_write_dir_entry(fs, dir_entry))
2099         return 0;
2100
2101     return 1;
2102 }
2103 #endif
2104
2105 #if DOXYGEN || FAT_WRITE_SUPPORT
2106 /**
2107  * \ingroup fat_file
2108  * Deletes a file or directory.
2109  *
2110  * If a directory is deleted without first deleting its
2111  * subdirectories and files, disk space occupied by these
2112  * files will get wasted as there is no chance to release
2113  * it and mark it as free.
2114  *
2115  * \param[in] fs The filesystem on which to operate.
2116  * \param[in] dir_entry The directory entry of the file to delete.
2117  * \returns 0 on failure, 1 on success.
2118  * \see fat_create_file
2119  */
2120 uint8_t fat_delete_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry)
2121 {
2122     if(!fs || !dir_entry)
2123         return 0;
2124
2125     /* get offset of the file's directory entry */
2126     offset_t dir_entry_offset = dir_entry->entry_offset;
2127     if(!dir_entry_offset)
2128         return 0;
2129
2130 #if FAT_LFN_SUPPORT
2131     uint8_t buffer[12];
2132     while(1)
2133     {
2134         /* read directory entry */
2135         if(!fs->partition->device_read(dir_entry_offset, buffer, sizeof(buffer)))
2136             return 0;
2137
2138         /* mark the directory entry as deleted */
2139         buffer[0] = FAT_DIRENTRY_DELETED;
2140
2141         /* write back entry */
2142         if(!fs->partition->device_write(dir_entry_offset, buffer, sizeof(buffer)))
2143             return 0;
2144
2145         /* check if we deleted the whole entry */
2146         if(buffer[11] != 0x0f)
2147             break;
2148
2149         dir_entry_offset += 32;
2150     }
2151 #else
2152     /* mark the directory entry as deleted */
2153     uint8_t first_char = FAT_DIRENTRY_DELETED;
2154     if(!fs->partition->device_write(dir_entry_offset, &first_char, 1))
2155         return 0;
2156 #endif
2157
2158     /* We deleted the directory entry. The next thing to do is
2159      * marking all occupied clusters as free.
2160      */
2161     return (dir_entry->cluster == 0 || fat_free_clusters(fs, dir_entry->cluster));
2162 }
2163 #endif
2164
2165 #if DOXYGEN || FAT_WRITE_SUPPORT
2166 /**
2167  * \ingroup fat_file
2168  * Moves or renames a file.
2169  *
2170  * Changes a file's name, optionally moving it into another
2171  * directory as well. Before calling this function, the
2172  * target file name must not exist. Moving a file to a
2173  * different filesystem (i.e. \a parent_new doesn't lie on
2174  * \a fs) is not supported.
2175  *
2176  * After successfully renaming (and moving) the file, the
2177  * given directory entry is updated such that it points to
2178  * the file's new location.
2179  *
2180  * \note The notes which apply to fat_create_file() also
2181  * apply to this function.
2182  *
2183  * \param[in] fs The filesystem on which to operate.
2184  * \param[in,out] dir_entry The directory entry of the file to move.
2185  * \param[in] parent_new The handle of the new parent directory of the file.
2186  * \param[in] file_new The file's new name.
2187  * \returns 0 on failure, 1 on success.
2188  * \see fat_create_file, fat_delete_file, fat_move_dir
2189  */
2190 uint8_t fat_move_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry, struct fat_dir_struct* parent_new, const char* file_new)
2191 {
2192     if(!fs || !dir_entry || !parent_new || (file_new && !file_new[0]))
2193         return 0;
2194     if(fs != parent_new->fs)
2195         return 0;
2196
2197     /* use existing file name if none has been specified */
2198     if(!file_new)
2199         file_new = dir_entry->long_name;
2200
2201     /* create file with new file name */
2202     struct fat_dir_entry_struct dir_entry_new;
2203     if(!fat_create_file(parent_new, file_new, &dir_entry_new))
2204         return 0;
2205
2206     /* copy members of directory entry which do not change with rename */
2207     dir_entry_new.attributes = dir_entry->attributes;
2208 #if FAT_DATETIME_SUPPORT
2209     dir_entry_new.modification_time = dir_entry->modification_time;
2210     dir_entry_new.modification_date = dir_entry->modification_date;
2211 #endif
2212     dir_entry_new.cluster = dir_entry->cluster;
2213     dir_entry_new.file_size = dir_entry->file_size;
2214
2215     /* make the new file name point to the old file's content */
2216     if(!fat_write_dir_entry(fs, &dir_entry_new))
2217     {
2218         fat_delete_file(fs, &dir_entry_new);
2219         return 0;
2220     }
2221
2222     /* delete the old file, but not its clusters, which have already been remapped above */
2223     dir_entry->cluster = 0;
2224     if(!fat_delete_file(fs, dir_entry))
2225         return 0;
2226
2227     *dir_entry = dir_entry_new;
2228     return 1;
2229 }
2230 #endif
2231
2232 #if DOXYGEN || FAT_WRITE_SUPPORT
2233 /**
2234  * \ingroup fat_dir
2235  * Creates a directory.
2236  *
2237  * Creates a directory and obtains its directory entry.
2238  * If the directory to create already exists, its
2239  * directory entry will be returned within the dir_entry
2240  * parameter.
2241  *
2242  * \note The notes which apply to fat_create_file() also
2243  * apply to this function.
2244  *
2245  * \param[in] parent The handle of the parent directory of the new directory.
2246  * \param[in] dir The name of the directory to create.
2247  * \param[out] dir_entry The directory entry to fill for the new directory.
2248  * \returns 0 on failure, 1 on success.
2249  * \see fat_delete_dir
2250  */
2251 uint8_t fat_create_dir(struct fat_dir_struct* parent, const char* dir, struct fat_dir_entry_struct* dir_entry)
2252 {
2253     if(!parent || !dir || !dir[0] || !dir_entry)
2254         return 0;
2255
2256     /* check if the file or directory already exists */
2257     while(fat_read_dir(parent, dir_entry))
2258     {
2259         if(strcmp(dir, dir_entry->long_name) == 0)
2260         {
2261             fat_reset_dir(parent);
2262             return 0;
2263         }
2264     }
2265
2266     struct fat_fs_struct* fs = parent->fs;
2267
2268     /* allocate cluster which will hold directory entries */
2269     cluster_t dir_cluster = fat_append_clusters(fs, 0, 1);
2270     if(!dir_cluster)
2271         return 0;
2272
2273     /* clear cluster to prevent bogus directory entries */
2274     fat_clear_cluster(fs, dir_cluster);
2275
2276     memset(dir_entry, 0, sizeof(*dir_entry));
2277     dir_entry->attributes = FAT_ATTRIB_DIR;
2278
2279     /* create "." directory self reference */
2280     dir_entry->entry_offset = fs->header.cluster_zero_offset +
2281                               (offset_t) (dir_cluster - 2) * fs->header.cluster_size;
2282     dir_entry->long_name[0] = '.';
2283     dir_entry->cluster = dir_cluster;
2284     if(!fat_write_dir_entry(fs, dir_entry))
2285     {
2286         fat_free_clusters(fs, dir_cluster);
2287         return 0;
2288     }
2289
2290     /* create ".." parent directory reference */
2291     dir_entry->entry_offset += 32;
2292     dir_entry->long_name[1] = '.';
2293     dir_entry->cluster = parent->dir_entry.cluster;
2294     if(!fat_write_dir_entry(fs, dir_entry))
2295     {
2296         fat_free_clusters(fs, dir_cluster);
2297         return 0;
2298     }
2299
2300     /* fill directory entry */
2301     strncpy(dir_entry->long_name, dir, sizeof(dir_entry->long_name) - 1);
2302     dir_entry->cluster = dir_cluster;
2303
2304     /* find place where to store directory entry */
2305     if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))
2306     {
2307         fat_free_clusters(fs, dir_cluster);
2308         return 0;
2309     }
2310
2311     /* write directory to disk */
2312     if(!fat_write_dir_entry(fs, dir_entry))
2313     {
2314         fat_free_clusters(fs, dir_cluster);
2315         return 0;
2316     }
2317
2318     return 1;
2319 }
2320 #endif
2321
2322 /**
2323  * \ingroup fat_dir
2324  * Deletes a directory.
2325  *
2326  * This is just a synonym for fat_delete_file().
2327  * If a directory is deleted without first deleting its
2328  * subdirectories and files, disk space occupied by these
2329  * files will get wasted as there is no chance to release
2330  * it and mark it as free.
2331  *
2332  * \param[in] fs The filesystem on which to operate.
2333  * \param[in] dir_entry The directory entry of the directory to delete.
2334  * \returns 0 on failure, 1 on success.
2335  * \see fat_create_dir
2336  */
2337 #ifdef DOXYGEN
2338 uint8_t fat_delete_dir(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry);
2339 #endif
2340
2341 /**
2342  * \ingroup fat_dir
2343  * Moves or renames a directory.
2344  *
2345  * This is just a synonym for fat_move_file().
2346  *
2347  * \param[in] fs The filesystem on which to operate.
2348  * \param[in,out] dir_entry The directory entry of the directory to move.
2349  * \param[in] parent_new The handle of the new parent directory.
2350  * \param[in] dir_new The directory's new name.
2351  * \returns 0 on failure, 1 on success.
2352  * \see fat_create_dir, fat_delete_dir, fat_move_file
2353  */
2354 #ifdef DOXYGEN
2355 uint8_t fat_move_dir(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry, struct fat_dir_struct* parent_new, const char* dir_new);
2356 #endif
2357
2358 #if DOXYGEN || FAT_DATETIME_SUPPORT
2359 /**
2360  * \ingroup fat_file
2361  * Returns the modification date of a file.
2362  *
2363  * \param[in] dir_entry The directory entry of which to return the modification date.
2364  * \param[out] year The year the file was last modified.
2365  * \param[out] month The month the file was last modified.
2366  * \param[out] day The day the file was last modified.
2367  */
2368 void fat_get_file_modification_date(const struct fat_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day)
2369 {
2370     if(!dir_entry)
2371         return;
2372
2373     *year = 1980 + ((dir_entry->modification_date >> 9) & 0x7f);
2374     *month = (dir_entry->modification_date >> 5) & 0x0f;
2375     *day = (dir_entry->modification_date >> 0) & 0x1f;
2376 }
2377 #endif
2378
2379 #if DOXYGEN || FAT_DATETIME_SUPPORT
2380 /**
2381  * \ingroup fat_file
2382  * Returns the modification time of a file.
2383  *
2384  * \param[in] dir_entry The directory entry of which to return the modification time.
2385  * \param[out] hour The hour the file was last modified.
2386  * \param[out] min The min the file was last modified.
2387  * \param[out] sec The sec the file was last modified.
2388  */
2389 void fat_get_file_modification_time(const struct fat_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec)
2390 {
2391     if(!dir_entry)
2392         return;
2393
2394     *hour = (dir_entry->modification_time >> 11) & 0x1f;
2395     *min = (dir_entry->modification_time >> 5) & 0x3f;
2396     *sec = ((dir_entry->modification_time >> 0) & 0x1f) * 2;
2397 }
2398 #endif
2399
2400 #if DOXYGEN || (FAT_WRITE_SUPPORT && FAT_DATETIME_SUPPORT)
2401 /**
2402  * \ingroup fat_file
2403  * Sets the modification time of a date.
2404  *
2405  * \param[in] dir_entry The directory entry for which to set the modification date.
2406  * \param[in] year The year the file was last modified.
2407  * \param[in] month The month the file was last modified.
2408  * \param[in] day The day the file was last modified.
2409  */
2410 void fat_set_file_modification_date(struct fat_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day)
2411 {
2412     if(!dir_entry)
2413         return;
2414
2415     dir_entry->modification_date =
2416         ((year - 1980) << 9) |
2417         ((uint16_t) month << 5) |
2418         ((uint16_t) day << 0);
2419 }
2420 #endif
2421
2422 #if DOXYGEN || (FAT_WRITE_SUPPORT && FAT_DATETIME_SUPPORT)
2423 /**
2424  * \ingroup fat_file
2425  * Sets the modification time of a file.
2426  *
2427  * \param[in] dir_entry The directory entry for which to set the modification time.
2428  * \param[in] hour The year the file was last modified.
2429  * \param[in] min The month the file was last modified.
2430  * \param[in] sec The day the file was last modified.
2431  */
2432 void fat_set_file_modification_time(struct fat_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec)
2433 {
2434     if(!dir_entry)
2435         return;
2436
2437     dir_entry->modification_time =
2438         ((uint16_t) hour << 11) |
2439         ((uint16_t) min << 5) |
2440         ((uint16_t) sec >> 1) ;
2441 }
2442 #endif
2443
2444 /**
2445  * \ingroup fat_fs
2446  * Returns the amount of total storage capacity of the filesystem in bytes.
2447  *
2448  * \param[in] fs The filesystem on which to operate.
2449  * \returns 0 on failure, the filesystem size in bytes otherwise.
2450  */
2451 offset_t fat_get_fs_size(const struct fat_fs_struct* fs)
2452 {
2453     if(!fs)
2454         return 0;
2455
2456 #if FAT_FAT32_SUPPORT
2457     if(fs->partition->type == PARTITION_TYPE_FAT32)
2458         return (offset_t) (fs->header.fat_size / 4 - 2) * fs->header.cluster_size;
2459     else
2460 #endif
2461         return (offset_t) (fs->header.fat_size / 2 - 2) * fs->header.cluster_size;
2462 }
2463
2464 /**
2465  * \ingroup fat_fs
2466  * Returns the amount of free storage capacity on the filesystem in bytes.
2467  *
2468  * \note As the FAT filesystem is cluster based, this function does not
2469  *       return continuous values but multiples of the cluster size.
2470  *
2471  * \param[in] fs The filesystem on which to operate.
2472  * \returns 0 on failure, the free filesystem space in bytes otherwise.
2473  */
2474 offset_t fat_get_fs_free(const struct fat_fs_struct* fs)
2475 {
2476     if(!fs)
2477         return 0;
2478
2479     uint8_t fat[32];
2480     struct fat_usage_count_callback_arg count_arg;
2481     count_arg.cluster_count = 0;
2482     count_arg.buffer_size = sizeof(fat);
2483
2484     offset_t fat_offset = fs->header.fat_offset;
2485     uint32_t fat_size = fs->header.fat_size;
2486     while(fat_size > 0)
2487     {
2488         uintptr_t length = UINTPTR_MAX - 1;
2489         if(fat_size < length)
2490             length = fat_size;
2491
2492         if(!fs->partition->device_read_interval(fat_offset,
2493                                                 fat,
2494                                                 sizeof(fat),
2495                                                 length,
2496 #if FAT_FAT32_SUPPORT
2497                                                 (fs->partition->type == PARTITION_TYPE_FAT16) ?
2498                                                     fat_get_fs_free_16_callback :
2499                                                     fat_get_fs_free_32_callback,
2500 #else
2501                                                 fat_get_fs_free_16_callback,
2502 #endif
2503                                                 &count_arg
2504                                                )
2505           )
2506             return 0;
2507
2508         fat_offset += length;
2509         fat_size -= length;
2510     }
2511
2512     return (offset_t) count_arg.cluster_count * fs->header.cluster_size;
2513 }
2514
2515 /**
2516  * \ingroup fat_fs
2517  * Callback function used for counting free clusters in a FAT.
2518  */
2519 uint8_t fat_get_fs_free_16_callback(uint8_t* buffer, offset_t offset, void* p)
2520 {
2521     struct fat_usage_count_callback_arg* count_arg = (struct fat_usage_count_callback_arg*) p;
2522     uintptr_t buffer_size = count_arg->buffer_size;
2523
2524     (void)offset;
2525
2526     for(uintptr_t i = 0; i < buffer_size; i += 2, buffer += 2)
2527     {
2528         uint16_t cluster = read16(buffer);
2529         if(cluster == HTOL16(FAT16_CLUSTER_FREE))
2530             ++(count_arg->cluster_count);
2531     }
2532
2533     return 1;
2534 }
2535
2536 #if DOXYGEN || FAT_FAT32_SUPPORT
2537 /**
2538  * \ingroup fat_fs
2539  * Callback function used for counting free clusters in a FAT32.
2540  */
2541 uint8_t fat_get_fs_free_32_callback(uint8_t* buffer, offset_t offset, void* p)
2542 {
2543     struct fat_usage_count_callback_arg* count_arg = (struct fat_usage_count_callback_arg*) p;
2544     uintptr_t buffer_size = count_arg->buffer_size;
2545
2546     (void)offset;
2547
2548     for(uintptr_t i = 0; i < buffer_size; i += 4, buffer += 4)
2549     {
2550         uint32_t cluster = read32(buffer);
2551         if(cluster == HTOL32(FAT32_CLUSTER_FREE))
2552             ++(count_arg->cluster_count);
2553     }
2554
2555     return 1;
2556 }
2557 #endif
2558