COSA
An Object-Oriented Platform for Arduino Programming
FAT16.cpp
Go to the documentation of this file.
1 
22 #include "FAT16.hh"
23 
24 bool
25 FAT16::make83Name(const char* str, uint8_t* name)
26 {
27  uint8_t c;
28  uint8_t n = 7;
29  uint8_t i = 0;
30  while (i < 11) name[i++] = ' ';
31  i = 0;
32  while ((c = *str++) != '\0') {
33  if (c == '.') {
34  if (n == 10) return (false);
35  n = 10;
36  i = 8;
37  }
38  else {
39  PGM_P p = (PGM_P) PSTR("|<>^+=?/[];,*\"\\");
40  uint8_t b;
41  while ((b = pgm_read_byte(p++))) if (b == c) return (false);
42  if (i > n || c < 0X21 || c > 0X7E) return (false);
43  name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a');
44  }
45  }
46  return (name[0] != ' ');
47 }
48 
50 
52 uint8_t FAT16::fatCount;
57 uint32_t FAT16::fatStartBlock;
59 uint32_t FAT16::dataStartBlock;
60 
61 uint32_t FAT16::cacheBlockNumber = 0XFFFFFFFF;
63 uint8_t FAT16::cacheDirty = 0;
64 uint32_t FAT16::cacheMirrorBlock = 0;
65 void (*FAT16::dateTime)(uint16_t* date, uint16_t* time) = NULL;
66 
67 bool
68 FAT16::begin(SD* sd, uint8_t part)
69 {
70  // Error if invalid partition
71  if (UNLIKELY(part > 4)) return (false);
72  device = sd;
73  uint32_t volumeStartBlock = 0;
74 
75  // If part == 0 assume super floppy with FAT16 boot sector in block zero
76  // If part > 0 assume mbr volume with partition table
77  if (part) {
78  if (!cacheRawBlock(volumeStartBlock)) return (false);
79  volumeStartBlock = cacheBuffer.mbr.part[part - 1].firstSector;
80  }
81  if (!cacheRawBlock(volumeStartBlock)) return (false);
82 
83  // Check boot block signature
84  if (cacheBuffer.data[510] != BOOTSIG0 ||
85  cacheBuffer.data[511] != BOOTSIG1) return (false);
86 
87  bpb_t* bpb = &cacheBuffer.fbs.bpb;
88  fatCount = bpb->fatCount;
92  fatStartBlock = volumeStartBlock + bpb->reservedSectorCount;
94  dataStartBlock = rootDirStartBlock + ((32*bpb->rootDirEntryCount + 511)/512);
95  uint32_t totalBlocks = bpb->totalSectors16 ? bpb->totalSectors16 : bpb->totalSectors32;
96  clusterCount = (totalBlocks - (dataStartBlock - volumeStartBlock)) / bpb->sectorsPerCluster;
97 
98  // Check valid FAT16 volume
99  if ((bpb->bytesPerSector != 512) // Only allow 512 byte blocks
100  || (bpb->sectorsPerFat16 == 0) // Zero for FAT32
101  || (clusterCount < 4085) // FAT12 if true
102  || (totalBlocks > 0X800000) // Max size for FAT16 volume
103  || (bpb->reservedSectorCount == 0) // invalid volume
104  || (bpb->fatCount == 0) // invalid volume
105  || (bpb->sectorsPerFat16 < (clusterCount >> 8))
106  || (bpb->sectorsPerCluster == 0)
107  || (bpb->sectorsPerCluster & (bpb->sectorsPerCluster - 1))) {
108  return (false);
109  }
110  volumeInitialized = true;
111  return (true);
112 }
113 
114 bool
116 {
117  return (begin(sd, 1) || begin(sd, 0));
118 }
119 
120 bool
122 {
123  if (m_flags & F_FILE_DIR_DIRTY) {
124  // Cache directory entry
125  dir_t* d = cacheDirEntry(m_dirEntryIndex, CACHE_FOR_WRITE);
126  if (!d) return (false);
127 
128  // Update file size and first cluster
129  d->fileSize = m_fileSize;
130  d->firstClusterLow = m_firstCluster;
131 
132  // Set modify time if user supplied a callback date/time function
133  if (dateTime) {
136  }
137  m_flags &= ~F_FILE_DIR_DIRTY;
138  }
139  return (cacheFlush());
140 }
141 
142 bool
143 FAT16::File::open(const char* fileName, uint8_t oflag)
144 {
145  uint8_t dname[11]; // name formated for dir entry
146  int16_t empty = -1; // index of empty slot
147  dir_t* p; // pointer to cached dir entry
148 
149  if (!volumeInitialized || is_open()) return (false);
150 
151  // Check valid 8.3 file name
152  if (!make83Name(fileName, dname)) return (false);
153 
154  for (uint16_t index = 0; index < rootDirEntryCount; index++) {
155  if (!(p = cacheDirEntry(index))) return (false);
156  if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) {
157  // Remember first empty slot
158  if (empty < 0) empty = index;
159  // Done if no entries follow
160  if (p->name[0] == DIR_NAME_FREE) break;
161  }
162  else if (!memcmp(dname, p->name, 11)) {
163  // Don't open existing file if O_CREAT and O_EXCL
164  if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return (false);
165  // Open existing file
166  return (open(index, oflag));
167  }
168  }
169 
170  // Error if directory is full
171  if (empty < 0) return (false);
172 
173  // Only create file if O_CREAT and O_WRITE
174  if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return (false);
175  if (!(p = cacheDirEntry(empty, CACHE_FOR_WRITE))) return (false);
176 
177  // Initialize as empty file
178  memset(p, 0, sizeof(dir_t));
179  memcpy(p->name, dname, 11);
180 
181  // Set timestamps with user function or use default date/time
182  if (dateTime) {
184  } else {
187  }
189  p->lastWriteDate = p->creationDate;
190  p->lastWriteTime = p->creationTime;
191 
192  // Force created directory entry will be written to storage device
193  if (!cacheFlush()) return (false);
194 
195  // Open entry
196  return (open(empty, oflag));
197 }
198 
199 bool
200 FAT16::File::open(uint16_t index, uint8_t oflag)
201 {
202  if (!volumeInitialized || is_open()) return (false);
203  if ((oflag & O_TRUNC) && !(oflag & O_WRITE)) return (false);
204  dir_t* d = cacheDirEntry(index);
205  // If bad file index or I/O error
206  if (!d) return (false);
207  // Error if unused entry
208  if (d->name[0] == DIR_NAME_FREE || d->name[0] == DIR_NAME_DELETED)
209  return (false);
210  // Error if long name, volume label or subdirectory
211  if ((d->attributes & (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY)) != 0)
212  return (false);
213  // Don't allow write or truncate if read-only
214  if ((d->attributes & DIR_ATT_READ_ONLY) && (oflag & (O_WRITE | O_TRUNC)))
215  return (false);
216 
217  m_curCluster = 0;
218  m_curPosition = 0;
219  m_dirEntryIndex = index;
220  m_fileSize = d->fileSize;
221  m_firstCluster = d->firstClusterLow;
222  m_flags = oflag & (O_RDWR | O_SYNC | O_APPEND);
223  if (oflag & O_TRUNC) return (truncate(0));
224  return (true);
225 }
226 
227 bool
229 {
230  // Error if file is not open for write
231  if (!(m_flags & O_WRITE)) return (false);
232  if (m_firstCluster && !freeChain(m_firstCluster)) return (false);
233  dir_t* d = cacheDirEntry(m_dirEntryIndex, CACHE_FOR_WRITE);
234  if (!d) return (false);
235  d->name[0] = DIR_NAME_DELETED;
236  m_flags = 0;
237  return (cacheFlush());
238 }
239 
240 int
242 {
243  uint8_t res;
244  return (read(&res, sizeof(res)) == sizeof(res) ? res : -1);
245 }
246 
247 int
248 FAT16::File::read(void* buf, size_t nbyte)
249 {
250  // Convert void pointer to uin8_t pointer
251  uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
252 
253  // Error if not open for read
254  if (!(m_flags & O_READ)) return (IOStream::EOF);
255 
256  // Don't read beyond end of file
257  if ((m_curPosition + nbyte) > m_fileSize) nbyte = m_fileSize - m_curPosition;
258 
259  // Bytes left to read in loop
260  uint16_t nToRead = nbyte;
261  while (nToRead > 0) {
262  uint8_t blkOfCluster = blockOfCluster(m_curPosition);
263  uint16_t blockOffset = cacheDataOffset(m_curPosition);
264  if (blkOfCluster == 0 && blockOffset == 0) {
265  // Start next cluster
266  if (m_curCluster == 0) {
267  m_curCluster = m_firstCluster;
268  } else {
269  if (!fatGet(m_curCluster, &m_curCluster)) return (IOStream::EOF);
270  }
271  // Return error if bad cluster chain
272  if (m_curCluster < 2 || isEOC(m_curCluster)) return (IOStream::EOF);
273  }
274 
275  // Cache data block
276  if (!cacheRawBlock(dataBlockLba(m_curCluster, blkOfCluster)))
277  return (IOStream::EOF);
278 
279  // Location of data in cache
280  uint8_t* src = cacheBuffer.data + blockOffset;
281 
282  // Max number of byte available in block
283  uint16_t n = 512 - blockOffset;
284 
285  // Lesser of available and amount to read
286  if (n > nToRead) n = nToRead;
287 
288  // Copy data to caller
289  memcpy(dst, src, n);
290 
291  m_curPosition += n;
292  dst += n;
293  nToRead -= n;
294  }
295  return (nbyte);
296 }
297 
298 int
299 FAT16::File::write(const void* buf, size_t nbyte)
300 {
301  uint16_t nToWrite = nbyte;
302  const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
303 
304  // Error if file is not open for write
305  if (!(m_flags & O_WRITE)) return (IOStream::EOF);
306 
307  // Go to end of file if O_APPEND
308  if ((m_flags & O_APPEND) && m_curPosition != m_fileSize) {
309  if (!seek(0, SEEK_END)) return (IOStream::EOF);
310  }
311 
312  while (nToWrite > 0) {
313  uint8_t blkOfCluster = blockOfCluster(m_curPosition);
314  uint16_t blockOffset = cacheDataOffset(m_curPosition);
315  if (blkOfCluster == 0 && blockOffset == 0) {
316  // Start of new cluster
317  if (m_curCluster == 0) {
318  if (m_firstCluster == 0) {
319  // Allocate first cluster of file
320  if (!addCluster()) return (IOStream::EOF);
321  } else {
322  m_curCluster = m_firstCluster;
323  }
324  } else {
325  fat_t next;
326  if (!fatGet(m_curCluster, &next)) return (IOStream::EOF);
327  if (isEOC(next)) {
328  // Add cluster if at end of chain
329  if (!addCluster()) return (IOStream::EOF);
330  } else {
331  m_curCluster = next;
332  }
333  }
334  }
335  uint32_t lba = dataBlockLba(m_curCluster, blkOfCluster);
336  if (blockOffset == 0 && m_curPosition >= m_fileSize) {
337  // Start of new block don't need to read into cache
338  if (!cacheFlush()) return (IOStream::EOF);
339  cacheBlockNumber = lba;
340  cacheSetDirty();
341  } else {
342  // Rewrite part of block
343  if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) return (IOStream::EOF);
344  }
345  uint8_t* dst = cacheBuffer.data + blockOffset;
346 
347  // Max space in block
348  uint16_t n = 512 - blockOffset;
349 
350  // Lesser of space and amount to write
351  if (n > nToWrite) n = nToWrite;
352 
353  // Copy data to cache
354  memcpy(dst, src, n);
355 
356  m_curPosition += n;
357  nToWrite -= n;
358  src += n;
359  }
360  if (m_curPosition > m_fileSize) {
361  // Update fileSize and insure sync will update dir entry
362  m_fileSize = m_curPosition;
363  m_flags |= F_FILE_DIR_DIRTY;
364  }
365  else if (dateTime && nbyte) {
366  // Force sync will update modified date and time
367  m_flags |= F_FILE_DIR_DIRTY;
368  }
369 
370  if (m_flags & O_SYNC) {
371  if (!sync()) return (IOStream::EOF);
372  }
373  return (nbyte);
374 }
375 
376 int
378 {
379  return (write(&c, sizeof(c)));
380 }
381 
382 bool
383 FAT16::File::seek(uint32_t pos, uint8_t whence)
384 {
385  if (whence == SEEK_CUR) pos += m_curPosition;
386  else if (whence == SEEK_END) pos = m_fileSize;
387  else if (whence != SEEK_SET) return (false);
388 
389  // Error if file not open or seek past end of file
390  if (!is_open() || pos > m_fileSize) return (false);
391  if (pos == 0) {
392  // Set position to start of file
393  m_curCluster = 0;
394  m_curPosition = 0;
395  return (true);
396  }
397  fat_t n = ((pos - 1) >> 9) / blocksPerCluster;
398  if (pos < m_curPosition || m_curPosition == 0) {
399  // Must follow chain from first cluster
400  m_curCluster = m_firstCluster;
401  } else {
402  // Advance from curPosition
403  n -= ((m_curPosition - 1) >> 9)/blocksPerCluster;
404  }
405  while (n--) {
406  if (!fatGet(m_curCluster, &m_curCluster)) return (false);
407  }
408  m_curPosition = pos;
409  return (true);
410 }
411 
412 bool
413 FAT16::File::truncate(uint32_t length)
414 {
415  // Error if file is not open for write
416  if (!(m_flags & O_WRITE)) return (false);
417 
418  if (length > m_fileSize) return (false);
419 
420  // Filesize and length are zero - nothing to do
421  if (m_fileSize == 0) return (true);
422  uint32_t newPos = m_curPosition > length ? length : m_curPosition;
423  if (length == 0) {
424  // Free all clusters
425  if (!freeChain(m_firstCluster)) return (false);
426  m_curCluster = m_firstCluster = 0;
427  }
428  else {
429  fat_t toFree;
430  if (!seek(length)) return (false);
431  if (!fatGet(m_curCluster, &toFree)) return (false);
432  if (!isEOC(toFree)) {
433  // Free extra clusters
434  if (!fatPut(m_curCluster, EOC16)) return (false);
435  if (!freeChain(toFree)) return (false);
436  }
437  }
438  m_fileSize = length;
439  m_flags |= F_FILE_DIR_DIRTY;
440  if (!sync()) return (false);
441  return seek(newPos);
442 }
443 
444 bool
446 {
447  if (!sync()) return (false);
448  dir_t* p = cacheDirEntry(m_dirEntryIndex, CACHE_FOR_WRITE);
449  if (!p) return (false);
450  memcpy(dir, p, sizeof(dir_t));
451  return (true);
452 }
453 
454 bool
455 FAT16::read(dir_t* dir, uint16_t* index, uint8_t skip)
456 {
457  dir_t* p;
458  for (uint16_t i = *index; ; i++) {
459  if (i >= rootDirEntryCount) return (false);
460  if (!(p = cacheDirEntry(i))) return (false);
461 
462  // Done if beyond last used entry
463  if (p->name[0] == DIR_NAME_FREE) return (false);
464 
465  // Skip deleted entry
466  if (p->name[0] == DIR_NAME_DELETED) continue;
467 
468  // Skip long names
469  if ((p->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME) continue;
470 
471  // Skip if attribute match
472  if (p->attributes & skip) continue;
473 
474  // Return found index
475  *index = i;
476  break;
477  }
478  memcpy(dir, p, sizeof(dir_t));
479  return (true);
480 }
481 
482 void
483 FAT16::printDirName(IOStream& outs, const dir_t& dir, uint8_t width)
484 {
485  uint8_t w = 0;
486  for (uint8_t i = 0; i < 11; i++) {
487  if (dir.name[i] == ' ') continue;
488  if (i == 8) {
489  outs << '.';
490  w++;
491  }
492  outs << (char) dir.name[i];
493  w++;
494  }
495  if (DIR_IS_SUBDIR(&dir)) {
496  outs << '/';
497  w++;
498  }
499  while (w < width) {
500  outs << ' ';
501  w++;
502  }
503 }
504 
505 void
506 FAT16::ls(IOStream& outs, uint8_t flags)
507 {
508  dir_t d;
509  for (uint16_t index = 0; read(&d, &index, DIR_ATT_VOLUME_ID); index++) {
510  // Print file name with possible blank fill
511  printDirName(outs, d, flags & (LS_DATE | LS_SIZE) ? 14 : 0);
512 
513  // Print modify date/time if requested
514  if (flags & LS_DATE) {
515  date_t date(d.lastWriteDate);
516  time_t time(d.lastWriteTime);
517  outs << date << ' ' << time;
518  }
519 
520  // Print size if requested
521  if (DIR_IS_FILE(&d) && (flags & LS_SIZE)) {
522  outs << ' ' << d.fileSize;
523  }
524  outs << endl;
525  }
526 }
527 
528 bool
530 {
531  // Start search after last cluster of file or at cluster two in FAT
532  fat_t freeCluster = m_curCluster ? m_curCluster : 1;
533 
534  for (fat_t i = 0; ; i++) {
535  // Return no free clusters
536  if (i >= clusterCount) return (false);
537  // Fat has clusterCount + 2 entries
538  if (freeCluster > clusterCount) freeCluster = 1;
539  freeCluster++;
540  fat_t value;
541  if (!fatGet(freeCluster, &value)) return (false);
542  if (value == 0) break;
543  }
544 
545  // Mark cluster allocated
546  if (!fatPut(freeCluster, EOC16)) return (false);
547 
548  if (m_curCluster != 0) {
549  // Link cluster to chain
550  if (!fatPut(m_curCluster, freeCluster)) return (false);
551  } else {
552  // first cluster of file so update directory entry
553  m_flags |= F_FILE_DIR_DIRTY;
554  m_firstCluster = freeCluster;
555  }
556  m_curCluster = freeCluster;
557  return (true);
558 }
559 
561 FAT16::cacheDirEntry(uint16_t index, uint8_t action)
562 {
563  if (index >= rootDirEntryCount) return NULL;
564  if (!cacheRawBlock(rootDirStartBlock + (index >> 4), action)) return NULL;
565  return &cacheBuffer.dir[index & 0XF];
566 }
567 
568 uint8_t
570 {
571  if (cacheDirty) {
573  return (false);
574  }
575  if (cacheMirrorBlock) {
577  return (false);
578  }
579  cacheMirrorBlock = 0;
580  }
581  cacheDirty = 0;
582  }
583  return (true);
584 }
585 
586 uint8_t
587 FAT16::cacheRawBlock(uint32_t blockNumber, uint8_t action)
588 {
589  if (cacheBlockNumber != blockNumber) {
590  if (!cacheFlush()) return (false);
591  if (!device->read(blockNumber, cacheBuffer.data)) return (false);
592  cacheBlockNumber = blockNumber;
593  }
594  cacheDirty |= action;
595  return (true);
596 }
597 
598 bool
599 FAT16::fatGet(fat_t cluster, fat_t* value)
600 {
601  if (cluster > (clusterCount + 1)) return (false);
602  uint32_t lba = fatStartBlock + (cluster >> 8);
603  if (lba != cacheBlockNumber) {
604  if (!cacheRawBlock(lba)) return (false);
605  }
606  *value = cacheBuffer.fat[cluster & 0XFF];
607  return (true);
608 }
609 
610 bool
611 FAT16::fatPut(fat_t cluster, fat_t value)
612 {
613  if (cluster < 2) return (false);
614  if (cluster > (clusterCount + 1)) return (false);
615  uint32_t lba = fatStartBlock + (cluster >> 8);
616  if (lba != cacheBlockNumber) {
617  if (!cacheRawBlock(lba)) return (false);
618  }
619  cacheBuffer.fat[cluster & 0XFF] = value;
620  cacheSetDirty();
621  if (fatCount > 1) cacheMirrorBlock = lba + blocksPerFat;
622  return (true);
623 }
624 
625 bool
627 {
628  while (1) {
629  fat_t next;
630  if (!fatGet(cluster, &next)) return (false);
631  if (!fatPut(cluster, 0)) return (false);
632  if (isEOC(next)) return (true);
633  cluster = next;
634  }
635 }
636 
637 IOStream&
639 {
640  outs << date.YEAR() << '-';
641  uint8_t month = date.MONTH();
642  if (month < 9) outs << '0';
643  outs << month << '-';
644  uint8_t day = date.DAY();
645  if (day < 9) outs << '0';
646  outs << day;
647  return (outs);
648 }
649 
650 IOStream&
652 {
653  uint8_t hours = time.HOURS();
654  if (hours < 9) outs << '0';
655  outs << hours << ':';
656  uint8_t minutes = time.MINUTES();
657  if (minutes < 9) outs << '0';
658  outs << minutes << ':';
659  uint8_t seconds = time.SECONDS();
660  if (seconds < 9) outs << '0';
661  outs << seconds;
662  return (outs);
663 }
664 
uint16_t sectorsPerFat16
Definition: FAT16.hh:200
static uint16_t const EOC16
Definition: FAT16.hh:320
static void(* dateTime)(uint16_t *date, uint16_t *time)
Definition: FAT16.hh:798
virtual int putchar(char c)
Definition: FAT16.cpp:377
static uint8_t cacheDirty
Definition: FAT16.hh:794
virtual int read(void *buf, size_t size)
Definition: FAT16.cpp:248
Absolute position.
Definition: FS.hh:47
uint16_t creationTime
Definition: FAT16.hh:366
static bool volumeInitialized
Definition: FAT16.hh:779
static SD * device
Definition: FAT16.hh:776
uint16_t lastWriteTime
Definition: FAT16.hh:385
static uint8_t const BOOTSIG1
Definition: FAT16.hh:47
static uint8_t const DIR_ATT_DIRECTORY
Definition: FAT16.hh:417
static uint8_t const CACHE_FOR_WRITE
Definition: FAT16.hh:791
uint8_t MINUTES()
Definition: FAT16.hh:542
uint16_t rootDirEntryCount
Definition: FAT16.hh:177
static uint8_t const DIR_NAME_FREE
Definition: FAT16.hh:406
bool dirEntry(dir_t *dir)
Definition: FAT16.cpp:445
uint16_t firstClusterLow
Definition: FAT16.hh:393
#define NULL
Definition: Types.h:101
bool open(const char *fileName, uint8_t oflag)
Definition: FAT16.cpp:143
static uint8_t blockOfCluster(uint32_t position)
Definition: FAT16.hh:806
bool write(uint32_t block, const uint8_t *src)
Definition: SD.cpp:314
Open for reading.
Definition: FS.hh:28
static uint32_t rootDirStartBlock
Definition: FAT16.hh:786
#define PSTR(s)
Definition: Types.h:202
static const uint16_t DEFAULT_TIME
Definition: FAT16.hh:554
uint16_t totalSectors16
Definition: FAT16.hh:187
static const uint16_t DEFAULT_DATE
Definition: FAT16.hh:551
static uint8_t const DIR_ATT_VOLUME_ID
Definition: FAT16.hh:415
static uint8_t const DIR_ATT_READ_ONLY
Definition: FAT16.hh:409
static fat_t clusterCount
Definition: FAT16.hh:784
uint8_t MONTH()
Definition: FAT16.hh:506
bool freeChain(fat_t cluster)
Definition: FAT16.cpp:626
bool remove()
Definition: FAT16.cpp:228
dir_t dir[16]
Definition: FAT16.hh:471
uint32_t fileSize
Definition: FAT16.hh:397
virtual int getchar()
Definition: FAT16.cpp:241
Relative to end of file.
Definition: FS.hh:49
uint8_t name[11]
Definition: FAT16.hh:344
static uint32_t dataBlockLba(fat_t cluster, uint8_t blockOfCluster)
Definition: FAT16.hh:821
Definition: SD.hh:35
static uint32_t fatStartBlock
Definition: FAT16.hh:785
static uint8_t fatCount
Definition: FAT16.hh:780
static uint8_t const BOOTSIG0
Definition: FAT16.hh:44
static uint32_t cacheMirrorBlock
Definition: FAT16.hh:795
static uint8_t const DIR_NAME_DELETED
Definition: FAT16.hh:404
Truncate the file to zero length.
Definition: FS.hh:40
static bool fatGet(fat_t cluster, fat_t *value)
Definition: FAT16.cpp:599
uint8_t DAY()
Definition: FAT16.hh:507
static void printDirName(IOStream &outs, const dir_t &dir, uint8_t width)
Definition: FAT16.cpp:483
static uint8_t blocksPerCluster
Definition: FAT16.hh:781
bool truncate(uint32_t size)
Definition: FAT16.cpp:413
uint8_t sectorsPerCluster
Definition: FAT16.hh:159
uint8_t data[512]
Definition: FAT16.hh:467
uint8_t SECONDS()
Definition: FAT16.hh:543
static uint8_t const DIR_ATT_LONG_NAME
Definition: FAT16.hh:421
static const int EOF
Definition: IOStream.hh:33
static fat_t blocksPerFat
Definition: FAT16.hh:783
uint16_t YEAR()
Definition: FAT16.hh:505
virtual int write(const void *buf, size_t size)
Definition: FAT16.cpp:299
static bool begin(SD *sd, uint8_t partion)
Definition: FAT16.cpp:68
IOStream & endl(IOStream &outs)
Definition: IOStream.hh:817
bool read(CMD command, uint32_t arg, void *buf, size_t count)
Definition: SD.cpp:183
Open for reading and writing.
Definition: FS.hh:32
bool seek(uint32_t pos, uint8_t whence=SEEK_SET)
Definition: FAT16.cpp:383
static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action=0)
Definition: FAT16.cpp:587
uint16_t creationDate
Definition: FAT16.hh:370
static uint8_t DIR_IS_FILE(const dir_t *dir)
Definition: FAT16.hh:441
uint16_t lastAccessDate
Definition: FAT16.hh:376
static uint8_t DIR_IS_SUBDIR(const dir_t *dir)
Definition: FAT16.hh:449
static bool make83Name(const char *str, uint8_t *name)
Definition: FAT16.cpp:25
static void cacheSetDirty(void)
Definition: FAT16.hh:817
static uint8_t cacheFlush(void)
Definition: FAT16.cpp:569
Relative to current position.
Definition: FS.hh:48
static void ls(IOStream &outs, uint8_t flags=0)
Definition: FAT16.cpp:506
uint8_t fatCount
Definition: FAT16.hh:168
uint16_t fat_t
Definition: FAT16.hh:463
friend IOStream & operator<<(IOStream &outs, date_t &date)
Definition: FAT16.cpp:638
static uint32_t dataStartBlock
Definition: FAT16.hh:787
static uint16_t rootDirEntryCount
Definition: FAT16.hh:782
uint16_t lastWriteDate
Definition: FAT16.hh:389
bool addCluster()
Definition: FAT16.cpp:529
bool sync()
Definition: FAT16.cpp:121
static uint8_t const DIR_ATT_LONG_NAME_MASK
Definition: FAT16.hh:423
Create the file if nonexistent.
Definition: FS.hh:36
uint16_t HOURS()
Definition: FAT16.hh:541
static uint32_t cacheBlockNumber
Definition: FAT16.hh:793
static bool fatPut(fat_t cluster, fat_t value)
Definition: FAT16.cpp:611
part_t part[4]
Definition: FAT16.hh:133
static bool read(dir_t *dir, uint16_t *index, uint8_t skip=DIR_ATT_SKIP)
Definition: FAT16.cpp:455
fat_t fat[256]
Definition: FAT16.hh:469
#define UNLIKELY(x)
Definition: Types.h:153
uint8_t attributes
Definition: FAT16.hh:351
uint16_t reservedSectorCount
Definition: FAT16.hh:164
static dir_t * cacheDirEntry(uint16_t index, uint8_t action=0)
Definition: FAT16.cpp:561
Definition: FS.hh:33
uint16_t bytesPerSector
Definition: FAT16.hh:153
uint32_t totalSectors32
Definition: FAT16.hh:221
Open for write.
Definition: FS.hh:30
static uint8_t const F_FILE_DIR_DIRTY
Definition: FAT16.hh:802
Definition: FS.hh:37
Synchronous writes.
Definition: FS.hh:35
bpb_t bpb
Definition: FAT16.hh:280
uint32_t firstSector
Definition: FAT16.hh:106
static cache16_t cacheBuffer
Definition: FAT16.hh:792
static uint16_t cacheDataOffset(uint32_t position)
Definition: FAT16.hh:810