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