Contiki-Inga 3.x
cfs-fat.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Institute of Operating Systems and Computer Networks (TU Braunschweig).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * Author: Christoph Peltz <peltz@ibr.cs.tu-bs.de>
30  */
31 
32 /**
33  * \addtogroup cfs
34  * @{
35  */
36 
37 /**
38  * \addtogroup fat_driver
39  * @{
40  */
41 
42 /**
43  * \file
44  * FAT driver implementation
45  * \author
46  * Christoph Peltz <peltz@ibr.cs.tu-bs.de>
47  * Enrico Joerns <joerns@ibr.cs.tu-bs.de>
48  */
49 
50 #include "cfs-fat.h"
51 
52 #ifndef CFS_FAT_DEBUG
53 #define CFS_FAT_DEBUG 1
54 #endif
55 #if CFS_FAT_DEBUG > 0
56 #include <stdio.h>
57 #define PRINTERROR(...) printf(__VA_ARGS__)
58 #else
59 #define PRINTERROR(...)
60 #endif
61 #if CFS_FAT_DEBUG > 1
62 #define PRINTDEBUG(...) printf(__VA_ARGS__)
63 #else
64 #define PRINTDEBUG(...)
65 #endif
66 #if CFS_FAT_DEBUG > 2
67 #define PRINTF(...) printf(__VA_ARGS__)
68 #else
69 #define PRINTF(...)
70 #endif
71 
72 #define ATTR_READ_ONLY 0x01
73 #define ATTR_HIDDEN 0x02
74 #define ATTR_SYSTEM 0x04
75 #define ATTR_VOLUME_ID 0x08
76 #define ATTR_DIRECTORY 0x10
77 #define ATTR_ARCHIVE 0x20
78 #define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
79 
80 #define FAT_FLAG_FREE 0x00
81 #define FAT_FLAG_DELETED 0xE5
82 
83 uint8_t sector_buffer[512];
84 uint32_t sector_buffer_addr = 0;
85 uint8_t sector_buffer_dirty = 0;
86 
87 uint16_t cfs_readdir_offset = 0;
88 
89 struct file_system {
90  struct diskio_device_info *dev;
91  struct FAT_Info info;
92  uint32_t first_data_sector;
93 } mounted; // TODO: volume?
94 
95 #define CLUSTER_TO_SECTOR(cluster_num) (((cluster_num - 2) * mounted.info.BPB_SecPerClus) + mounted.first_data_sector)
96 #define SECTOR_TO_CLUSTER(sector_num) (((sector_num - mounted.first_data_sector) / mounted.info.BPB_SecPerClus) + 2)
97 
98 struct PathResolver {
99  uint16_t start, end;
100  const char *path;
101  char name[11];
102 };
103 
104 struct file fat_file_pool[FAT_FD_POOL_SIZE];
105 struct file_desc fat_fd_pool[FAT_FD_POOL_SIZE];
106 
107 #ifdef FAT_COOPERATIVE
108 #include "fat_coop.h"
109 extern void coop_switch_sp();
110 extern uint8_t coop_step_allowed;
111 extern uint8_t next_step_type;
112 
113 enum {
114  READ = 1,
115  WRITE,
116  INTERNAL
117 };
118 
119 extern QueueEntry queue[FAT_COOP_QUEUE_SIZE];
120 extern uint16_t queue_start, queue_len;
121 #endif
122 
123 /* Declerations */
124 static uint8_t is_EOC(uint32_t fat_entry);
125 static uint32_t get_free_cluster(uint32_t start_cluster);
126 static uint16_t _get_free_cluster_16();
127 static uint16_t _get_free_cluster_32();
128 static uint32_t find_nth_cluster(uint32_t start_cluster, uint32_t n);
129 static void reset_cluster_chain(struct dir_entry *dir_ent);
130 static void add_cluster_to_file(int fd);
131 static uint32_t read_fat_entry(uint32_t cluster_num);
132 static void write_fat_entry(uint32_t cluster_num, uint32_t value);
133 static void calc_fat_block(uint32_t cur_cluster, uint32_t *fat_sec_num, uint32_t *ent_offset);
134 static uint8_t _make_valid_name(const char *path, uint8_t start, uint8_t end, char *name);
135 static void pr_reset(struct PathResolver *rsolv);
136 static uint8_t pr_get_next_path_part(struct PathResolver *rsolv);
137 static uint8_t pr_is_current_path_part_a_file(struct PathResolver *rsolv);
138 static uint8_t read_sector(uint32_t sector_addr);
139 static uint8_t read_next_sector();
140 static uint8_t lookup(const char *name, struct dir_entry *dir_entry, uint32_t *dir_entry_sector, uint16_t *dir_entry_offset);
141 static uint8_t get_dir_entry(const char *path, struct dir_entry *dir_ent, uint32_t *dir_entry_sector, uint16_t *dir_entry_offset, uint8_t create);
142 static uint8_t add_directory_entry_to_current(struct dir_entry *dir_ent, uint32_t *dir_entry_sector, uint16_t *dir_entry_offset);
143 static void update_dir_entry(int fd);
144 static void remove_dir_entry(uint32_t dir_entry_sector, uint16_t dir_entry_offset);
145 static uint8_t load_next_sector_of_file(int fd, uint32_t clusters, uint8_t clus_offset, uint8_t write);
146 static void make_readable_entry(struct dir_entry *dir, struct cfs_dirent *dirent);
147 static uint8_t _is_file(struct dir_entry *dir_ent);
148 static uint8_t _cfs_flags_ok(int flags, struct dir_entry *dir_ent);
149 static int fat_read_write(int fd, const void *buf, unsigned int len, unsigned char write);
150 /*----------------------------------------------------------------------------*/
151 /* Checks if the given fat entry is EOC (end of clusterchain)
152  * returns 1 for true, 0 for false
153  */
154 static uint8_t
155 is_EOC(uint32_t fat_entry)
156 {
157  if (mounted.info.type == FAT16) {
158  if (fat_entry >= 0xFFF8) {
159  return 1;
160  }
161 
162  } else if (mounted.info.type == FAT32) {
163  if ((fat_entry & 0x0FFFFFFF) >= 0x0FFFFFF8) {
164  return 1;
165  }
166  }
167  return 0;
168 }
169 /*----------------------------------------------------------------------------*/
170 /**
171  * \brief Looks through the FAT to find a free cluster. Sets the sector adress pointer to the start
172  * of the new cluster.
173  *
174  * \TODO Check for end of FAT and no free clusters.
175  * \param start_cluster cluster number to start for searching
176  * \return Returns the number of a free cluster.
177  */
178 static uint32_t
179 get_free_cluster(uint32_t start_cluster)
180 {
181  uint32_t fat_sec_num = 0;
182  uint32_t ent_offset = 0;
183  uint16_t i = 0;
184 
185  /* calculate sector to start search from */
186  calc_fat_block(start_cluster, &fat_sec_num, &ent_offset);
187 
188  /* iterate over fat sectors until free sector found */
189  do {
190  // printf("\nfat_sec_num: %lu", fat_sec_num);
191  if (read_sector(fat_sec_num) != 0) {
192  PRINTERROR("\nERROR: read_sector() failed!");
193  fat_sec_num++;
194  continue;
195  }
196  if (mounted.info.type == FAT16) {
197  i = _get_free_cluster_16();
198  } else if (mounted.info.type == FAT32) {
199  i = _get_free_cluster_32();
200  }
201  fat_sec_num++;
202  } while (i == 512);
203 
204  ent_offset = ((fat_sec_num - 1) - mounted.info.BPB_RsvdSecCnt) * mounted.info.BPB_BytesPerSec + i;
205  if (mounted.info.type == FAT16) {
206  ent_offset /= 2;
207  } else if (mounted.info.type == FAT32) {
208  ent_offset /= 4;
209  }
210 
211  PRINTF("\nfat.c: get_free_cluster(start_cluster = %lu) = %lu", start_cluster, ent_offset);
212  return ent_offset;
213 }
214 /*----------------------------------------------------------------------------*/
215 static uint16_t
216 _get_free_cluster_16()
217 {
218  uint16_t entry = 0;
219  uint16_t i = 0;
220 
221  for (i = 0; i < 512; i += 2) {
222  entry = (((uint16_t) sector_buffer[i]) << 8) + ((uint16_t) sector_buffer[i + 1]);
223  if (entry == 0) {
224  return i;
225  }
226  }
227 
228  return 512;
229 }
230 /*----------------------------------------------------------------------------*/
231 /**
232  * Iterates over currently loaded (FAT) sector and searches for free cluster.
233  * \return 0,4,...,511: cluster number offset relative to current fat sector,
234  * 512: no free cluster found
235  */
236 static uint16_t
237 _get_free_cluster_32()
238 {
239  uint32_t entry = 0;
240  uint16_t i = 0;
241 
242  // TODO check...
243  //if (sector_buffer_addr > data start sector) .... ERROR
244 
245  for (i = 0; i < 512; i += 4) {
246  entry = (((uint32_t) sector_buffer[i + 3]) << 24) + (((uint32_t) sector_buffer[i + 2]) << 16) + (((uint32_t) sector_buffer[i + 1]) << 8) + ((uint32_t) sector_buffer[i]);
247 
248  if ((entry & 0x0FFFFFFF) == 0) {
249  return i;
250  }
251  }
252 
253  return 512;
254 }
255 /*----------------------------------------------------------------------------*/
256 /* With a given start cluster it looks for the nth cluster in the corresponding chain
257  */
258 static uint32_t
259 find_nth_cluster(uint32_t start_cluster, uint32_t n)
260 {
261  uint32_t cluster = start_cluster,
262  i = 0;
263 
264  for (i = 0; i < n; i++) {
265  cluster = read_fat_entry(cluster);
266  }
267 
268  PRINTF("\nfat.c: find_nth_cluster( start_cluster = %lu, n = %lu ) = %lu", start_cluster, n, cluster);
269  return cluster;
270 }
271 /*----------------------------------------------------------------------------*/
272 /*
273  * Iterates over a cluster chain corresponding to a given dir entry and removes all entries.
274  */
275 static void
276 reset_cluster_chain(struct dir_entry *dir_ent)
277 {
278  uint32_t cluster = (((uint32_t) dir_ent->DIR_FstClusHI) << 16) + dir_ent->DIR_FstClusLO;
279  uint32_t next_cluster = read_fat_entry(cluster);
280 
281  while (!is_EOC(cluster) && cluster >= 2) {
282  write_fat_entry(cluster, 0L);
283  cluster = next_cluster;
284  next_cluster = read_fat_entry(cluster);
285  }
286 
287  write_fat_entry(cluster, 0L);
288 }
289 /*----------------------------------------------------------------------------*/
290 /*
291  * Searches for next free cluster to add id to the file associated with the
292  * given file descriptor.
293  */
294 static void
295 add_cluster_to_file(int fd)
296 {
297  /* get the address of any free cluster */
298  uint32_t free_cluster = get_free_cluster(0);
299  uint32_t cluster = fat_file_pool[fd].nth_cluster;
300  uint32_t n = cluster;
301  PRINTF("\nfat.c: add_cluster_to_file( fd = %d ) = void", fd);
302 
303  // if file has no cluster yet, add first
304  if (fat_file_pool[fd].cluster == 0) {
305  write_fat_entry(free_cluster, EOC);
306  fat_file_pool[fd].dir_entry.DIR_FstClusHI = (uint16_t) (free_cluster >> 16);
307  fat_file_pool[fd].dir_entry.DIR_FstClusLO = (uint16_t) (free_cluster);
308 
309  update_dir_entry(fd);
310 
311  fat_file_pool[fd].cluster = free_cluster;
312  fat_file_pool[fd].n = 0;
313  fat_file_pool[fd].nth_cluster = free_cluster;
314 
315  PRINTF("\n\tfat.c: File was empty, now has first cluster %lu added to Chain", free_cluster);
316  return;
317  }
318 
319  while (!is_EOC(n)) {
320  cluster = n;
321  n = read_fat_entry(cluster);
322  fat_file_pool[fd].n++;
323  }
324 
325  write_fat_entry(cluster, free_cluster);
326  write_fat_entry(free_cluster, EOC);
327  fat_file_pool[fd].nth_cluster = free_cluster;
328  PRINTF("\n\tfat.c: File was NOT empty, now has cluster %lu as %lu. cluster to Chain", free_cluster, fat_file_pool[fd].n);
329 }
330 /*----------------------------------------------------------------------------*/
331 /*Debug Functions*/
332 void
333 print_current_sector()
334 {
335  uint16_t i = 0;
336 
337  printf("\n");
338  for (i = 0; i < 512; i++) {
339  printf("%02x", sector_buffer[i]);
340  if (((i + 1) % 2) == 0) {
341  printf(" ");
342  }
343  if (((i + 1) % 32) == 0) {
344  printf("\n");
345  }
346  }
347 }
348 /*----------------------------------------------------------------------------*/
349 void
350 print_cluster_chain(int fd)
351 {
352  uint32_t cluster = fat_file_pool[fd].cluster;
353  printf("\nClusterchain for fd = %d\n", fd);
354  do {
355  printf("%lu ->", cluster);
356  } while (!is_EOC(cluster = read_fat_entry(cluster)));
357  printf("%lu\n", cluster);
358 }
359 /*----------------------------------------------------------------------------*/
360 void
362 {
363  printf("\nFile Info for fd = %d", fd);
364  printf("\n\toffset = %lu", fat_fd_pool[fd].offset);
365  printf("\n\tflags = %x", fat_fd_pool[fd].flags);
366  printf("\n\tfile = %p", fat_fd_pool[fd].file);
367  printf("\n\t\tcluster = %lu", fat_file_pool[fd].cluster);
368  printf("\n\t\tdir_entry_sector = %lu", fat_file_pool[fd].dir_entry_sector);
369  printf("\n\t\tdir_entry_offset = %u", fat_file_pool[fd].dir_entry_offset);
370  printf("\n\t\tnth_cluster = %lu", fat_file_pool[fd].nth_cluster);
371  printf("\n\t\tn = %lu", fat_file_pool[fd].n);
372  printf("\n\t\tdir_entry");
373  printf("\n\t\t\tDIR_Name = %c%c%c%c%c%c%c%c%c%c%c", fat_file_pool[fd].dir_entry.DIR_Name[0], fat_file_pool[fd].dir_entry.DIR_Name[1], fat_file_pool[fd].dir_entry.DIR_Name[2], fat_file_pool[fd].dir_entry.DIR_Name[3], fat_file_pool[fd].dir_entry.DIR_Name[4], fat_file_pool[fd].dir_entry.DIR_Name[5], fat_file_pool[fd].dir_entry.DIR_Name[6], fat_file_pool[fd].dir_entry.DIR_Name[7], fat_file_pool[fd].dir_entry.DIR_Name[8], fat_file_pool[fd].dir_entry.DIR_Name[9], fat_file_pool[fd].dir_entry.DIR_Name[10]);
374  printf("\n\t\t\tDIR_Attr = %x", fat_file_pool[fd].dir_entry.DIR_Attr);
375  printf("\n\t\t\tDIR_NTRes = %x", fat_file_pool[fd].dir_entry.DIR_NTRes);
376  printf("\n\t\t\tCrtTimeTenth = %x", fat_file_pool[fd].dir_entry.CrtTimeTenth);
377  printf("\n\t\t\tDIR_CrtTime = %x", fat_file_pool[fd].dir_entry.DIR_CrtTime);
378  printf("\n\t\t\tDIR_CrtDate = %x", fat_file_pool[fd].dir_entry.DIR_CrtDate);
379  printf("\n\t\t\tDIR_LstAccessDate = %x", fat_file_pool[fd].dir_entry.DIR_LstAccessDate);
380  printf("\n\t\t\tDIR_FstClusHI = %x", fat_file_pool[fd].dir_entry.DIR_FstClusHI);
381  printf("\n\t\t\tDIR_WrtTime = %x", fat_file_pool[fd].dir_entry.DIR_WrtTime);
382  printf("\n\t\t\tDIR_WrtDate = %x", fat_file_pool[fd].dir_entry.DIR_WrtDate);
383  printf("\n\t\t\tDIR_FstClusLO = %x", fat_file_pool[fd].dir_entry.DIR_FstClusLO);
384  printf("\n\t\t\tDIR_FileSize = %lu Bytes", fat_file_pool[fd].dir_entry.DIR_FileSize);
385 }
386 /*----------------------------------------------------------------------------*/
387 void
389 {
390  printf("\nDirectory Entry");
391  printf("\n\tDIR_Name = %c%c%c%c%c%c%c%c%c%c%c", dir_entry->DIR_Name[0], dir_entry->DIR_Name[1], dir_entry->DIR_Name[2], dir_entry->DIR_Name[3], dir_entry->DIR_Name[4], dir_entry->DIR_Name[5], dir_entry->DIR_Name[6], dir_entry->DIR_Name[7], dir_entry->DIR_Name[8], dir_entry->DIR_Name[9], dir_entry->DIR_Name[10]);
392  printf("\n\tDIR_Attr = %x", dir_entry->DIR_Attr);
393  printf("\n\tDIR_NTRes = %x", dir_entry->DIR_NTRes);
394  printf("\n\tCrtTimeTenth = %x", dir_entry->CrtTimeTenth);
395  printf("\n\tDIR_CrtTime = %x", dir_entry->DIR_CrtTime);
396  printf("\n\tDIR_CrtDate = %x", dir_entry->DIR_CrtDate);
397  printf("\n\tDIR_LstAccessDate = %x", dir_entry->DIR_LstAccessDate);
398  printf("\n\tDIR_FstClusHI = %x", dir_entry->DIR_FstClusHI);
399  printf("\n\tDIR_WrtTime = %x", dir_entry->DIR_WrtTime);
400  printf("\n\tDIR_WrtDate = %x", dir_entry->DIR_WrtDate);
401  printf("\n\tDIR_FstClusLO = %x", dir_entry->DIR_FstClusLO);
402  printf("\n\tDIR_FileSize = %lu Bytes", dir_entry->DIR_FileSize);
403 }
404 /*---------------------------------------------------------------------------*/
405 void
407 {
408  memcpy(info, &(mounted.info), sizeof (struct FAT_Info));
409 }
410 /*---------------------------------------------------------------------------*/
411 uint16_t
413 {
414  return fat_file_pool[fd].dir_entry.DIR_WrtDate;
415 }
416 /*---------------------------------------------------------------------------*/
417 uint16_t
419 {
420  return fat_file_pool[fd].dir_entry.DIR_WrtTime;
421 }
422 /*---------------------------------------------------------------------------*/
423 uint16_t
425 {
426  return fat_file_pool[fd].dir_entry.DIR_CrtDate;
427 }
428 /*---------------------------------------------------------------------------*/
429 uint16_t
431 {
432  return fat_file_pool[fd].dir_entry.DIR_CrtTime;
433 }
434 /*----------------------------------------------------------------------------*/
435 /* Reads the FAT entry at the position representing the given cluster number.
436  * I.e. it reads the next clusters address in a cluster chain (or EOC)
437  */
438 static uint32_t
439 read_fat_entry(uint32_t cluster_num)
440 {
441  uint32_t fat_sec_num = 0,
442  ent_offset = 0;
443 
444  calc_fat_block(cluster_num, &fat_sec_num, &ent_offset);
445  if (read_sector(fat_sec_num) != 0) {
446  PRINTERROR("\nError while reading FAT entry for cluster %ld", cluster_num);
447  return EOC;
448  }
449 
450  if (mounted.info.type == FAT16) {
451  PRINTF("\nfat.c: read_fat_entry( cluster_num = %lu ) = %lu", cluster_num, (uint32_t) (((uint16_t) sector_buffer[ent_offset + 1]) << 8) + ((uint16_t) sector_buffer[ent_offset]));
452  return (uint32_t) (((uint16_t) sector_buffer[ent_offset + 1]) << 8) + ((uint16_t) sector_buffer[ent_offset]);
453  } else if (mounted.info.type == FAT32) {
454  PRINTF("\nfat.c: read_fat_entry( cluster_num = %lu ) = %lu", cluster_num,
455  (((((uint32_t) sector_buffer[ent_offset + 3]) << 24) +
456  (((uint32_t) sector_buffer[ent_offset + 2]) << 16) +
457  (((uint32_t) sector_buffer[ent_offset + 1]) << 8) +
458  ((uint32_t) sector_buffer[ent_offset + 0]))
459  & 0x0FFFFFFF));
460  /* First read a uint32_t out of the sector_buffer (first 4 lines) and then mask the highest order bit (5th line)*/
461  return (((((uint32_t) sector_buffer[ent_offset + 3]) << 24) +
462  (((uint32_t) sector_buffer[ent_offset + 2]) << 16) +
463  (((uint32_t) sector_buffer[ent_offset + 1]) << 8) +
464  ((uint32_t) sector_buffer[ent_offset + 0]))
465  & 0x0FFFFFFF);
466  }
467 
468  PRINTF("\nfat.c: read_fat_entry( cluster_num = %lu ) = EOC", cluster_num);
469  return EOC;
470 }
471 /*----------------------------------------------------------------------------*/
472 /* Writes the given value to the table entry representing the given cluster number.
473  */
474 void
475 write_fat_entry(uint32_t cluster_num, uint32_t value)
476 {
477  uint32_t fat_sec_num = 0,
478  ent_offset = 0;
479 
480  calc_fat_block(cluster_num, &fat_sec_num, &ent_offset);
481  read_sector(fat_sec_num);
482  PRINTF("\nfat.c: write_fat_entry( cluster_num = %lu, value = %lu ) = void", cluster_num, value);
483 
484  /* Write value to sector buffer and set dirty flag (little endian) */
485  if (mounted.info.type == FAT16) {
486  sector_buffer[ent_offset + 1] = (uint8_t) (value >> 8);
487  sector_buffer[ent_offset] = (uint8_t) (value);
488  } else if (mounted.info.type == FAT32) {
489  sector_buffer[ent_offset + 3] = ((uint8_t) (value >> 24) & 0x0FFF) + (0xF000 & sector_buffer[ent_offset + 3]);
490  sector_buffer[ent_offset + 2] = (uint8_t) (value >> 16);
491  sector_buffer[ent_offset + 1] = (uint8_t) (value >> 8);
492  sector_buffer[ent_offset] = (uint8_t) (value);
493  }
494 
495  sector_buffer_dirty = 1;
496 }
497 /*----------------------------------------------------------------------------*/
498 /*
499  * For a given cluster number this rountine calculates both the
500  * corresponding fat sector number and the offset within the sector
501  */
502 static void
503 calc_fat_block(uint32_t cur_cluster, uint32_t *fat_sec_num, uint32_t *ent_offset)
504 {
505  uint32_t N = cur_cluster;
506 
507  if (mounted.info.type == FAT16) {
508  *ent_offset = N * 2;
509  } else if (mounted.info.type == FAT32) {
510  *ent_offset = N * 4;
511  }
512 
513  *fat_sec_num = mounted.info.BPB_RsvdSecCnt + (*ent_offset / mounted.info.BPB_BytesPerSec);
514  *ent_offset = *ent_offset % mounted.info.BPB_BytesPerSec;
515  PRINTF("\nfat.c: calc_fat_block( cur_cluster = %lu, *fat_sec_num = %lu, *ent_offset = %lu ) = void", cur_cluster, *fat_sec_num, *ent_offset);
516 }
517 /*----------------------------------------------------------------------------*/
518 /*Path Resolver Functions*/
519 static uint8_t
520 _make_valid_name(const char *path, uint8_t start, uint8_t end, char *name)
521 {
522  uint8_t i = 0,
523  idx = 0,
524  dot_found = 0;
525 
526  memset(name, 0x20, 11);
527 
528  //printf("\n_make_valid_name() : name = ");
529  for (i = 0, idx = 0; i < end - start; ++i, ++idx) {
530  // Part too long
531  if (idx >= 11) {
532  PRINTF("\nfat.c: _make_valid_name( path = %s, start = %u, end = %u, name = %s ) = 2", path, start, end, name);
533  return 2;
534  }
535 
536  //ignore . but jump to last 3 chars of name
537  if (path[start + i] == '.') {
538  if (dot_found) {
539  PRINTF("\nfat.c: _make_valid_name( path = %s, start = %u, end = %u, name = %s ) = 3", path, start, end, name);
540  return 3;
541  }
542 
543  idx = 7;
544  dot_found = 1;
545  continue;
546  }
547 
548  if (!dot_found && idx > 7) {
549  PRINTF("\nfat.c: _make_valid_name( path = %s, start = %u, end = %u, name = %s ) = 4", path, start, end, name);
550  return 4;
551  }
552 
553  name[idx] = toupper(path[start + i]);
554  }
555 
556  PRINTF("\nfat.c: _make_valid_name( path = %s, start = %u, end = %u, name = %s ) = 0", path, start, end, name);
557  return 0;
558 }
559 /*----------------------------------------------------------------------------*/
560 static void
561 pr_reset(struct PathResolver *rsolv)
562 {
563  rsolv->start = 0;
564  rsolv->end = 0;
565  rsolv->path = NULL;
566  memset(rsolv->name, '\0', 11);
567 }
568 /*----------------------------------------------------------------------------*/
569 static uint8_t
570 pr_get_next_path_part(struct PathResolver *rsolv)
571 {
572  uint16_t i = 0;
573 
574  if (rsolv->path == NULL) {
575  return 2;
576  }
577 
578  rsolv->start = rsolv->end;
579  rsolv->end++;
580  if (rsolv->path[rsolv->start] == '/') {
581  rsolv->start++;
582  }
583 
584  for (i = rsolv->start; rsolv->path[i] != '\0'; i++) {
585  if (rsolv->path[i] != '/') {
586  rsolv->end++;
587  }
588 
589  if (rsolv->path[rsolv->end] == '/' || rsolv->path[rsolv->end] == '\0') {
590  return _make_valid_name(rsolv->path, rsolv->start, rsolv->end, rsolv->name);
591  }
592  }
593 
594  return 1;
595 }
596 /*----------------------------------------------------------------------------*/
597 static uint8_t
598 pr_is_current_path_part_a_file(struct PathResolver *rsolv)
599 {
600  if (rsolv->path[rsolv->end] == '/') {
601  return 0;
602  } else if (rsolv->path[rsolv->end] == '\0') {
603  return 1;
604  }
605 
606  return 0;
607 }
608 /*----------------------------------------------------------------------------*/
609 /*Sector Buffer Functions*/
610 /**
611  * Writes the current buffered block back to the disk if it was changed.
612  */
613 void
615 {
616  if (!sector_buffer_dirty) {
617  return;
618  }
619 
620 #ifdef FAT_COOPERATIVE
621  if (!coop_step_allowed) {
622  next_step_type = WRITE;
623  coop_switch_sp();
624  } else {
625  coop_step_allowed = 0;
626  }
627 #endif
628 
629  PRINTF("\nfat.c: fat_flush(): Flushing sector %lu", sector_buffer_addr);
630  if (diskio_write_block(mounted.dev, sector_buffer_addr, sector_buffer) != DISKIO_SUCCESS) {
631  PRINTERROR("\nfat.c: fat_flush(): DiskIO-Error occured");
632  }
633 
634  sector_buffer_dirty = 0;
635 }
636 /*----------------------------------------------------------------------------*/
637 /* Reads sector at given address.
638  * If sector is already loaded, this version is used.
639  * If sector is not loaded, previous sector is flushed and new sector is loaded
640  * from medium.
641  */
642 static uint8_t
643 read_sector(uint32_t sector_addr)
644 {
645  if (sector_buffer_addr == sector_addr && sector_addr != 0) {
646  PRINTF("\nfat.c: fat_read_sector( sector_addr = 0x%lX ) = 0", sector_addr);
647  return 0;
648  }
649 
650  cfs_fat_flush();
651 
652  sector_buffer_addr = sector_addr;
653 
654 #ifdef FAT_COOPERATIVE
655  if (!coop_step_allowed) {
656  next_step_type = READ;
657  coop_switch_sp();
658  } else {
659  coop_step_allowed = 0;
660  }
661 #endif
662 
663  if (diskio_read_block(mounted.dev, sector_addr, sector_buffer) != 0) {
664  PRINTERROR("\nfat.c: Error while reading sector 0x%lX", sector_addr);
665  sector_buffer_addr = 0;
666  return 1;
667  }
668 
669  PRINTF("\nfat.c: read_sector( sector_addr = 0x%lX ) = 0", sector_addr);
670  return 0;
671 }
672 /*----------------------------------------------------------------------------*/
673 /** Loads the next sector of current sector_buffer_addr.
674  * \return
675  * Returns 0 if sector could be read
676  * If this was the last sector in a cluster chain, it returns error code 128.
677  */
678 static uint8_t
679 read_next_sector()
680 {
681  PRINTF("\nread_next_sector()");
682  cfs_fat_flush();
683 
684  /* To restore start sector buffer address if reading next sector failed. */
685  uint32_t save_sbuff_addr = sector_buffer_addr;
686  /* Are we on a Cluster edge? */
687  if ((sector_buffer_addr - mounted.first_data_sector + 1) % mounted.info.BPB_SecPerClus == 0) {
688  PRINTDEBUG("\nCluster end, trying to load next");
689  /* We need to change the cluster, for this we have to read the FAT entry corresponding to the current sector number */
690  uint32_t entry = read_fat_entry(SECTOR_TO_CLUSTER(sector_buffer_addr));
691  /* If the returned entry is an End Of Clusterchain, return error code 128 */
692  if (is_EOC(entry)) {
693  PRINTDEBUG("\nis_EOC! (%ld)", sector_buffer_addr);
694  /* Restore previous sector adress. */
695  read_sector(save_sbuff_addr);
696  return 128;
697  }
698 
699  /* The entry is valid and we calculate the first sector number of this new cluster and read it */
700  return read_sector(CLUSTER_TO_SECTOR(entry));
701  } else {
702  /* We are still inside a cluster, so we only need to read the next sector */
703  return read_sector(sector_buffer_addr + 1);
704  }
705 }
706 /*----------------------------------------------------------------------------*/
707 /*Mount related Functions*/
708 /*----------------------------------------------------------------------------*/
709 /**
710  * Parses the Bootsector of a FAT-Filesystem and validates it.
711  *
712  * \param buffer One sector of the filesystem, must be at least 512 Bytes long.
713  * \param info The FAT_Info struct which gets populated with the FAT information.
714  * \return <ul>
715  * <li> 0 : Bootsector seems okay.
716  * <li> 1 : BPB_BytesPerSec is not a power of 2
717  * <li> 2 : BPB_SecPerClus is not a power of 2
718  * <li> 4 : Bytes per Cluster is more than 32K
719  * <li> 8 : More than 2 FATs (not supported)
720  * <li> 16: BPB_TotSec is 0
721  * <li> 32: BPB_FATSz is 0
722  * <li> 64: FAT Signature isn't correct
723  * </ul>
724  * More than one error flag may be set but return is 0 on no error.
725  */
726 static uint8_t
727 parse_bootsector(uint8_t *buffer, struct FAT_Info *info)
728 {
729  int ret = 0;
730 
731  info->BPB_BytesPerSec = (((uint16_t) buffer[12]) << 8) + buffer[11];
732  info->BPB_SecPerClus = buffer[13];
733  info->BPB_RsvdSecCnt = buffer[14] + (((uint16_t) buffer[15]) << 8);
734  info->BPB_NumFATs = buffer[16];
735  info->BPB_RootEntCnt = buffer[17] + (((uint16_t) buffer[18]) << 8);
736  info->BPB_TotSec = buffer[19] + (((uint16_t) buffer[20]) << 8);
737  if (info->BPB_TotSec == 0) {
738  info->BPB_TotSec = buffer[32] +
739  (((uint32_t) buffer[33]) << 8) +
740  (((uint32_t) buffer[34]) << 16) +
741  (((uint32_t) buffer[35]) << 24);
742  }
743 
744  info->BPB_Media = buffer[21];
745  info->BPB_FATSz = buffer[22] + (((uint16_t) buffer[23]) << 8);
746  if (info->BPB_FATSz == 0) {
747  info->BPB_FATSz = buffer[36] +
748  (((uint32_t) buffer[37]) << 8) +
749  (((uint32_t) buffer[38]) << 16) +
750  (((uint32_t) buffer[39]) << 24);
751  }
752 
753  info->BPB_RootClus = buffer[44] +
754  (((uint32_t) buffer[45]) << 8) +
755  (((uint32_t) buffer[46]) << 16) +
756  (((uint32_t) buffer[47]) << 24);
757 
758  // do we have a FAT12/16 string at pos 54?
759  if ((buffer[54] == 'F') && (buffer[55] == 'A') && (buffer[56] == 'T')) {
760  // check if FAT12 or FAT16
761  if (buffer[58] == '2') {
762  info->type = FAT12;
763  } else if (buffer[58] == '6') {
764  info->type = FAT16;
765  } else {
766  info->type = FAT_INVALID;
767  }
768  // otherwise check for FAT32 at pos 58
769  } else if ((buffer[82] == 'F') && (buffer[83] == 'A') && (buffer[84] == 'T')) {
770  info->type = FAT32;
771  } else {
772  info->type = FAT_INVALID;
773  }
774 
775  if (is_a_power_of_2(info->BPB_BytesPerSec) != 0) {
776  ret += 1;
777  }
778 
779  if (is_a_power_of_2(info->BPB_SecPerClus) != 0) {
780  ret += 2;
781  }
782 
783  if (info->BPB_BytesPerSec * info->BPB_SecPerClus > 32 * ((uint32_t) 1024)) {
784  ret += 4;
785  }
786 
787  if (info->BPB_NumFATs > 2) {
788  ret += 8;
789  }
790 
791  if (info->BPB_TotSec == 0) {
792  ret += 16;
793  }
794 
795  if (info->BPB_FATSz == 0) {
796  ret += 32;
797  }
798 
799  if (buffer[510] != 0x55 || buffer[511] != 0xaa) {
800  ret += 64;
801  }
802 
803  return ret;
804 }
805 /*----------------------------------------------------------------------------*/
806 #define DIR_ENTRY_SIZE 32
807 uint8_t
809 {
810  uint32_t RootDirSectors = 0;
811 
812  if (mounted.dev != 0) {
814  }
815 
816  //read first sector into buffer
817  diskio_read_block(dev, 0, sector_buffer);
818 
819  //parse bootsector
820  if (parse_bootsector(sector_buffer, &(mounted.info)) != 0) {
821  return 1;
822  }
823 
824  //return 2 if unsupported
825  if (mounted.info.type != FAT16 && mounted.info.type != FAT32) {
826  return 2;
827  }
828 
829  mounted.dev = dev;
830 
831  //sync every FAT to the first on mount
832  //Addendum: Takes so frigging long to do that
833  //fat_sync_fats();
834 
835  //Calculated the first_data_sector (Note: BPB_RootEntCnt is 0 for FAT32)
836  RootDirSectors = ((mounted.info.BPB_RootEntCnt * DIR_ENTRY_SIZE) + (mounted.info.BPB_BytesPerSec - 1)) / mounted.info.BPB_BytesPerSec;
837  mounted.first_data_sector = mounted.info.BPB_RsvdSecCnt + (mounted.info.BPB_NumFATs * mounted.info.BPB_FATSz) + RootDirSectors;
838 
839  return 0;
840 }
841 /*----------------------------------------------------------------------------*/
842 void
844 {
845  uint8_t i = 0;
846 
847  // Write last buffer
848  cfs_fat_flush();
849 
850 #if FAT_SYNC
851  // Write second FAT
853 #endif
854 
855  // invalidate file-descriptors
856  for (i = 0; i < FAT_FD_POOL_SIZE; i++) {
857  fat_fd_pool[i].file = 0;
858  }
859 
860  // Reset the device pointer and sector buffer
861  mounted.dev = 0;
862  sector_buffer_addr = 0;
863 }
864 /*----------------------------------------------------------------------------*/
865 /*CFS frontend functions*/
866 int
867 cfs_open(const char *name, int flags)
868 {
869  // get FileDescriptor
870  int fd = -1;
871  uint8_t i = 0;
872  struct dir_entry dir_ent;
873  PRINTF("\nfat.c: cfs_open( name = %s, flags = %x) = ?", name, flags);
874 
875 #ifndef FAT_COOPERATIVE
876  for (i = 0; i < FAT_FD_POOL_SIZE; i++) {
877  if (fat_fd_pool[i].file == 0) {
878  fd = i;
879  break;
880  }
881  }
882 
883  /*No free FileDesciptors available*/
884  if (fd == -1) {
885  PRINTF("\nfat.c: cfs_open(): No free FileDescriptors available!");
886  return fd;
887  }
888 #else /* !FAT_COOPERATIVE */
889  fd = queue[queue_start].ret_value;
890 #endif /* !FAT_COOPERATIVE */
891 
892  /* Reset entry for overwriting */
893  if (flags & CFS_WRITE) {
894  cfs_remove(name);
895  }
896 
897  // find file on Disk
898  if (!get_dir_entry(name, &dir_ent, &fat_file_pool[fd].dir_entry_sector, &fat_file_pool[fd].dir_entry_offset, (flags & CFS_WRITE) || (flags & CFS_APPEND))) {
899  PRINTF("\nfat.c: cfs_open(): Could not fetch the directory entry!");
900  return -1;
901  }
902 
903  if (!_is_file(&dir_ent)) {
904  PRINTF("\nfat.c: cfs_open(): Directory entry is not a file!");
905  return -1;
906  }
907 
908  if (!_cfs_flags_ok(flags, &dir_ent)) {
909  PRINTF("\nfat.c: cfs_open(): Invalid flags!!");
910  return -1;
911  }
912 
913  fat_file_pool[fd].cluster = dir_ent.DIR_FstClusLO + (((uint32_t) dir_ent.DIR_FstClusHI) << 16);
914  fat_file_pool[fd].nth_cluster = fat_file_pool[fd].cluster;
915  fat_file_pool[fd].n = 0;
916  fat_fd_pool[fd].file = &(fat_file_pool[fd]);
917  fat_fd_pool[fd].flags = (uint8_t) flags;
918 
919  // put read/write position in the right spot
920  fat_fd_pool[fd].offset = 0;
921  memcpy(&(fat_file_pool[fd].dir_entry), &dir_ent, sizeof (struct dir_entry));
922 
923  if (flags & CFS_APPEND) {
924  PRINTF("\nfat.c: cfs_open(): Seek to end of file (APPEND)!");
925  cfs_seek(fd, 0, CFS_SEEK_END);
926  }
927 
928  // return FileDescriptor
929  PRINTF("\nfat.c: cfs_open( name = %s, flags = %x) = %d", name, flags, fd);
930  return fd;
931 }
932 /*----------------------------------------------------------------------------*/
933 void
934 cfs_close(int fd)
935 {
936  if (fd < 0 || fd >= FAT_FD_POOL_SIZE) {
937  PRINTERROR("\nfat.c: cfs_close: Invalid fd");
938  return;
939  }
940 
941  if (fat_fd_pool[fd].file == NULL) {
942  PRINTERROR("\nfat.c: cfs_close: file not found\n");
943  return;
944  }
945 
946  update_dir_entry(fd);
947  cfs_fat_flush(fd);
948  fat_fd_pool[fd].file = NULL;
949 }
950 /*----------------------------------------------------------------------------*/
951 int
952 cfs_read(int fd, void *buf, unsigned int len)
953 {
954 
955  /* validate file pointer and read flag */
956  if ((fd < 0 || fd >= FAT_FD_POOL_SIZE) || (!(fat_fd_pool[fd].flags & CFS_READ))) {
957  return -1;
958  }
959 
960  return fat_read_write(fd, buf, len, 0);
961 }
962 /*----------------------------------------------------------------------------*/
963 int
964 cfs_write(int fd, const void *buf, unsigned int len)
965 {
966  return fat_read_write(fd, buf, len, 1);
967 }
968 /*----------------------------------------------------------------------------*/
969 static int
970 fat_read_write(int fd, const void *buf, unsigned int len, unsigned char write)
971 {
972  /* offset within sector [bytes] */
973  uint16_t offset = fat_fd_pool[fd].offset % (uint32_t) mounted.info.BPB_BytesPerSec;
974  /* cluster offset */
975  uint32_t clusters = (fat_fd_pool[fd].offset / mounted.info.BPB_BytesPerSec) / mounted.info.BPB_SecPerClus;
976  /* offset within cluster [sectors] */
977  uint8_t clus_offset = (fat_fd_pool[fd].offset / mounted.info.BPB_BytesPerSec) % mounted.info.BPB_SecPerClus;
978  uint16_t i, j = 0;
979  uint8_t *buffer = (uint8_t *) buf;
980 
981  /* For read acces, check file length. */
982  if (write == 0) {
983  uint32_t size_left = fat_file_pool[fd].dir_entry.DIR_FileSize - fat_fd_pool[fd].offset;
984 
985  /* limit len to remaining file length */
986  if (size_left < len) {
987  len = size_left;
988  }
989 
990  /* Special case of empty file (cluster is zero) or zero length to read */
991  if ((fat_file_pool[fd].cluster == 0) || (len == 0)) {
992  PRINTDEBUG("Empty cluster or zero file size");
993  return 0;
994  }
995  }
996 
997  while (load_next_sector_of_file(fd, clusters, clus_offset, write) == 0) {
998  PRINTF("\nfat.c: cfs_write(): Writing in sector %lu", sector_buffer_addr);
999  for (i = offset; i < mounted.info.BPB_BytesPerSec && j < len; i++, j++, fat_fd_pool[fd].offset++) {
1000  if (write) {
1001 #ifndef FAT_COOPERATIVE
1002  sector_buffer[i] = buffer[j];
1003 #else
1004  sector_buffer[i] = get_item_from_buffer(buffer, j);
1005 #endif
1006  /* Enlarge file size if required */
1007  if (fat_fd_pool[fd].offset == fat_file_pool[fd].dir_entry.DIR_FileSize) {
1008  fat_file_pool[fd].dir_entry.DIR_FileSize++;
1009  } else if (fat_fd_pool[fd].offset > fat_file_pool[fd].dir_entry.DIR_FileSize) {
1010  fat_file_pool[fd].dir_entry.DIR_FileSize = fat_fd_pool[fd].offset;
1011  }
1012  } else {/* read */
1013  buffer[j] = sector_buffer[i];
1014  }
1015  }
1016 
1017  if (write) {
1018  sector_buffer_dirty = 1;
1019  }
1020 
1021  offset = 0;
1022  clus_offset = (clus_offset + 1) % mounted.info.BPB_SecPerClus;
1023  if (clus_offset == 0) {
1024  clusters++;
1025  }
1026 
1027  if (j >= len) {
1028  break;
1029  }
1030  }
1031 
1032  return j;
1033 }
1034 /*----------------------------------------------------------------------------*/
1035 cfs_offset_t
1036 cfs_seek(int fd, cfs_offset_t offset, int whence)
1037 {
1038  if (fd < 0 || fd >= FAT_FD_POOL_SIZE) {
1039  return -1;
1040  }
1041 
1042  switch (whence) {
1043  case CFS_SEEK_SET:
1044  fat_fd_pool[fd].offset = offset;
1045  break;
1046  case CFS_SEEK_CUR:
1047  fat_fd_pool[fd].offset += offset;
1048  break;
1049  case CFS_SEEK_END:
1050  fat_fd_pool[fd].offset = (fat_file_pool[fd].dir_entry.DIR_FileSize - 1) + offset;
1051  break;
1052  default:
1053  break;
1054  }
1055 
1056  if (fat_fd_pool[fd].offset >= fat_file_pool[fd].dir_entry.DIR_FileSize) {
1057  fat_fd_pool[fd].offset = (fat_file_pool[fd].dir_entry.DIR_FileSize - 1);
1058  }
1059 
1060  if (fat_fd_pool[fd].offset < 0) {
1061  fat_fd_pool[fd].offset = 0;
1062  }
1063 
1064  return fat_fd_pool[fd].offset;
1065 }
1066 /*----------------------------------------------------------------------------*/
1067 int
1068 cfs_remove(const char *name)
1069 {
1070  struct dir_entry dir_ent;
1071  uint32_t sector;
1072  uint16_t offset;
1073 
1074  if (!get_dir_entry(name, &dir_ent, &sector, &offset, 0)) {
1075  return -1;
1076  }
1077 
1078  if (_is_file(&dir_ent)) {
1079  reset_cluster_chain(&dir_ent);
1080  remove_dir_entry(sector, offset);
1081  cfs_fat_flush();
1082  return 0;
1083  }
1084 
1085  return -1;
1086 }
1087 /*----------------------------------------------------------------------------*/
1088 int
1089 cfs_opendir(struct cfs_dir *dirp, const char *name)
1090 {
1091  struct dir_entry dir_ent;
1092  uint32_t sector;
1093  uint16_t offset;
1094  uint32_t dir_cluster = get_dir_entry(name, &dir_ent, &sector, &offset, 0);
1095 
1096  cfs_readdir_offset = 0;
1097 
1098  if (dir_cluster == 0) {
1099  return -1;
1100  }
1101 
1102  memcpy(dirp, &dir_ent, sizeof (struct dir_entry));
1103  return 0;
1104 }
1105 /*----------------------------------------------------------------------------*/
1106 int
1107 cfs_readdir(struct cfs_dir *dirp, struct cfs_dirent *dirent)
1108 {
1109  struct dir_entry *dir_ent = (struct dir_entry *) dirp;
1110  struct dir_entry entry;
1111 
1112  { /* Get the next directory_entry */
1113  uint32_t dir_off = cfs_readdir_offset * 32;
1114  uint16_t cluster_num = dir_off / mounted.info.BPB_SecPerClus;
1115  uint32_t cluster;
1116 
1117  cluster = find_nth_cluster((((uint32_t) dir_ent->DIR_FstClusHI) << 16) + dir_ent->DIR_FstClusLO, (uint32_t) cluster_num);
1118  if (cluster == 0) {
1119  return -1;
1120  }
1121 
1122  if (read_sector(CLUSTER_TO_SECTOR(cluster) + dir_off / mounted.info.BPB_BytesPerSec) != 0) {
1123  return -1;
1124  }
1125 
1126  memcpy(&entry, &(sector_buffer[dir_off % mounted.info.BPB_BytesPerSec]), sizeof (struct dir_entry));
1127  }
1128 
1129  make_readable_entry(&entry, dirent);
1130  dirent->size = entry.DIR_FileSize;
1131  cfs_readdir_offset++;
1132  return 0;
1133 }
1134 /*----------------------------------------------------------------------------*/
1135 void
1136 cfs_closedir(struct cfs_dir *dirp)
1137 {
1138  cfs_readdir_offset = 0;
1139 }
1140 /*----------------------------------------------------------------------------*/
1141 /*Dir_entry Functions*/
1142 /**
1143  * Looks for file name starting at current sector buffer address.
1144  * \note sector buffer address must point to the sector to start search from.
1145  * \note
1146  * @param name name of the directory/file to find
1147  * @param dir_entry Pointer to directory entry to store infos about file if found
1148  * @param dir_entry_sector Pointer to variable to store sector address of found file
1149  * @param dir_entry_offset Pointer to variable to store sector address offset of found file
1150  * @return returns 0 if found, 1 if not found, 128 if end of cluster chain reached
1151  */
1152 static uint8_t
1153 lookup(const char *name, struct dir_entry *dir_entry, uint32_t *dir_entry_sector, uint16_t *dir_entry_offset)
1154 {
1155  uint16_t i = 0;
1156  PRINTF("\nfat.c: BEGIN lookup( name = %c%c%c%c%c%c%c%c%c%c%c, dir_entry = %p, *dir_entry_sector = %lu, *dir_entry_offset = %u) = ?", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10], dir_entry, *dir_entry_sector, *dir_entry_offset);
1157  for (;;) {
1158  /* iterate over all directory entries in current sector */
1159  for (i = 0; i < 512; i += 32) {
1160  PRINTF("\nfat.c: lookup(): name = %c%c%c%c%c%c%c%c%c%c%c", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10]);
1161  PRINTF("\nfat.c: lookup(): sec_buf = %c%c%c%c%c%c%c%c%c%c%c", sector_buffer[i + 0], sector_buffer[i + 1], sector_buffer[i + 2], sector_buffer[i + 3], sector_buffer[i + 4], sector_buffer[i + 5], sector_buffer[i + 6], sector_buffer[i + 7], sector_buffer[i + 8], sector_buffer[i + 9], sector_buffer[i + 10]);
1162  if (memcmp(name, &(sector_buffer[i]), 11) == 0) {
1163  memcpy(dir_entry, &(sector_buffer[i]), sizeof (struct dir_entry));
1164  *dir_entry_sector = sector_buffer_addr;
1165  *dir_entry_offset = i;
1166  PRINTF("\nfat.c: END lookup( name = %c%c%c%c%c%c%c%c%c%c%c, dir_entry = %p, *dir_entry_sector = %lu, *dir_entry_offset = %u) = 0", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10], dir_entry, *dir_entry_sector, *dir_entry_offset);
1167  return 0;
1168  }
1169 
1170  // There are no more entries in this directory
1171  if (sector_buffer[i] == FAT_FLAG_FREE) {
1172  PRINTF("\nfat.c: lookup(): No more directory entries");
1173  PRINTF("\nfat.c: END lookup( name = %c%c%c%c%c%c%c%c%c%c%c, dir_entry = %p, *dir_entry_sector = %lu, *dir_entry_offset = %u) = 1", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10], dir_entry, *dir_entry_sector, *dir_entry_offset);
1174  return 1;
1175  }
1176  }
1177 
1178  /* Read next sector */
1179  uint8_t fns;
1180  if ((fns = read_next_sector()) != 0) {
1181  PRINTF("\nfat.c: END lookup( name = %c%c%c%c%c%c%c%c%c%c%c, dir_entry = %p, *dir_entry_sector = %lu, *dir_entry_offset = %u) = 2", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10], dir_entry, *dir_entry_sector, *dir_entry_offset);
1182  return fns;
1183  }
1184  }
1185 
1186  PRINTF("\nfat.c: END lookup( name = %c%c%c%c%c%c%c%c%c%c%c, dir_entry = %p, *dir_entry_sector = %lu, *dir_entry_offset = %u) = 0", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7], name[8], name[9], name[10], dir_entry, *dir_entry_sector, *dir_entry_offset);
1187  return 0;
1188 }
1189 /*----------------------------------------------------------------------------*/
1190 /**
1191  *
1192  * @param path
1193  * @param dir_ent
1194  * @param dir_entry_sector
1195  * @param dir_entry_offset
1196  * @param create
1197  * @return
1198  */
1199 static uint8_t
1200 get_dir_entry(const char *path, struct dir_entry *dir_ent, uint32_t *dir_entry_sector, uint16_t *dir_entry_offset, uint8_t create)
1201 {
1202  uint32_t first_root_dir_sec_num = 0;
1203  uint32_t file_sector_num = 0;
1204  uint8_t i = 0;
1205  struct PathResolver pr;
1206  PRINTF("\nfat.c: get_dir_entry( path = %s, dir_ent = %p, *dir_entry_sector = %lu, *dir_entry_offset = %u, create = %u ) = ?", path, dir_ent, *dir_entry_sector, *dir_entry_offset, create);
1207 
1208  pr_reset(&pr);
1209  pr.path = path;
1210 
1211  if (mounted.info.type == FAT16) {
1212  // calculate the first cluster of the root dir
1213  first_root_dir_sec_num = mounted.info.BPB_RsvdSecCnt + (mounted.info.BPB_NumFATs * mounted.info.BPB_FATSz); // TODO Verify this is correct
1214  } else if (mounted.info.type == FAT32) {
1215  // BPB_RootClus is the first cluster of the root dir
1216  first_root_dir_sec_num = CLUSTER_TO_SECTOR(mounted.info.BPB_RootClus);
1217  }
1218  PRINTF("\nfat.c: get_dir_entry(): first_root_dir_sec_num = %lu", first_root_dir_sec_num);
1219 
1220  file_sector_num = first_root_dir_sec_num;
1221  for (i = 0; pr_get_next_path_part(&pr) == 0 && i < 255; i++) {
1222  read_sector(file_sector_num);
1223  if (lookup(pr.name, dir_ent, dir_entry_sector, dir_entry_offset) != 0) {
1224  PRINTF("\nfat.c: get_dir_entry(): Current path part doesn't exist!");
1225  if (pr_is_current_path_part_a_file(&pr) && create) {
1226  PRINTF("\nfat.c: get_dir_entry(): Current path part describes a file and it should be created!");
1227  memset(dir_ent, 0, sizeof (struct dir_entry));
1228  memcpy(dir_ent->DIR_Name, pr.name, 11);
1229  dir_ent->DIR_Attr = 0;
1230  return add_directory_entry_to_current(dir_ent, dir_entry_sector, dir_entry_offset);
1231  }
1232  return 0;
1233  }
1234  file_sector_num = CLUSTER_TO_SECTOR(dir_ent->DIR_FstClusLO + (((uint32_t) dir_ent->DIR_FstClusHI) << 16));
1235  PRINTF("\nfat.c: get_dir_entry(): file_sector_num = %lu", file_sector_num);
1236  }
1237 
1238  if (file_sector_num == first_root_dir_sec_num) {
1239  return 0;
1240  }
1241 
1242  return 1;
1243 }
1244 /*----------------------------------------------------------------------------*/
1245 /**
1246  * Tries to add dir entry starting from the sector currently in buffer.
1247  * \params dir_ent directory entry to add to directory
1248  * \params dir_entry_sector returns sector address of added dir
1249  * \params dir_entry_offset returns sector address offset of added dir
1250  * \return Returns 0 if nothing was added (failed) and 1 if adding succeeded
1251  */
1252 static uint8_t
1253 add_directory_entry_to_current(struct dir_entry *dir_ent, uint32_t *dir_entry_sector, uint16_t *dir_entry_offset)
1254 {
1255  uint16_t i = 0;
1256  uint8_t ret = 0;
1257 
1258  // TODO: security check
1259  // if (sector_buffer_addr < first data sector) ... Error, we try to write dir into FAT region...
1260 
1261  PRINTF("\nfat.c: add_directory_entry_to_current( dir_ent = %p, *dir_entry_sector = %lu, *dir_entry_offset = %u ) = ?", dir_ent, *dir_entry_sector, *dir_entry_offset);
1262  for (;;) {
1263  /* iterate over all directory entries in current sector */
1264  for (i = 0; i < 512; i += 32) {
1265  if (sector_buffer[i] == FAT_FLAG_FREE || sector_buffer[i] == FAT_FLAG_DELETED) {
1266  memcpy(&(sector_buffer[i]), dir_ent, sizeof (struct dir_entry));
1267  sector_buffer_dirty = 1;
1268  *dir_entry_sector = sector_buffer_addr;
1269  *dir_entry_offset = i;
1270  PRINTF("\nfat.c: add_directory_entry_to_current(): Found empty directory entry! *dir_entry_sector = %lu, *dir_entry_offset = %u", *dir_entry_sector, *dir_entry_offset);
1271  return 1;
1272  }
1273  }
1274 
1275  /* If no free directory entry was found, switch to next sector */
1276  PRINTF("\nfat.c: add_directory_entry_to_current(): No free entry in current sector (sector_buffer_addr = %lu) reading next sector!", sector_buffer_addr);
1277  if ((ret = read_next_sector()) != 0) {
1278  /* if end of cluster reached, get free cluster */
1279  if (ret == 128) {
1280  uint32_t last_sector = sector_buffer_addr;
1281  uint32_t free_cluster = get_free_cluster(SECTOR_TO_CLUSTER(sector_buffer_addr)); // TODO: any free cluster? start at (0)
1282  PRINTF("\nfat.c: add_directory_entry_to_current(): The directory cluster chain is too short, we need to add another cluster!");
1283 
1284  write_fat_entry(SECTOR_TO_CLUSTER(last_sector), free_cluster);
1285  write_fat_entry(free_cluster, EOC);
1286  PRINTF("\nfat.c: add_directory_entry_to_current(): cluster %lu added to chain of sector_buffer_addr cluster %lu", free_cluster, SECTOR_TO_CLUSTER(sector_buffer_addr));
1287 
1288  cfs_fat_flush();
1289  /* Iterate over all sectors in new allocated cluster and clear them. */
1290  uint32_t first_free_sector = CLUSTER_TO_SECTOR(free_cluster);
1291  memset(sector_buffer, 0x00, 512);
1292  for (i = 0; i < mounted.info.BPB_SecPerClus; i++) {
1293  sector_buffer_addr = first_free_sector + i;
1294  sector_buffer_dirty = 1;
1295  cfs_fat_flush();
1296  }
1297 
1298  if (read_sector(CLUSTER_TO_SECTOR(free_cluster)) == 0) {
1299  memcpy(&(sector_buffer[0]), dir_ent, sizeof (struct dir_entry));
1300  sector_buffer_dirty = 1;
1301  *dir_entry_sector = sector_buffer_addr;
1302  *dir_entry_offset = 0;
1303  PRINTF("\nfat.c: add_directory_entry_to_current(): read of the newly added cluster successful! *dir_entry_sector = %lu, *dir_entry_offset = %u", *dir_entry_sector, *dir_entry_offset);
1304  return 1;
1305  }
1306  }
1307  return 0;
1308  }
1309  }
1310 
1311  return 0;
1312 }
1313 /*----------------------------------------------------------------------------*/
1314 static void
1315 update_dir_entry(int fd)
1316 {
1317  PRINTF("\nfat.c: update_dir_entry( fd = %d ) = void ", fd);
1318  if (read_sector(fat_file_pool[fd].dir_entry_sector) != 0) {
1319  PRINTERROR("\nfat.c: update_dir_entry(): error reading the sector containing the directory entry");
1320  return;
1321  }
1322 
1323  memcpy(&(sector_buffer[fat_file_pool[fd].dir_entry_offset]), &(fat_file_pool[fd].dir_entry), sizeof (struct dir_entry));
1324  sector_buffer_dirty = 1;
1325 }
1326 /*----------------------------------------------------------------------------*/
1327 static void
1328 remove_dir_entry(uint32_t dir_entry_sector, uint16_t dir_entry_offset)
1329 {
1330  PRINTF("\nfat.c: remove_dir_entry( dir_entry_sector = %lu, dir_entry_offset = %u ) = void ", dir_entry_sector, dir_entry_offset);
1331  if (read_sector(dir_entry_sector) != 0) {
1332  PRINTERROR("\nfat.c: remove_dir_entry(): error reading the sector containing the directory entry");
1333  return;
1334  }
1335 
1336  memset(&(sector_buffer[dir_entry_offset]), 0, sizeof (struct dir_entry));
1337  sector_buffer[dir_entry_offset] = FAT_FLAG_DELETED;
1338  sector_buffer_dirty = 1;
1339 }
1340 /*----------------------------------------------------------------------------*/
1341 /*FAT Implementation Functions*/
1342 static uint8_t
1343 load_next_sector_of_file(int fd, uint32_t clusters, uint8_t clus_offset, uint8_t write)
1344 {
1345  uint32_t cluster = 0;
1346  PRINTF("\nfat.c: load_next_sector_of_file( fd = %d, clusters = %lu, clus_offset = %u, write = %u ) = ?", fd, clusters, clus_offset, write);
1347 
1348  //If we know the nth Cluster already we do not have to recalculate it
1349  if (clusters == fat_file_pool[fd].n) {
1350  PRINTF("\nfat.c: load_next_sector_of_file(): we know nth cluster already");
1351  cluster = fat_file_pool[fd].nth_cluster;
1352  //If we are now at the nth-1 Cluster it is easy to get the next cluster
1353  } else if (clusters == fat_file_pool[fd].n + 1) {
1354  PRINTF("\nfat.c: load_next_sector_of_file(): we need the cluster n and are at n-1");
1355  cluster = read_fat_entry(fat_file_pool[fd].nth_cluster);
1356  //Somehow our cluster-information is out of sync. We have to calculate the cluster the hard way.
1357  } else {
1358  PRINTF("\nfat.c: load_next_sector_of_file(): We are somewhere else, need to iterate the chain until nth cluster");
1359  cluster = find_nth_cluster(fat_file_pool[fd].cluster, clusters);
1360  }
1361  PRINTF("\nfat.c: load_next_sector_of_file(): fat_file_pool[%d].nth_cluster = %lu, fat_file_pool[%d].n = %lu", fd, fat_file_pool[fd].nth_cluster, fd, fat_file_pool[fd].n);
1362 
1363  // If there is no cluster allocated to the file or the current cluster is EOC then add another cluster to the file
1364  if (cluster == 0 || is_EOC(cluster)) {
1365  PRINTF("\nfat.c: load_next_sector_of_file(): Either file is empty or current cluster is EOC!");
1366  if (write) {
1367  PRINTF("\nfat.c: load_next_sector_of_file(): write flag enabled! adding cluster to file!");
1368  add_cluster_to_file(fd);
1369  // Remember that after the add_cluster_to_file-Function the nth_cluster and n is set to the added cluster
1370  cluster = fat_file_pool[fd].nth_cluster;
1371  } else {
1372  return 1;
1373  }
1374  } else {
1375  fat_file_pool[fd].nth_cluster = cluster;
1376  fat_file_pool[fd].n = clusters;
1377  }
1378 
1379  return read_sector(CLUSTER_TO_SECTOR(cluster) + clus_offset);
1380 }
1381 /*----------------------------------------------------------------------------*/
1382 /*FAT Interface Functions*/
1383 uint32_t
1385 {
1386  if (fd < 0 || fd >= FAT_FD_POOL_SIZE) {
1387  return 0;
1388  }
1389 
1390  if (fat_fd_pool[fd].file == NULL) {
1391  return 0;
1392  }
1393 
1394  return fat_file_pool[fd].dir_entry.DIR_FileSize;
1395 }
1396 /*----------------------------------------------------------------------------*/
1397 /**
1398  * Syncs every FAT with the first.
1399  */
1400 void
1402 {
1403  uint8_t fat_number;
1404  uint32_t fat_block;
1405 
1406  cfs_fat_flush();
1407 
1408  for (fat_block = 0; fat_block < mounted.info.BPB_FATSz; fat_block++) {
1409  diskio_read_block(mounted.dev, fat_block + mounted.info.BPB_RsvdSecCnt, sector_buffer);
1410  for (fat_number = 2; fat_number <= mounted.info.BPB_NumFATs; fat_number++) {
1411  diskio_write_block(mounted.dev, (fat_block + mounted.info.BPB_RsvdSecCnt) + ((fat_number - 1) * mounted.info.BPB_FATSz), sector_buffer);
1412  }
1413  }
1414 }
1415 /*----------------------------------------------------------------------------*/
1416 /*Helper Functions*/
1417 static void
1418 make_readable_entry(struct dir_entry *dir, struct cfs_dirent *dirent)
1419 {
1420  uint8_t i, j;
1421 
1422  for (i = 0, j = 0; i < 11; i++) {
1423  if (dir->DIR_Name[i] != ' ') {
1424  dirent->name[j] = dir->DIR_Name[i];
1425  j++;
1426  }
1427 
1428  if (i == 7) {
1429  dirent->name[j] = '.';
1430  j++;
1431  }
1432  }
1433 }
1434 /*----------------------------------------------------------------------------*/
1435 /**
1436  * Tests if the given value is a power of 2.
1437  *
1438  * \param value Number which should be testet if it is a power of 2.
1439  * \return 1 on failure and 0 if value is a power of 2.
1440  */
1441 uint8_t
1442 is_a_power_of_2(uint32_t value)
1443 {
1444  uint32_t test = 1;
1445  uint8_t i = 0;
1446 
1447  if (value == 0) {
1448  return 0;
1449  }
1450 
1451  for (i = 0; i < 32; ++i) {
1452  if (test == value) {
1453  return 0;
1454  }
1455 
1456  test = test << 1;
1457  }
1458  return 1;
1459 }
1460 /*----------------------------------------------------------------------------*/
1461 /**
1462  * Rounds the value down to the next lower power of 2.
1463  *
1464  * \param value The number which should be rounded down.
1465  * \return the next lower number which is a power of 2
1466  */
1467 uint32_t
1469 {
1470  uint32_t po2 = ((uint32_t) 1) << 31;
1471 
1472  while (value < po2) {
1473  po2 = po2 >> 1;
1474  }
1475 
1476  return po2;
1477 }
1478 /*----------------------------------------------------------------------------*/
1479 static uint8_t
1480 _is_file(struct dir_entry *dir_ent)
1481 {
1482  if (dir_ent->DIR_Attr & ATTR_DIRECTORY) {
1483  return 0;
1484  }
1485 
1486  if (dir_ent->DIR_Attr & ATTR_VOLUME_ID) {
1487  return 0;
1488  }
1489 
1490  return 1;
1491 }
1492 /*----------------------------------------------------------------------------*/
1493 static uint8_t
1494 _cfs_flags_ok(int flags, struct dir_entry *dir_ent)
1495 {
1496  if (((flags & CFS_APPEND) || (flags & CFS_WRITE)) && (dir_ent->DIR_Attr & ATTR_READ_ONLY)) {
1497  return 0;
1498  }
1499 
1500  return 1;
1501 }
1502 
1503 /** @} */
1504 /** @} */