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