embkernel
 All Classes Functions Variables Typedefs Groups Pages
Fs.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "Fs.hpp"
7 #include "FsFile.hpp"
8 #include "LibEndian.hpp"
9 #include "LibRtc.hpp"
10 #include "FsDir.hpp"
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 
15 RtosSemaphore Fs::sSema(1, 1);
16 FsPartition** Fs::sPartitions;
17 size_t Fs::sPartitionsCount;
18 
20 //
22 void Fs::init(FsPartition* partitions[], size_t partitionsCount) {
23  sPartitions = partitions;
24  sPartitionsCount = partitionsCount;
25 }
26 
27 FsDefs::RESULT Fs::format(FsDrive* drive, FsFormatCallback* listener) {
28  FsDefs::SECTOR* sector = (FsDefs::SECTOR*) malloc(sizeof(sector));
29  if (!sector) {
30  return FsDefs::RES_OUT_OF_MEMORY;
31  }
32  drive->lock();
33  FsDefs::RESULT result = internalFormat(drive, sector, listener);
34  drive->unlock();
35  free(sector);
36  return result;
37 }
38 
40 //
42 FsDefs::RESULT Fs::open(const char* path, class FsEntry* file) {
43  int pathIdx = 0;
44  unsigned int partitionIdx = 0;
45  for (; pathIdx < 2; pathIdx++) {
46  if (path[pathIdx] == '/') {
47  break;
48  }
49  if (path[pathIdx] < '0' && path[0] > '0') {
50  return FsDefs::RES_INVALID_PATH;
51  }
52  partitionIdx *= 10;
53  partitionIdx += path[pathIdx] - '0';
54  }
55 
56  if (partitionIdx >= sPartitionsCount) {
57  return FsDefs::RES_INVALID_PARTITION;
58  }
59 
60  if (path[pathIdx] == '/') {
61  pathIdx++; //Skip '/'
62  }
63  else if (!path[pathIdx]) { //Zero length path?
64  return FsDefs::RES_INVALID_PATH;
65  }
66 
67  file->mPartition = sPartitions[partitionIdx];
68 
69  file->mPartition->lock();
70  FsDefs::RESULT result = internalOpen(&path[pathIdx], file);
71  file->mPartition->unlock();
72  return result;
73 }
74 
75 FsDefs::RESULT Fs::read(void* buffer, size_t len, size_t* read, class FsFile* file) {
76  file->mPartition->lock();
77  if (file->mPosition + len > file->mSize) {
78  len = file->mSize - file->mPosition;
79  }
80  FsDefs::RESULT result = internalRead(buffer, len, read, file);
81  file->mPartition->unlock();
82  return result;
83 }
84 
85 FsDefs::RESULT Fs::write(const void* buffer, size_t len, size_t* transfered, class FsFile* file) {
86  file->mPartition->lock();
87  FsDefs::RESULT result = internalWrite(buffer, len, transfered, file);
88  file->mPartition->unlock();
89  return result;
90 }
91 
92 FsDefs::RESULT Fs::seek(class FsFile* file, size_t position) {
93  file->mPartition->lock();
94  FsDefs::RESULT result = internalSeek(file, position);
95  file->mPartition->unlock();
96  return result;
97 }
98 
99 FsDefs::RESULT Fs::flush(FsFile* file) {
100  file->mPartition->lock();
101  FsDefs::SECTOR* sector = (FsDefs::SECTOR*) malloc(sizeof(FsDefs::SECTOR));
102  if (!sector) {
103  file->mPartition->unlock();
104  return FsDefs::RES_OUT_OF_MEMORY;
105  }
106  FsDefs::RESULT result = internalFlush(file, sector);
107  free(sector);
108  file->mPartition->unlock();
109  return result;
110 }
111 
112 FsDefs::RESULT Fs::del(class FsEntry* file) {
113  file->mPartition->lock();
114  FsDefs::RESULT result = internalDel(file);
115  file->mPartition->unlock();
116  return result;
117 }
118 
119 FsDefs::RESULT Fs::getNextEntry(class FsEntry* file, FsDir::ENTRY_INFO* info) {
120  file->mPartition->lock();
121  FsDefs::RESULT result = internalGetNextEntry(file, info);
122  file->mPartition->unlock();
123  return result;
124 }
125 
127 //
129 FsDefs::RESULT Fs::internalOpen(const char* path, FsEntry* file) {
130  if (!file->mPartition->mIsValid) {
131  FsDefs::RESULT result = internalInitPartition(file->mPartition, file->mSector);
132  if (result != FsDefs::RES_SUCCESS) {
133  return result;
134  }
135  }
136 
137  //Path is the root directory?
138  if (file->mFlags.bits.directory && path[0] == '\0') {
139  file->mDirectoryEntryLba = 0;
140  file->mDirectoryEntryIndex = 0;
141  file->mClusterBegin = file->mPartition->mRootDirFirstCluster;
142  file->mCurrentLba = file->mPartition->getClusterBeginLba(LibEndian::leToHw(file->mClusterBegin));
143  file->mPosition = 0;
144  return FsDefs::RES_SUCCESS;
145  }
146 
147  //Read root directory
148  uint32_t currentLba = file->mPartition->getRootClusterLba();
149  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
150  return FsDefs::RES_DISK_ERROR;
151  }
152  file->mDirectoryEntryLba = currentLba;
153 
154  uint32_t unusedEntryLba = 0;
155  uint32_t unusedEntryIndex = 0;
156 
157  for (size_t entryIndex = 0;;) {
158  if (entryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
159  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &currentLba);
160  switch (result) {
161  case FsDefs::RES_SUCCESS:
162  break;
163  case FsDefs::RES_EOF:
164  return FsDefs::RES_ENTRY_NOT_FOUND;
165  default:
166  return result;
167  }
168  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
169  return FsDefs::RES_DISK_ERROR;
170  }
171  entryIndex = 0;
172  }
173 
174  FsDefs::RESULT result = FsDefs::RES_ENTRY_NOT_FOUND;
175  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[entryIndex];
176 
177  if (entry->shortEntry.name[0] == FsDefs::ENTRY_UNUSED) { //Free directory table
178  if (unusedEntryLba == 0) { //Save the first empty entry location position which may be used later for file creation
179  unusedEntryLba = currentLba;
180  unusedEntryIndex = entryIndex;
181  }
182  }
183  else if (entry->shortEntry.name[0] == FsDefs::ENTRY_LAST) { //Last entry
184  if (file->mFlags.bits.createAlways) {
185  int len;
186  FILENAME_TYPE type = getFilenameType(path, len);
187  switch (type) {
188  case FT_INVALID:
189  return FsDefs::RES_INVALID_PATH;
190  break;
191  case FT_SHORT_FILENAME:
192  file->mLfnDirectoryEntryLba = file->mLfnDirectoryEntryIndex = 0;
193  if (unusedEntryLba == 0) {
194  file->mDirectoryEntryLba = currentLba;
195  file->mDirectoryEntryIndex = entryIndex;
196  if (entryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
197  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &currentLba);
198  if (result != FsDefs::RES_SUCCESS) {
199  return result;
200  }
201  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
202  return FsDefs::RES_DISK_ERROR;
203  }
204  //Mark next entry as last
205  FsDefs::DIRECTORY_ENTRY* lastEntry = &file->mSector->dirEntries[entryIndex + 1];
206  memset(lastEntry, 0, sizeof(FsDefs::DIRECTORY_ENTRY));
207  if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
208  return FsDefs::RES_DISK_ERROR;
209  }
210  if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
211  return FsDefs::RES_DISK_ERROR;
212  }
213  }
214  else {
215  //Mark next entry as last
216  FsDefs::DIRECTORY_ENTRY* lastEntry = &file->mSector->dirEntries[entryIndex + 1];
217  memset(lastEntry, 0, sizeof(FsDefs::DIRECTORY_ENTRY));
218  }
219  }
220  else {
221  if (unusedEntryLba != currentLba) {
222  if (!file->mPartition->readBlocks(file->mSector, unusedEntryLba, 1)) {
223  return FsDefs::RES_DISK_ERROR;
224  }
225  }
226  currentLba = file->mDirectoryEntryLba = unusedEntryLba;
227  entryIndex = file->mDirectoryEntryIndex = unusedEntryIndex;
228  }
229  result = createShortFilenameEntry(&path, file, true);
230  break;
231  case FT_LONG_FILENAME:
232  if (file->mDirectoryEntryLba != currentLba) {
233  if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
234  return FsDefs::RES_DISK_ERROR;
235  }
236  }
237  result = createLongFilenameEntry(&path, file, len);
238  break;
239  }
240  }
241  if (result != FsDefs::RES_SUCCESS) {
242  return result;
243  }
244  entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
245  }
246  else { //Check entry
247  if (isLongFilenameEntry(entry)) {
248  file->mDirectoryEntryLba = file->mLfnDirectoryEntryLba = currentLba;
249  file->mDirectoryEntryIndex = file->mLfnDirectoryEntryIndex = entryIndex;
250  result = checkLongFilename(&path, file);
251  entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
252  }
253  else {
254  file->mDirectoryEntryLba = currentLba;
255  file->mDirectoryEntryIndex = entryIndex;
256  file->mLfnDirectoryEntryLba = file->mLfnDirectoryEntryIndex = 0;
257  result = checkShortFilename(&path, entry);
258  }
259  }
260 
261  if (result == FsDefs::RES_SUCCESS) {
262  if (*path == '\0') {
263  file->mClusterBegin = (((uint32_t) LibEndian::leToHw(entry->shortEntry.firstClusterHi)) << 16)
264  + LibEndian::leToHw(entry->shortEntry.firstClusterLo);
265  file->mCurrentLba = file->mPartition->getClusterBeginLba(LibEndian::leToHw(file->mClusterBegin));
266  file->mPosition = 0;
267  file->mFlags.bits.directory = entry->shortEntry.attributes.bits.directory;
268  if (file->mFlags.bits.createAlways) {
269  //Free all allocated clusters
270  if ((entry->shortEntry.attributes.bits.readOnly != file->mFlags.bits.readOnly) || (entry->shortEntry.fileSize != 0)) {
271  entry->shortEntry.attributes.bits.readOnly = file->mFlags.bits.readOnly;
272  entry->shortEntry.fileSize = 0;
273  if (!file->mPartition->writeBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
274  return FsDefs::RES_DISK_ERROR;
275  }
276  }
277  file->mSize = 0;
278  file->mPartition->freeClusterChain(file->mSector, file->mClusterBegin);
279  }
280  else {
281  file->mSize = LibEndian::leToHw(entry->shortEntry.fileSize);
282  if (!file->mFlags.bits.readOnly && entry->shortEntry.attributes.bits.readOnly) {
283  return FsDefs::RES_DENIED;
284  }
285  }
286  return FsDefs::RES_SUCCESS;
287  }
288  else {
289  currentLba = file->mPartition->getClusterBeginLba((((uint32_t) entry->shortEntry.firstClusterHi) << 16) + entry->shortEntry.firstClusterLo);
290  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
291  return FsDefs::RES_DISK_ERROR;
292  }
293  file->mDirectoryEntryLba = currentLba;
294  entryIndex = 0;
295  unusedEntryLba = 0;
296  unusedEntryIndex = 0;
297  }
298  }
299  else {
300  entryIndex++;
301  }
302  }
303 }
304 
305 FsDefs::RESULT Fs::internalInitPartition(FsPartition* partition, FsDefs::SECTOR* sector) {
306  if (!partition->mDrive->mIsReady) {
307  if (!partition->mDrive->init()) {
308  return FsDefs::RES_DISK_ERROR;
309  }
310  partition->mDrive->mIsReady = true;
311  }
312  if (!partition->readBlocks(sector, 0, 1)) {
313  return FsDefs::RES_DISK_ERROR;
314  }
315 
316  FsDefs::MBR* mbr = (FsDefs::MBR*) sector;
317  if (LibEndian::leToHw(mbr->checkAA55) != 0xAA55) {
318  return FsDefs::RES_NOT_FORMATTED;
319  }
320 
321  FsDefs::BOOT_SECTOR* bootSector = (FsDefs::BOOT_SECTOR*) sector;
322  if (memcmp(bootSector->type.fat32.filSysType, "FAT", 3) == 0) { //BOOT record in sector 0
323  if (partition->mIndexOnDrive == 0) {
324  if (partition->initFromBootSector(bootSector, 0) == FsDefs::RES_SUCCESS) {
325  return FsDefs::RES_SUCCESS;
326  }
327  }
328  }
329  else {
330  uint32_t partitionBeginLba = 0;
331  FsDefs::PARTITION_ENTRY* partitionEntry = &mbr->partitionEntries[partition->mIndexOnDrive];
332  if ((partitionEntry->partitionType == FsDefs::PT_FAT32) || (partitionEntry->partitionType == FsDefs::PT_FAT32X)) {
333  partitionBeginLba = LibEndian::leToHw(partitionEntry->lbaBegin);
334  if (!partition->readBlocks(sector, partitionBeginLba, 1)) {
335  return FsDefs::RES_DISK_ERROR;
336  }
337  FsDefs::BOOT_SECTOR* bootSector = (FsDefs::BOOT_SECTOR*) sector;
338  if (partition->initFromBootSector(bootSector, partitionBeginLba) == FsDefs::RES_SUCCESS) {
339  return FsDefs::RES_SUCCESS;
340  }
341  }
342  }
343  return FsDefs::RES_NOT_FORMATTED;
344 }
345 
346 FsDefs::RESULT Fs::internalRead(void* buffer, size_t len, size_t* read, class FsFile* file) {
347  *read = 0;
348  size_t blockByteIndex = file->mPosition % FsDefs::SECTOR_BYTES;
349  while (*read < len) {
350  //If sector as not been read yet, read it
351  if (file->mFlags.bits.sectorCacheInvalid) {
352  if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
353  return FsDefs::RES_DISK_ERROR;
354  }
355  file->mFlags.bits.sectorCacheInvalid = false;
356  }
357 
358  int copyLen = len - *read;
359  int leftOnSector = FsDefs::SECTOR_BYTES - blockByteIndex;
360  if (copyLen > leftOnSector) {
361  copyLen = leftOnSector;
362  }
363  memcpy(&((uint8_t*) buffer)[*read], &file->mSector->bytes[blockByteIndex], copyLen);
364  *read += copyLen;
365  blockByteIndex += copyLen;
366  file->mPosition += copyLen;
367 
368  if (blockByteIndex >= FsDefs::SECTOR_BYTES) { //read next block
369  blockByteIndex = 0;
370  file->mFlags.bits.sectorCacheInvalid = true;
371  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
372  switch (result) {
373  case FsDefs::RES_SUCCESS:
374  break;
375  default:
376  return result;
377  }
378  }
379  }
380  return FsDefs::RES_SUCCESS;
381 }
382 
383 FsDefs::RESULT Fs::internalWrite(const void* buffer, size_t len, size_t* transfered, class FsFile* file) {
384  *transfered = 0;
385  if (file->mClusterBegin == 0) { //File doesn't have a cluster yet
386  uint32_t freeCluster;
387  FsDefs::RESULT result = file->mPartition->getNextFreeCluster(file->mSector, &freeCluster);
388  if (result != FsDefs::RES_SUCCESS) {
389  return result;
390  }
391  file->mClusterBegin = freeCluster;
392  file->mCurrentLba = file->mPartition->getClusterBeginLba(freeCluster);
393  file->mPosition = 0;
394  file->mSize = 0;
395  file->mFlags.bits.unflushedSector = false;
396  file->mFlags.bits.unflushedDirectory = true;
397  internalFlush(file, file->mSector);
398  file->mFlags.bits.sectorCacheInvalid = true;
399  //Mark cluster as last
400  result = file->mPartition->setFatValue(file->mSector, freeCluster, FsDefs::FAT_LAST_CLUSTER);
401  if (result != FsDefs::RES_SUCCESS) {
402  return result;
403  }
404  }
405  size_t blockByteIndex = file->mPosition % FsDefs::SECTOR_BYTES;
406  while (*transfered < len) {
407  size_t copyLen = len - *transfered;
408  size_t leftOnSector = FsDefs::SECTOR_BYTES - blockByteIndex;
409  if (copyLen > leftOnSector) {
410  copyLen = leftOnSector;
411  }
412 
413  //If sector as not been read yet, read it
414  if ((copyLen < FsDefs::SECTOR_BYTES) || (blockByteIndex != 0)) {
415  if (file->mFlags.bits.sectorCacheInvalid) {
416  if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
417  return FsDefs::RES_DISK_ERROR;
418  }
419  file->mFlags.bits.sectorCacheInvalid = false;
420  }
421  }
422 
423  memcpy(&file->mSector->bytes[blockByteIndex], &((uint8_t*) buffer)[*transfered], copyLen);
424  *transfered += copyLen;
425  blockByteIndex += copyLen;
426  file->mPosition += copyLen;
427  file->mFlags.bits.unflushedSector = true;
428 
429  if (file->mPosition > file->mSize) {
430  file->mSize = file->mPosition;
431  file->mFlags.bits.unflushedDirectory = true;
432  }
433 
434  if (blockByteIndex >= FsDefs::SECTOR_BYTES) { //read next block
435  blockByteIndex = 0;
436  internalFlush(file, file->mSector);
437  file->mFlags.bits.sectorCacheInvalid = true;
438  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
439  switch (result) {
440  case FsDefs::RES_SUCCESS:
441  break;
442  case FsDefs::RES_EOF: {
443  uint32_t cluster = file->mPartition->getClusterFromLba(file->mCurrentLba);
444  FsDefs::RESULT result = file->mPartition->appendFreeCluster(file->mSector, &cluster);
445  if (result != FsDefs::RES_SUCCESS) {
446  return result;
447  }
448  file->mCurrentLba = file->mPartition->getClusterBeginLba(cluster);
449  break;
450  }
451  default:
452  return result;
453  }
454  }
455  }
456  return FsDefs::RES_SUCCESS;
457 }
458 
459 FsDefs::RESULT Fs::internalDel(class FsEntry* file) {
460  if (file->mFlags.bits.directory) {
461  uint32_t entryLba = file->mPartition->getFatSectorLba(file->mClusterBegin);
462  if (!file->mPartition->readBlocks(file->mSector, entryLba, 1)) {
463  return FsDefs::RES_DISK_ERROR;
464  }
465  uint16_t entryIndex = 0;
466  while (true) {
467  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[entryIndex++];
468  if (entry->shortEntry.name[0] == FsDefs::ENTRY_LAST) {
469  break;
470  }
471  if (entry->shortEntry.name[0] != FsDefs::ENTRY_UNUSED) {
472  return FsDefs::RES_FOLDER_NOT_EMPTY;
473  }
474 
475  if (entryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
476  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &entryLba);
477  if (result != FsDefs::RES_SUCCESS) {
478  return result;
479  }
480  if (!file->mPartition->readBlocks(file->mSector, entryLba, 1)) {
481  return FsDefs::RES_DISK_ERROR;
482  }
483  entryIndex = 0;
484  }
485  }
486  }
487 
488  file->mPartition->freeClusterChain(file->mSector, file->mClusterBegin);
489  file->mClusterBegin = 0;
490 
491  if (file->mLfnDirectoryEntryLba) { //Long file name
492  if (!file->mPartition->readBlocks(file->mSector, file->mLfnDirectoryEntryLba, 1)) {
493  return FsDefs::RES_DISK_ERROR;
494  }
495  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[file->mLfnDirectoryEntryIndex];
496  int entriesCount = (entry->longEntry.order & 0x3F);
497  uint16_t entryIndex = file->mLfnDirectoryEntryIndex;
498  uint32_t entryLba = file->mLfnDirectoryEntryLba;
499  while (true) {
500  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[entryIndex++];
501  entry->shortEntry.name[0] = FsDefs::ENTRY_UNUSED;
502  if (entriesCount-- <= 0) {
503  break;
504  }
505  if (entryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
506  if (!file->mPartition->writeBlocks(file->mSector, entryLba, 1)) {
507  return FsDefs::RES_DISK_ERROR;
508  }
509  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &entryLba);
510  if (result != FsDefs::RES_SUCCESS) {
511  return result;
512  }
513  if (!file->mPartition->readBlocks(file->mSector, entryLba, 1)) {
514  return FsDefs::RES_DISK_ERROR;
515  }
516  entryIndex = 0;
517  }
518  }
519  if (!file->mPartition->writeBlocks(file->mSector, entryLba, 1)) {
520  return FsDefs::RES_DISK_ERROR;
521  }
522  }
523  else {
524  if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
525  return FsDefs::RES_DISK_ERROR;
526  }
527  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
528  entry->shortEntry.name[0] = FsDefs::ENTRY_UNUSED;
529  if (!file->mPartition->writeBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
530  return FsDefs::RES_DISK_ERROR;
531  }
532  }
533  return FsDefs::RES_SUCCESS;
534 }
535 
536 FsDefs::RESULT Fs::internalSeek(class FsFile* file, size_t position) {
537  if (position == 0) {
538  file->mPosition = 0;
539  if (file->mClusterBegin) {
540  file->mCurrentLba = file->mPartition->getClusterBeginLba(LibEndian::leToHw(file->mClusterBegin));
541  }
542  return FsDefs::RES_SUCCESS;
543  }
544  if (!file->mClusterBegin) { //No clusters have been allocated yet
545  uint32_t freeCluster;
546  FsDefs::RESULT result = file->mPartition->getNextFreeCluster(file->mSector, &freeCluster);
547  file->mFlags.bits.sectorCacheInvalid = true;
548  if (result != FsDefs::RES_SUCCESS) {
549  return result;
550  }
551  file->mClusterBegin = freeCluster;
552  file->mCurrentLba = file->mPartition->getClusterBeginLba(LibEndian::leToHw(file->mClusterBegin));
553  }
554  size_t blockIdx = (position / FsDefs::SECTOR_BYTES);
555  for (size_t idx = 0; idx < blockIdx; idx++) {
556  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
557  file->mFlags.bits.sectorCacheInvalid = true;
558  switch (result) {
559  case FsDefs::RES_SUCCESS:
560  break;
561  case FsDefs::RES_EOF: {
562  uint32_t cluster = file->mPartition->getClusterFromLba(file->mCurrentLba);
563  FsDefs::RESULT result = file->mPartition->appendFreeCluster(file->mSector, &cluster);
564  if (result != FsDefs::RES_SUCCESS) {
565  return result;
566  }
567  file->mCurrentLba = file->mPartition->getClusterBeginLba(cluster);
568  break;
569  }
570  default:
571  return result;
572 
573  }
574  }
575  if (file->mSize < file->mPosition) {
576  file->mSize = file->mPosition;
577  }
578  file->mPosition = position;
579  return FsDefs::RES_SUCCESS;
580 }
581 
582 FsDefs::RESULT Fs::internalFlush(class FsFile* file, FsDefs::SECTOR* sector) {
583  if (file->mFlags.bits.unflushedSector) {
584  if (!file->mPartition->writeBlocks(file->mSector, file->mCurrentLba, 1)) {
585  return FsDefs::RES_DISK_ERROR;
586  }
587  file->mFlags.bits.unflushedSector = false;
588  }
589  if (file->mFlags.bits.unflushedDirectory) {
590  if (!file->mPartition->readBlocks(sector, file->mDirectoryEntryLba, 1)) {
591  return FsDefs::RES_DISK_ERROR;
592  }
593 
594  FsDefs::DIRECTORY_ENTRY* entry = &sector->dirEntries[file->mDirectoryEntryIndex];
595 
596  entry->shortEntry.fileSize = LibEndian::hwToLe(file->mSize);
597  entry->shortEntry.firstClusterHi = LibEndian::hwToLe((uint16_t) (file->mClusterBegin >> 16));
598  entry->shortEntry.firstClusterLo = LibEndian::hwToLe((uint16_t) (file->mClusterBegin & 0xFFFF));
599 
600  {
601  LibRtc::DATE_AND_TIME dateAndTime;
602  LibRtc::getCurrentDateAndTime(&dateAndTime);
603 
604  entry->shortEntry.lastModifiedTime.bits.hours = dateAndTime.time.hour;
605  entry->shortEntry.lastModifiedTime.bits.minutes = dateAndTime.time.min;
606  entry->shortEntry.lastModifiedTime.bits.seconds = dateAndTime.time.sec / 2;
607 
608  entry->shortEntry.lastModifiedDate.bits.day = dateAndTime.date.dayOfMonth;
609  entry->shortEntry.lastModifiedDate.bits.month = dateAndTime.date.month;
610  entry->shortEntry.lastModifiedDate.bits.year = dateAndTime.date.year - 1980;
611 
612  entry->shortEntry.lastAccess.value = entry->shortEntry.lastModifiedDate.value;
613  }
614 
615  if (!file->mPartition->writeBlocks(sector, file->mDirectoryEntryLba, 1)) {
616  return FsDefs::RES_DISK_ERROR;
617  }
618  file->mFlags.bits.unflushedDirectory = false;
619  }
620  return FsDefs::RES_SUCCESS;
621 }
622 
623 FsDefs::RESULT Fs::internalFormat(FsDrive * drive, FsDefs::SECTOR * sector, FsFormatCallback * listener) {
624  const static uint16_t bkBootSec = 6;
625  const static uint16_t rsvdSecCnt = 0x20;
626  const static uint8_t media = 0xF8;
627  const static uint8_t numFats = 2;
628 
629  drive->mIsReady = false;
630  if (!drive->init()) {
631  return FsDefs::RES_DISK_ERROR;
632  }
633 //Write boot sector
634  memset(sector, 0, sizeof(FsDefs::SECTOR));
635  uint8_t secPerClus = 8; //32 * 1024 / drive->mBytesPerSector; //uint8_t
636  uint32_t tmp1 = drive->mSectorsCount - rsvdSecCnt;
637  uint32_t tmp2 = ((256 * secPerClus) + 2) >> 1;
638  uint32_t fatSz32 = (tmp1 + (tmp2 - 1)) / tmp2;
639  {
640  FsDefs::BOOT_SECTOR* bootSector = (FsDefs::BOOT_SECTOR*) sector;
641  //bootSector->jmpBoot; //uint8_t[3]
642  //bootSector->oemName; //uint8_t[8]
643  memcpy(bootSector->jmpBoot, "\xEB\xFE\x90" "MSWIN4.1", 11);
644  bootSector->bytsPerSec = LibEndian::hwToLe((uint16_t) drive->mBytesPerSector); //uint16_t
645  bootSector->secPerClus = secPerClus;
646  bootSector->rsvdSecCnt = LibEndian::hwToLe((uint16_t) rsvdSecCnt); //uint16_t
647  bootSector->numFats = numFats; //uint8_t
648  //bootSector->rootEntCnt=0; //uint16_t
649  //bootSector->totSec16=0; //uint16_t
650  bootSector->media = media; //uint8_t
651  //bootSector->fatSz16=0; //uint16_t
652  //bootSector->secPerTrk=0; //uint16_t
653  //bootSector->numHeads=0; //uint16_t
654  //bootSector->hiddSec=0; //uint32_t
655  bootSector->totSec32 = LibEndian::hwToLe((uint32_t) drive->mSectorsCount); //uint32_t
656  bootSector->type.fat32.fatSz32 = LibEndian::hwToLe(fatSz32); //uint32_t
657  //bootSector->type.fat32.extFlags=0; //uint16_t
658  //bootSector->type.fat32.fsVer=0; //uint16_t
659  bootSector->type.fat32.rootClus = LibEndian::hwToLe((uint32_t) 2); //uint32_t
660  bootSector->type.fat32.fsInfo = LibEndian::hwToLe((uint16_t) 1); //uint16_t
661  bootSector->type.fat32.bkBootSec = LibEndian::hwToLe((uint16_t) bkBootSec); //uint16_t
662  //bootSector->type.fat32.reserved1; //uint8_t[12]
663  //bootSector->type.fat32.drvNum=0; //uint8_t
664  //bootSector->type.fat32.reserved2; //uint8_t
665  bootSector->type.fat32.bootSig = 0x29; //uint8_t
666  //bootSector->type.fat32.volId; //uint8_t[4]
667  uint32_t time = LibEndian::hwToLe((uint32_t) getCurrentTime());
668  memcpy(bootSector->type.fat32.volId, &time, 4);
669  //bootSector->type.fat32.volLab; //uint8_t[11]
670  //bootSector->type.fat32.filSysType; //uint8_t[8]
671  memcpy(bootSector->type.fat32.volLab, "NO NAME " "FAT32 ", 19);
672  //bootSector->type.fat32.reserved3; //uint8_t[420]
673  bootSector->type.fat32.checkAA55 = LibEndian::hwToLe((uint16_t) 0xAA55); //uint16_t
674  }
675 
676  if (!drive->writeBlocks(sector, 0, 1)) { //Write boot sector
677  return FsDefs::RES_DISK_ERROR;
678  }
679  if (!drive->writeBlocks(sector, bkBootSec, 1)) { //Write backup boot sector
680  return FsDefs::RES_DISK_ERROR;
681  }
682 
683 //Initialize FAT table
684  uint32_t lba = rsvdSecCnt;
685  for (uint8_t i = 0; i < numFats; i++) { //num fats
686  memset(sector, 0, sizeof(FsDefs::SECTOR));
687  sector->dwords[0] = media | 0xFFFFFF00;
688  sector->dwords[1] = 0xFFFFFFFF;
689  sector->dwords[2] = 0xFFFFFFFF;
690  if (!drive->writeBlocks(sector, lba++, 1)) {
691  return FsDefs::RES_DISK_ERROR;
692  }
693  memset(sector, 0, sizeof(FsDefs::SECTOR));
694  for (uint32_t j = 1; j < fatSz32; j++) {
695  if (!drive->writeBlocks(sector, lba++, 1)) {
696  return FsDefs::RES_DISK_ERROR;
697  }
698  if (listener) {
699  listener->formatStatusUpdate(i * fatSz32 + j, (fatSz32 * numFats) - 1);
700  }
701  }
702  }
703 
704 //Write rootDir
705  for (uint8_t i = 0; i < secPerClus; i++) {
706  if (!drive->writeBlocks(sector, lba++, 1)) {
707  return FsDefs::RES_DISK_ERROR;
708  }
709  }
710 
711 //Write fs info
712  {
713  FsDefs::FS_INFO* info = (FsDefs::FS_INFO*) sector;
714  info->leadSig = LibEndian::hwToLe((uint32_t) 0x41615252);
715  info->structSig = LibEndian::hwToLe((uint32_t) 0x61417272);
716  info->freeCount = LibEndian::hwToLe((uint32_t) ((drive->mSectorsCount - rsvdSecCnt - (fatSz32 * 2)) / secPerClus));
717  info->nextFree = LibEndian::hwToLe((uint32_t) 2);
718  info->checkAA55 = LibEndian::hwToLe((uint16_t) 0xAA55);
719  if (!drive->writeBlocks(sector, 1, 1)) {
720  return FsDefs::RES_DISK_ERROR;
721  }
722  if (!drive->writeBlocks(sector, 1 + bkBootSec, 1)) {
723  return FsDefs::RES_DISK_ERROR;
724  }
725  }
726 
727  return FsDefs::RES_SUCCESS;
728 }
729 
730 FsDefs::RESULT Fs::internalGetNextEntry(class FsEntry* file, FsDir::ENTRY_INFO* info) {
731  memset(info, 0, sizeof(FsDir::ENTRY_INFO));
732  if (file->mFlags.bits.sectorCacheInvalid) {
733  if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
734  return FsDefs::RES_DISK_ERROR;
735  }
736  file->mFlags.bits.sectorCacheInvalid = false;
737  }
738 
739  while (true) {
740  if (file->mPosition == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
741  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
742  switch (result) {
743  case FsDefs::RES_SUCCESS:
744  break;
745  case FsDefs::RES_EOF:
746  return FsDefs::RES_ENTRY_NOT_FOUND;
747  default:
748  return result;
749  }
750  if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
751  return FsDefs::RES_DISK_ERROR;
752  }
753  file->mPosition = 0;
754  }
755 
756  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[file->mPosition++];
757 
758  if (entry->shortEntry.name[0] == FsDefs::ENTRY_UNUSED) { //Free directory table
759  continue;
760  }
761  else if (entry->shortEntry.name[0] == FsDefs::ENTRY_LAST) { //Last entry
762  return FsDefs::RES_EOF;
763  }
764  else { //Check entry
765  if (isLongFilenameEntry(entry)) {
766  int nameLen;
767  int order;
768  int posOnEntry;
769  getLongNameLenAndOrder(&entry->longEntry, &posOnEntry, &order, &nameLen);
770  info->longFileName = (const char*) malloc(nameLen + 1);
771  if (!info->longFileName) {
772  return FsDefs::RES_OUT_OF_MEMORY;
773  }
774  char* dst = (char*) info->longFileName;
775  memset(dst, 'p', nameLen + 1);
776  dst += nameLen;
777  *dst-- = 0;
778  for (; order > 0; order--) {
779  for (; posOnEntry >= 0; posOnEntry--) {
780  uint8_t* p;
781  if (posOnEntry < 5) {
782  p = &entry->longEntry.name1[posOnEntry * 2];
783  }
784  else if (posOnEntry < 11) {
785  p = &entry->longEntry.name2[(posOnEntry - 5) * 2];
786  }
787  else {
788  p = &entry->longEntry.name3[(posOnEntry - 11) * 2];
789  }
790  uint16_t wideChar = ((uint16_t) p[0]) + (((uint16_t) p[1]) << 8);
791  *dst-- = getAsciiFromWideChar(wideChar);
792  }
793 
794  if (file->mPosition == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
795  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
796  switch (result) {
797  case FsDefs::RES_SUCCESS:
798  break;
799  case FsDefs::RES_EOF:
800  return FsDefs::RES_ENTRY_NOT_FOUND;
801  default:
802  return result;
803  }
804  if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
805  return FsDefs::RES_DISK_ERROR;
806  }
807  file->mPosition = 0;
808  }
809  entry = &file->mSector->dirEntries[file->mPosition++];
810  posOnEntry = 12;
811  }
812  initEntryInfoFromShortEntry(&entry->shortEntry, info);
813  return FsDefs::RES_SUCCESS;
814  }
815  else {
816  initEntryInfoFromShortEntry(&entry->shortEntry, info);
817  info->longFileName = 0;
818  return FsDefs::RES_SUCCESS;
819  }
820  }
821  }
822  return FsDefs::RES_NOT_IMPLEMENTED;
823 }
824 
826 //
828 FsDefs::RESULT Fs::createShortFilenameEntry(const char** name, class FsEntry* file, bool writeEntry) {
829  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
830  const char* path = *name;
831 
832  memset(entry->shortEntry.name, ' ', 11);
833 
834  for (int i = 0; i < 8; i++) {
835  if (*path == '.' || *path == '\0' || *path == '/') {
836  break;
837  }
838  entry->shortEntry.name[i] = toupper(*path);
839  path++;
840  }
841 
842  if (*path == '.') {
843  path++;
844  for (int i = 0; i < 3; i++) {
845  if (*path == '\0' || *path == '/') {
846  break;
847  }
848  entry->shortEntry.ext[i] = toupper(*path);
849  path++;
850  }
851  }
852 
853  entry->shortEntry.attributes.value = 0;
854  entry->shortEntry.attributes.bits.readOnly = file->mFlags.bits.readOnly;
855  entry->shortEntry.attributes.bits.directory = (*path == '/');
856 
857  entry->shortEntry.reserved = 0;
858 
859  {
860  LibRtc::DATE_AND_TIME dateAndTime;
861  LibRtc::getCurrentDateAndTime(&dateAndTime);
862 
863  entry->shortEntry.createTimeMs = (dateAndTime.time.sec & 0x1) ? 100 : 0;
864 
865  entry->shortEntry.createTime.bits.hours = dateAndTime.time.hour;
866  entry->shortEntry.createTime.bits.minutes = dateAndTime.time.min;
867  entry->shortEntry.createTime.bits.seconds = dateAndTime.time.sec / 2;
868 
869  entry->shortEntry.createDate.bits.day = dateAndTime.date.dayOfMonth;
870  entry->shortEntry.createDate.bits.month = dateAndTime.date.month;
871  entry->shortEntry.createDate.bits.year = dateAndTime.date.year - 1980;
872 
873  entry->shortEntry.lastModifiedTime.value = entry->shortEntry.createTime.value;
874  entry->shortEntry.lastModifiedDate.value = entry->shortEntry.createDate.value;
875 
876  entry->shortEntry.lastAccess.value = entry->shortEntry.createDate.value;
877  }
878  entry->shortEntry.fileSize = 0;
879 
880  if (entry->shortEntry.attributes.bits.directory) {
881  FsDefs::SECTOR* sector = (FsDefs::SECTOR*) malloc(sizeof(FsDefs::SECTOR));
882  if (!sector) {
883  return FsDefs::RES_OUT_OF_MEMORY;
884  }
885  uint32_t freeCluster;
886  FsDefs::RESULT result = file->mPartition->getNextFreeCluster(sector, &freeCluster);
887  if (result != FsDefs::RES_SUCCESS) {
888  return result;
889  }
890  file->mPartition->setFatValue(sector, freeCluster, FsDefs::FAT_LAST_CLUSTER);
891 
892  memset(sector, 0, sizeof(FsDefs::SECTOR));
893  if (!file->mPartition->writeBlocks(sector, file->mPartition->getClusterBeginLba(freeCluster), 1)) {
894  free(sector);
895  return FsDefs::RES_DISK_ERROR;
896  }
897  entry->shortEntry.firstClusterHi = LibEndian::hwToLe((uint16_t) (freeCluster >> 16));
898  entry->shortEntry.firstClusterLo = LibEndian::hwToLe((uint16_t) (freeCluster & 0xFFFF));
899  free(sector);
900  }
901  else {
902  entry->shortEntry.firstClusterHi = 0;
903  entry->shortEntry.firstClusterLo = 0;
904  file->mClusterBegin = 0;
905  }
906 
907  if (writeEntry) {
908  if (!file->mPartition->writeBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
909  return FsDefs::RES_DISK_ERROR;
910  }
911  }
912  if (*path == '/') {
913  path++;
914  }
915  *name = path;
916  return FsDefs::RES_SUCCESS;
917 }
918 
919 FsDefs::RESULT Fs::createLongFilenameEntry(const char** name, class FsEntry* file, int len) {
920 //Calculate required entries
921  size_t nameLen;
922  const char* path = *name;
923  size_t extIdx = 0;
924  for (nameLen = 0; nameLen < FsDefs::MAX_LFN_CHARS; nameLen++) {
925  char c = path[nameLen];
926  if (c == '.') {
927  extIdx = nameLen + 1;
928  }
929  if ((c == '\0') || (c == '/')) {
930  break;
931  }
932  }
933 
934  char shortName[13];
935  memset(shortName, ' ', 11);
936  shortName[11] = path[nameLen];
937  bool isLossy = (extIdx > 8) || (nameLen - extIdx > 3);
938 
939  for (size_t i = 0; (!extIdx || (i < (extIdx - 1))) && (i < nameLen) && (i < 8); i++) {
940  char c = toupper(path[i]);
941  if (getCharType(c) == CT_SHORT_ALLOWED) {
942  shortName[i] = c;
943  }
944  else {
945  shortName[i] = '_';
946  isLossy = true;
947  }
948  }
949 
950  if (extIdx) {
951  for (size_t i = extIdx, j = 8; (j < 11) && (i < nameLen); i++, j++) {
952  char c = toupper(path[i]);
953  if (getCharType(c) == CT_SHORT_ALLOWED) {
954  shortName[j] = c;
955  }
956  else {
957  shortName[j] = '_';
958  isLossy = true;
959  }
960  }
961  }
962 
963  size_t lfnRequiredEntriesCount = (nameLen + FsDefs::LFN_MAX_CHARS_PER_ENTRY - 1) / FsDefs::LFN_MAX_CHARS_PER_ENTRY;
964 
965  uint32_t currentLba = file->mDirectoryEntryLba;
966  uint32_t beginLba = 0;
967  uint32_t beginIndex = 0;
968  size_t freeEntriesFoundCount = 0;
969  unsigned int tailNumber = 0;
970  bool isCrossesEnd = false;
971  bool isRequiredEntriesFound = false;
972 
973  if (isLossy) {
974  tailNumber++;
975  shortName[6] = '~';
976  shortName[7] = '1';
977  }
978 
979  for (size_t currentIndex = 0;;) {
980  if (currentIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
981  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &currentLba);
982  if (result != FsDefs::RES_SUCCESS) {
983  return result;
984  }
985  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
986  return FsDefs::RES_DISK_ERROR;
987  }
988  currentIndex = 0;
989  }
990 
991  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[currentIndex];
992  if (entry->shortEntry.name[0] == FsDefs::ENTRY_LAST) {
993  if (freeEntriesFoundCount == 0) {
994  beginLba = currentLba;
995  beginIndex = currentIndex;
996  }
997  isCrossesEnd = true;
998  break;
999  }
1000 
1001  if (!isRequiredEntriesFound) {
1002  if (entry->shortEntry.name[0] == FsDefs::ENTRY_UNUSED) {
1003  if (freeEntriesFoundCount == 0) {
1004  beginLba = currentLba;
1005  beginIndex = currentIndex;
1006  }
1007  freeEntriesFoundCount++;
1008  }
1009  else {
1010  freeEntriesFoundCount = 0;
1011  }
1012  if (freeEntriesFoundCount > lfnRequiredEntriesCount) {
1013  isRequiredEntriesFound = true;
1014  }
1015  }
1016 
1017  if (!isLongFilenameEntry(entry)) {
1018  if (memcmp(shortName, entry->shortEntry.name, 11) == 0) {
1019  //The short name already exist, increment the tail number and iterate from beginning again
1020  unsigned int value = ++tailNumber;
1021  if (value > 999999) {
1022  return FsDefs::RES_NO_MORE_SFN_AVAILABLE;
1023  }
1024  char* p = &shortName[7];
1025  while (value > 0) {
1026  *p-- = value % 10;
1027  value /= 10;
1028  }
1029  *p = '~';
1030  currentIndex = 0;
1031  if (currentLba != file->mDirectoryEntryLba) {
1032  currentLba = file->mDirectoryEntryLba;
1033  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1034  return FsDefs::RES_DISK_ERROR;
1035  }
1036  }
1037  continue;
1038  }
1039  }
1040  currentIndex++;
1041  }
1042 
1043  uint8_t checkSum = calcSfnChecksum(shortName);
1044 
1045  if (currentLba != beginLba) {
1046  currentLba = beginLba;
1047  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1048  return FsDefs::RES_DISK_ERROR;
1049  }
1050  }
1051 
1052  file->mLfnDirectoryEntryLba = currentLba;
1053  file->mLfnDirectoryEntryIndex = beginIndex;
1054 
1055  size_t nameIndex = lfnRequiredEntriesCount * 13 - 1;
1056 
1057  for (size_t i = 0; i < lfnRequiredEntriesCount; i++) {
1058  FsDefs::LONG_DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[beginIndex].longEntry;
1059  entry->checksum = checkSum;
1060  entry->attributes.value = 0x0F;
1061  entry->type = 0;
1062  entry->firstCluster = 0;
1063  if (i == 0) {
1064  entry->order = 0x40 | (lfnRequiredEntriesCount - i);
1065  }
1066  else {
1067  entry->order = lfnRequiredEntriesCount - i;
1068  }
1069 
1070  for (int j = 12; j >= 0; j--) {
1071  uint8_t* p;
1072  if (j < 5) {
1073  p = &entry->name1[j * 2];
1074  }
1075  else if (j < 11) {
1076  p = &entry->name2[(j - 5) * 2];
1077  }
1078  else {
1079  p = &entry->name3[(j - 11) * 2];
1080  }
1081 
1082  if (nameIndex > nameLen) {
1083  p[0] = p[1] = 0xFF;
1084  }
1085  else if (nameIndex == nameLen) {
1086  p[0] = p[1] = 0;
1087  }
1088  else {
1089  setWideCharFromAscii(p, path[nameIndex]);
1090  }
1091  nameIndex--;
1092  }
1093 
1094  beginIndex++;
1095  if (beginIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
1096  if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
1097  return FsDefs::RES_DISK_ERROR;
1098  }
1099  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &currentLba);
1100  if (result != FsDefs::RES_SUCCESS) {
1101  return result;
1102  }
1103  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1104  return FsDefs::RES_DISK_ERROR;
1105  }
1106  beginIndex = 0;
1107  }
1108  }
1109 
1110  {
1111  file->mDirectoryEntryLba = currentLba;
1112  file->mDirectoryEntryIndex = beginIndex;
1113  //Add dot
1114  shortName[12] = shortName[11];
1115  shortName[11] = shortName[10];
1116  shortName[10] = shortName[9];
1117  shortName[9] = shortName[8];
1118  shortName[8] = '.';
1119  const char* p = shortName;
1120  createShortFilenameEntry(&p, file, false);
1121  }
1122 
1123  if (isCrossesEnd) {
1124  beginIndex++;
1125  if (beginIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
1126  if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
1127  return FsDefs::RES_DISK_ERROR;
1128  }
1129  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &currentLba);
1130  if (result != FsDefs::RES_SUCCESS) {
1131  return result;
1132  }
1133  if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1134  return FsDefs::RES_DISK_ERROR;
1135  }
1136  beginIndex = 0;
1137  }
1138  memset(&file->mSector->dirEntries[beginIndex], 0, sizeof(FsDefs::DIRECTORY_ENTRY));
1139  if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
1140  return FsDefs::RES_DISK_ERROR;
1141  }
1142 
1143  }
1144  else {
1145  if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
1146  return FsDefs::RES_DISK_ERROR;
1147  }
1148  }
1149 
1150  path += nameLen;
1151  if (*path == '/') {
1152  path++;
1153  }
1154  *name = path;
1155 
1156  return FsDefs::RES_SUCCESS;
1157 }
1158 
1159 FsDefs::RESULT Fs::checkShortFilename(const char** name, FsDefs::DIRECTORY_ENTRY* entry) {
1160  const char* p = *name;
1161 
1162  for (int i = 0; i < 8; i++) { //Check name
1163  uint8_t c1 = entry->shortEntry.name[i];
1164  if (c1 == ' ') {
1165  break;
1166  }
1167  uint8_t c2 = toupper(*p);
1168  if (c2 == '\0' || c2 == '/') {
1169  return FsDefs::RES_ENTRY_NOT_FOUND;
1170  }
1171  if (c1 != c2) {
1172  return FsDefs::RES_ENTRY_NOT_FOUND;
1173  }
1174  p++;
1175  }
1176 
1177  bool isNameEnd = false;
1178  if (*p == '\0' || *p == '/') {
1179  isNameEnd = true;
1180  }
1181 
1182  if (entry->shortEntry.ext[0] == ' ') { //No extension?
1183  if (!isNameEnd) {
1184  return FsDefs::RES_ENTRY_NOT_FOUND;;
1185  }
1186  }
1187  else {
1188  if (isNameEnd) {
1189  return FsDefs::RES_ENTRY_NOT_FOUND;;
1190  }
1191  if (*p++ != '.') {
1192  return FsDefs::RES_ENTRY_NOT_FOUND;;
1193  }
1194 
1195  for (int i = 0; i < 3; i++) { //Check name
1196  uint8_t c1 = entry->shortEntry.ext[i];
1197  if (c1 == ' ') {
1198  break;
1199  }
1200  if (!isNameEnd) {
1201  uint8_t c2 = toupper(*p);
1202  if (c2 == '\0' || c2 == '/') {
1203  return FsDefs::RES_ENTRY_NOT_FOUND;
1204  }
1205  if (c1 != c2) {
1206  return FsDefs::RES_ENTRY_NOT_FOUND;
1207  }
1208  p++;
1209  }
1210  }
1211  }
1212 
1213  if (*p == '/') {
1214  if (!entry->shortEntry.attributes.bits.directory) {
1215  return FsDefs::RES_ENTRY_NOT_FOUND;
1216  }
1217  p++;
1218  }
1219  else if (*p == '\0') {
1220  if (entry->shortEntry.attributes.bits.directory) {
1221  return FsDefs::RES_ENTRY_NOT_FOUND;
1222  }
1223  }
1224  else {
1225  return FsDefs::RES_ENTRY_NOT_FOUND;;
1226  }
1227  *name = p;
1228  return FsDefs::RES_SUCCESS;
1229 }
1230 
1231 FsDefs::RESULT Fs::checkLongFilename(const char** name, class FsEntry* file) {
1232  FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
1233  if (!(entry->longEntry.order & 0x40)) {
1234  return FsDefs::RES_ENTRY_NOT_FOUND;
1235  }
1236 //Start from filename end
1237  const char *parser = *name;
1238  while (true) {
1239  char c = *parser;
1240  if (c == '\0' || c == '/') {
1241  parser--;
1242  break;
1243  }
1244  parser++;
1245  }
1246  int nameLen;
1247  int order;
1248  int posOnEntry;
1249  getLongNameLenAndOrder(&entry->longEntry, &posOnEntry, &order, &nameLen);
1250 
1251  int pathNameLen = (parser - *name) + 1;
1252  if (nameLen != pathNameLen) {
1253  return FsDefs::RES_ENTRY_NOT_FOUND;
1254  }
1255  const char* end = parser + 1;
1256  uint8_t chksum = entry->longEntry.checksum;
1257  while (parser >= *name) {
1258  for (; posOnEntry >= 0; posOnEntry--) {
1259  uint8_t* p;
1260  if (posOnEntry < 5) {
1261  p = &entry->longEntry.name1[posOnEntry * 2];
1262  }
1263  else if (posOnEntry < 11) {
1264  p = &entry->longEntry.name2[(posOnEntry - 5) * 2];
1265  }
1266  else {
1267  p = &entry->longEntry.name3[(posOnEntry - 11) * 2];
1268  }
1269  uint16_t wideChar = ((uint16_t) p[0]) + (((uint16_t) p[1]) << 8);
1270  if (wideChar == 0) {
1271  return FsDefs::RES_ENTRY_NOT_FOUND;
1272  }
1273  if (wideChar == 0xFFFF) {
1274  return FsDefs::RES_ENTRY_NOT_FOUND;
1275  }
1276  if (toupper(*parser) != toupper(getAsciiFromWideChar(wideChar))) {
1277 
1278  return FsDefs::RES_ENTRY_NOT_FOUND;
1279  }
1280  parser--;
1281 
1282  }
1283  if (parser < *name) {
1284  break;
1285  }
1286  order--;
1287  if (order <= 0) {
1288  return FsDefs::RES_ENTRY_NOT_FOUND;
1289  }
1290  posOnEntry = 12;
1291  file->mDirectoryEntryIndex++;
1292  if (file->mDirectoryEntryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
1293  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mDirectoryEntryLba);
1294  switch (result) {
1295  case FsDefs::RES_SUCCESS:
1296  break;
1297  default:
1298  return FsDefs::RES_ENTRY_NOT_FOUND;
1299  }
1300  if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
1301  return FsDefs::RES_DISK_ERROR;
1302  }
1303  file->mDirectoryEntryIndex = 0;
1304  }
1305  entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
1306 
1307  if (entry->longEntry.order != order) {
1308  return FsDefs::RES_ENTRY_NOT_FOUND;
1309  }
1310  if (!isLongFilenameEntry(entry)) {
1311  return FsDefs::RES_ENTRY_NOT_FOUND;
1312  }
1313  if (chksum != entry->longEntry.checksum) {
1314  return FsDefs::RES_ENTRY_NOT_FOUND;
1315  }
1316  }
1317 
1318  file->mDirectoryEntryIndex++;
1319  if (file->mDirectoryEntryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) { //Read next table
1320  FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mDirectoryEntryLba);
1321  switch (result) {
1322  case FsDefs::RES_SUCCESS:
1323  break;
1324  default:
1325  return FsDefs::RES_ENTRY_NOT_FOUND;
1326  }
1327  if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
1328  return FsDefs::RES_DISK_ERROR;
1329  }
1330  file->mDirectoryEntryIndex = 0;
1331  }
1332  entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
1333  if (isLongFilenameEntry(entry)) {
1334  return FsDefs::RES_ENTRY_NOT_FOUND;
1335  }
1336 
1337  if (chksum != calcSfnChecksum(entry->shortEntry.name)) {
1338  return FsDefs::RES_ENTRY_NOT_FOUND;
1339  }
1340 
1341  if (*end == '/') {
1342  if (!entry->shortEntry.attributes.bits.directory) {
1343  return FsDefs::RES_ENTRY_NOT_FOUND;
1344  }
1345  end++;
1346  }
1347  else if (*end == '\0') {
1348  if (entry->shortEntry.attributes.bits.directory) {
1349  return FsDefs::RES_ENTRY_NOT_FOUND;
1350  }
1351  }
1352  else {
1353  return FsDefs::RES_ENTRY_NOT_FOUND;;
1354  }
1355  *name = end;
1356  return FsDefs::RES_SUCCESS;
1357 }
1358 
1359 Fs::FILENAME_TYPE Fs::getFilenameType(const char* name, int& len) {
1360 
1361  FILENAME_TYPE type = FT_SHORT_FILENAME;
1362  bool isDotFound = false;
1363  len = 0;
1364 
1365  while (true) {
1366  char c = name[len];
1367 
1368  if (c == '\0' || c == '/') { //End character
1369  return type;
1370  }
1371  len++;
1372 
1373  if (len > 255) {
1374  return FT_INVALID;
1375  }
1376  if (!isDotFound && len > 8) {
1377  type = FT_LONG_FILENAME;
1378  }
1379  if (len > 12) {
1380  type = FT_LONG_FILENAME;
1381  }
1382 
1383  switch (getCharType(c)) {
1384  case CT_INVALID:
1385  return FT_INVALID;
1386  case CT_LONG_ALLOWED:
1387  type = FT_LONG_FILENAME;
1388  continue;
1389  case CT_SHORT_ALLOWED:
1390  continue;
1391  case CT_DOT:
1392  if (isDotFound) {
1393  type = FT_LONG_FILENAME;
1394  }
1395  isDotFound = true;
1396  continue;
1397  }
1398 
1399  return FT_INVALID;
1400  }
1401 }
1402 
1403 bool Fs::isLongFilenameEntry(FsDefs::DIRECTORY_ENTRY* entry) {
1404  return ((entry->shortEntry.attributes.value & 0x0F) == 0x0F);
1405 }
1406 
1407 Fs::CHAR_TYPE Fs::getCharType(const char c) {
1408  const static char LFN_SPECIAL_CHARS[] = {
1409  '+', ',', ';', '=', '[', ']' };
1410  const static char SFN_SPECIAL_CHARS[] = {
1411  '$', '%', '\'', '-', '_', '@', '~', '`', '!', '(', ')', '{', '}', '^', '#', '&' };
1412 
1413  if (iscntrl(c)) { //Control characters are not allowed
1414  return CT_INVALID;
1415  }
1416 
1417  if (isdigit(c)) {
1418  return CT_SHORT_ALLOWED;;
1419  }
1420  if (isupper(c)) {
1421  return CT_SHORT_ALLOWED;;
1422  }
1423 
1424  if (c == ' ') {
1425  return CT_SHORT_ALLOWED;
1426  }
1427 
1428  if (c == '.') {
1429  return CT_DOT;
1430  }
1431 
1432  if (c > 127) {
1433  return CT_SHORT_ALLOWED;
1434  }
1435 
1436  for (unsigned int i = 0; i < sizeof(SFN_SPECIAL_CHARS); i++) {
1437  if (c == SFN_SPECIAL_CHARS[i]) {
1438  return CT_SHORT_ALLOWED;
1439  }
1440  }
1441 
1442  if (islower(c)) {
1443  return CT_LONG_ALLOWED;
1444  }
1445 
1446  for (unsigned int i = 0; i < sizeof(LFN_SPECIAL_CHARS); i++) {
1447  if (c == LFN_SPECIAL_CHARS[i]) {
1448  return CT_LONG_ALLOWED;
1449  }
1450  }
1451 
1452  return CT_INVALID;
1453 }
1454 
1455 uint8_t Fs::calcSfnChecksum(const char* name) {
1456  uint8_t sum = 0;
1457  for (int i = 0; i < 11; i++) {
1458  sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *name++;
1459  }
1460  return sum;
1461 }
1462 
1463 void Fs::setWideCharFromAscii(uint8_t*p, char value) {
1464  p[0] = (uint8_t) value;
1465  p[1] = 0;
1466 }
1467 
1468 char Fs::getAsciiFromWideChar(uint16_t value) {
1469  return (char) (value & 0xFF);
1470 }
1471 
1472 void Fs::initEntryInfoFromShortEntry(FsDefs::SHORT_DIRECTORY_ENTRY* entry, FsDir::ENTRY_INFO* info) {
1473  char* p = info->shortFileName;
1474  for (int i = 0; i < 8; i++) {
1475  char c = entry->name[i];
1476  if (c != ' ') {
1477  *p++ = c;
1478  }
1479  }
1480  if (entry->ext[0] != ' ') {
1481  *p++ = '.';
1482  for (int i = 0; i < 3; i++) {
1483  char c = entry->ext[i];
1484  if (c != ' ') {
1485  *p++ = c;
1486  }
1487  }
1488  }
1489 
1490  info->attributes = entry->attributes;
1491  info->createTimeMs = entry->createTimeMs;
1492  info->createTime = entry->createTime;
1493  info->createDate = entry->createDate;
1494  info->lastAccess = entry->lastAccess;
1495  info->lastModifiedTime = entry->lastModifiedTime;
1496  info->lastModifiedDate = entry->lastModifiedDate;
1497  info->fileSize = entry->fileSize;
1498 }
1499 
1500 void Fs::getLongNameLenAndOrder(FsDefs::LONG_DIRECTORY_ENTRY* entry, int* lastOnEntry, int* order, int* nameLen) {
1501  int i;
1502  *nameLen = 0;
1503  for (i = 12; i > 0; i--) {
1504  uint8_t* p;
1505  if (i < 5) {
1506  p = &entry->name1[i * 2];
1507  }
1508  else if (i < 11) {
1509  p = &entry->name2[(i - 5) * 2];
1510  }
1511  else {
1512  p = &entry->name3[(i - 11) * 2];
1513  }
1514  uint16_t wideChar = ((uint16_t) p[0]) + (((uint16_t) p[1]) << 8);
1515  if (wideChar == 0) {
1516  *nameLen = i;
1517  break;
1518  }
1519  if (wideChar != 0xFFFF) {
1520  *nameLen = 13;
1521  i = 13;
1522  break;
1523  }
1524  }
1525  *lastOnEntry = i - 1;
1526  *order = entry->order & 0x3F;
1527  *nameLen += (*order - 1) * 13;
1528 }
1529 
1530 uint32_t Fs::getCurrentTime() {
1531  LibRtc::DATE_AND_TIME dateAndTime;
1532  LibRtc::getCurrentDateAndTime(&dateAndTime);
1533  return ((uint32_t) (dateAndTime.date.year - 1980) << 25) | //
1534  ((uint32_t) dateAndTime.date.month << 21) | //
1535  ((uint32_t) dateAndTime.date.dayOfMonth << 16) | //
1536  ((uint32_t) dateAndTime.time.hour << 11) | //
1537  ((uint32_t) dateAndTime.time.min << 5) | //
1538  ((uint32_t) dateAndTime.time.sec >> 1);
1539 }
1540