8 #include "LibEndian.hpp"
16 FsPartition** Fs::sPartitions;
17 size_t Fs::sPartitionsCount;
22 void Fs::init(FsPartition* partitions[],
size_t partitionsCount) {
23 sPartitions = partitions;
24 sPartitionsCount = partitionsCount;
27 FsDefs::RESULT Fs::format(FsDrive* drive, FsFormatCallback* listener) {
28 FsDefs::SECTOR* sector = (FsDefs::SECTOR*) malloc(
sizeof(sector));
30 return FsDefs::RES_OUT_OF_MEMORY;
33 FsDefs::RESULT result = internalFormat(drive, sector, listener);
42 FsDefs::RESULT Fs::open(
const char* path,
class FsEntry* file) {
44 unsigned int partitionIdx = 0;
45 for (; pathIdx < 2; pathIdx++) {
46 if (path[pathIdx] ==
'/') {
49 if (path[pathIdx] <
'0' && path[0] >
'0') {
50 return FsDefs::RES_INVALID_PATH;
53 partitionIdx += path[pathIdx] -
'0';
56 if (partitionIdx >= sPartitionsCount) {
57 return FsDefs::RES_INVALID_PARTITION;
60 if (path[pathIdx] ==
'/') {
63 else if (!path[pathIdx]) {
64 return FsDefs::RES_INVALID_PATH;
67 file->mPartition = sPartitions[partitionIdx];
69 file->mPartition->lock();
70 FsDefs::RESULT result = internalOpen(&path[pathIdx], file);
71 file->mPartition->unlock();
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;
80 FsDefs::RESULT result = internalRead(buffer, len, read, file);
81 file->mPartition->unlock();
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();
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();
99 FsDefs::RESULT Fs::flush(FsFile* file) {
100 file->mPartition->lock();
101 FsDefs::SECTOR* sector = (FsDefs::SECTOR*) malloc(
sizeof(FsDefs::SECTOR));
103 file->mPartition->unlock();
104 return FsDefs::RES_OUT_OF_MEMORY;
106 FsDefs::RESULT result = internalFlush(file, sector);
108 file->mPartition->unlock();
112 FsDefs::RESULT Fs::del(
class FsEntry* file) {
113 file->mPartition->lock();
114 FsDefs::RESULT result = internalDel(file);
115 file->mPartition->unlock();
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();
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) {
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));
144 return FsDefs::RES_SUCCESS;
148 uint32_t currentLba = file->mPartition->getRootClusterLba();
149 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
150 return FsDefs::RES_DISK_ERROR;
152 file->mDirectoryEntryLba = currentLba;
154 uint32_t unusedEntryLba = 0;
155 uint32_t unusedEntryIndex = 0;
157 for (
size_t entryIndex = 0;;) {
158 if (entryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
159 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, ¤tLba);
161 case FsDefs::RES_SUCCESS:
163 case FsDefs::RES_EOF:
164 return FsDefs::RES_ENTRY_NOT_FOUND;
168 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
169 return FsDefs::RES_DISK_ERROR;
174 FsDefs::RESULT result = FsDefs::RES_ENTRY_NOT_FOUND;
175 FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[entryIndex];
177 if (entry->shortEntry.name[0] == FsDefs::ENTRY_UNUSED) {
178 if (unusedEntryLba == 0) {
179 unusedEntryLba = currentLba;
180 unusedEntryIndex = entryIndex;
183 else if (entry->shortEntry.name[0] == FsDefs::ENTRY_LAST) {
184 if (file->mFlags.bits.createAlways) {
186 FILENAME_TYPE type = getFilenameType(path, len);
189 return FsDefs::RES_INVALID_PATH;
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) {
197 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, ¤tLba);
198 if (result != FsDefs::RES_SUCCESS) {
201 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
202 return FsDefs::RES_DISK_ERROR;
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;
210 if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
211 return FsDefs::RES_DISK_ERROR;
216 FsDefs::DIRECTORY_ENTRY* lastEntry = &file->mSector->dirEntries[entryIndex + 1];
217 memset(lastEntry, 0,
sizeof(FsDefs::DIRECTORY_ENTRY));
221 if (unusedEntryLba != currentLba) {
222 if (!file->mPartition->readBlocks(file->mSector, unusedEntryLba, 1)) {
223 return FsDefs::RES_DISK_ERROR;
226 currentLba = file->mDirectoryEntryLba = unusedEntryLba;
227 entryIndex = file->mDirectoryEntryIndex = unusedEntryIndex;
229 result = createShortFilenameEntry(&path, file,
true);
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;
237 result = createLongFilenameEntry(&path, file, len);
241 if (result != FsDefs::RES_SUCCESS) {
244 entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
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];
254 file->mDirectoryEntryLba = currentLba;
255 file->mDirectoryEntryIndex = entryIndex;
256 file->mLfnDirectoryEntryLba = file->mLfnDirectoryEntryIndex = 0;
257 result = checkShortFilename(&path, entry);
261 if (result == FsDefs::RES_SUCCESS) {
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));
267 file->mFlags.bits.directory = entry->shortEntry.attributes.bits.directory;
268 if (file->mFlags.bits.createAlways) {
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;
278 file->mPartition->freeClusterChain(file->mSector, file->mClusterBegin);
281 file->mSize = LibEndian::leToHw(entry->shortEntry.fileSize);
282 if (!file->mFlags.bits.readOnly && entry->shortEntry.attributes.bits.readOnly) {
283 return FsDefs::RES_DENIED;
286 return FsDefs::RES_SUCCESS;
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;
293 file->mDirectoryEntryLba = currentLba;
296 unusedEntryIndex = 0;
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;
310 partition->mDrive->mIsReady =
true;
312 if (!partition->readBlocks(sector, 0, 1)) {
313 return FsDefs::RES_DISK_ERROR;
316 FsDefs::MBR* mbr = (FsDefs::MBR*) sector;
317 if (LibEndian::leToHw(mbr->checkAA55) != 0xAA55) {
318 return FsDefs::RES_NOT_FORMATTED;
321 FsDefs::BOOT_SECTOR* bootSector = (FsDefs::BOOT_SECTOR*) sector;
322 if (memcmp(bootSector->type.fat32.filSysType,
"FAT", 3) == 0) {
323 if (partition->mIndexOnDrive == 0) {
324 if (partition->initFromBootSector(bootSector, 0) == FsDefs::RES_SUCCESS) {
325 return FsDefs::RES_SUCCESS;
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;
337 FsDefs::BOOT_SECTOR* bootSector = (FsDefs::BOOT_SECTOR*) sector;
338 if (partition->initFromBootSector(bootSector, partitionBeginLba) == FsDefs::RES_SUCCESS) {
339 return FsDefs::RES_SUCCESS;
343 return FsDefs::RES_NOT_FORMATTED;
346 FsDefs::RESULT Fs::internalRead(
void* buffer,
size_t len,
size_t* read,
class FsFile* file) {
348 size_t blockByteIndex = file->mPosition % FsDefs::SECTOR_BYTES;
349 while (*read < len) {
351 if (file->mFlags.bits.sectorCacheInvalid) {
352 if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
353 return FsDefs::RES_DISK_ERROR;
355 file->mFlags.bits.sectorCacheInvalid =
false;
358 int copyLen = len - *read;
359 int leftOnSector = FsDefs::SECTOR_BYTES - blockByteIndex;
360 if (copyLen > leftOnSector) {
361 copyLen = leftOnSector;
363 memcpy(&((uint8_t*) buffer)[*read], &file->mSector->bytes[blockByteIndex], copyLen);
365 blockByteIndex += copyLen;
366 file->mPosition += copyLen;
368 if (blockByteIndex >= FsDefs::SECTOR_BYTES) {
370 file->mFlags.bits.sectorCacheInvalid =
true;
371 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
373 case FsDefs::RES_SUCCESS:
380 return FsDefs::RES_SUCCESS;
383 FsDefs::RESULT Fs::internalWrite(
const void* buffer,
size_t len,
size_t* transfered,
class FsFile* file) {
385 if (file->mClusterBegin == 0) {
386 uint32_t freeCluster;
387 FsDefs::RESULT result = file->mPartition->getNextFreeCluster(file->mSector, &freeCluster);
388 if (result != FsDefs::RES_SUCCESS) {
391 file->mClusterBegin = freeCluster;
392 file->mCurrentLba = file->mPartition->getClusterBeginLba(freeCluster);
395 file->mFlags.bits.unflushedSector =
false;
396 file->mFlags.bits.unflushedDirectory =
true;
397 internalFlush(file, file->mSector);
398 file->mFlags.bits.sectorCacheInvalid =
true;
400 result = file->mPartition->setFatValue(file->mSector, freeCluster, FsDefs::FAT_LAST_CLUSTER);
401 if (result != FsDefs::RES_SUCCESS) {
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;
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;
419 file->mFlags.bits.sectorCacheInvalid =
false;
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;
429 if (file->mPosition > file->mSize) {
430 file->mSize = file->mPosition;
431 file->mFlags.bits.unflushedDirectory =
true;
434 if (blockByteIndex >= FsDefs::SECTOR_BYTES) {
436 internalFlush(file, file->mSector);
437 file->mFlags.bits.sectorCacheInvalid =
true;
438 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
440 case FsDefs::RES_SUCCESS:
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) {
448 file->mCurrentLba = file->mPartition->getClusterBeginLba(cluster);
456 return FsDefs::RES_SUCCESS;
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;
465 uint16_t entryIndex = 0;
467 FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[entryIndex++];
468 if (entry->shortEntry.name[0] == FsDefs::ENTRY_LAST) {
471 if (entry->shortEntry.name[0] != FsDefs::ENTRY_UNUSED) {
472 return FsDefs::RES_FOLDER_NOT_EMPTY;
475 if (entryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
476 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &entryLba);
477 if (result != FsDefs::RES_SUCCESS) {
480 if (!file->mPartition->readBlocks(file->mSector, entryLba, 1)) {
481 return FsDefs::RES_DISK_ERROR;
488 file->mPartition->freeClusterChain(file->mSector, file->mClusterBegin);
489 file->mClusterBegin = 0;
491 if (file->mLfnDirectoryEntryLba) {
492 if (!file->mPartition->readBlocks(file->mSector, file->mLfnDirectoryEntryLba, 1)) {
493 return FsDefs::RES_DISK_ERROR;
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;
500 FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[entryIndex++];
501 entry->shortEntry.name[0] = FsDefs::ENTRY_UNUSED;
502 if (entriesCount-- <= 0) {
505 if (entryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
506 if (!file->mPartition->writeBlocks(file->mSector, entryLba, 1)) {
507 return FsDefs::RES_DISK_ERROR;
509 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &entryLba);
510 if (result != FsDefs::RES_SUCCESS) {
513 if (!file->mPartition->readBlocks(file->mSector, entryLba, 1)) {
514 return FsDefs::RES_DISK_ERROR;
519 if (!file->mPartition->writeBlocks(file->mSector, entryLba, 1)) {
520 return FsDefs::RES_DISK_ERROR;
524 if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
525 return FsDefs::RES_DISK_ERROR;
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;
533 return FsDefs::RES_SUCCESS;
536 FsDefs::RESULT Fs::internalSeek(
class FsFile* file,
size_t position) {
539 if (file->mClusterBegin) {
540 file->mCurrentLba = file->mPartition->getClusterBeginLba(LibEndian::leToHw(file->mClusterBegin));
542 return FsDefs::RES_SUCCESS;
544 if (!file->mClusterBegin) {
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) {
551 file->mClusterBegin = freeCluster;
552 file->mCurrentLba = file->mPartition->getClusterBeginLba(LibEndian::leToHw(file->mClusterBegin));
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;
559 case FsDefs::RES_SUCCESS:
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) {
567 file->mCurrentLba = file->mPartition->getClusterBeginLba(cluster);
575 if (file->mSize < file->mPosition) {
576 file->mSize = file->mPosition;
578 file->mPosition = position;
579 return FsDefs::RES_SUCCESS;
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;
587 file->mFlags.bits.unflushedSector =
false;
589 if (file->mFlags.bits.unflushedDirectory) {
590 if (!file->mPartition->readBlocks(sector, file->mDirectoryEntryLba, 1)) {
591 return FsDefs::RES_DISK_ERROR;
594 FsDefs::DIRECTORY_ENTRY* entry = §or->dirEntries[file->mDirectoryEntryIndex];
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));
601 LibRtc::DATE_AND_TIME dateAndTime;
602 LibRtc::getCurrentDateAndTime(&dateAndTime);
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;
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;
612 entry->shortEntry.lastAccess.value = entry->shortEntry.lastModifiedDate.value;
615 if (!file->mPartition->writeBlocks(sector, file->mDirectoryEntryLba, 1)) {
616 return FsDefs::RES_DISK_ERROR;
618 file->mFlags.bits.unflushedDirectory =
false;
620 return FsDefs::RES_SUCCESS;
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;
629 drive->mIsReady =
false;
630 if (!drive->init()) {
631 return FsDefs::RES_DISK_ERROR;
634 memset(sector, 0,
sizeof(FsDefs::SECTOR));
635 uint8_t secPerClus = 8;
636 uint32_t tmp1 = drive->mSectorsCount - rsvdSecCnt;
637 uint32_t tmp2 = ((256 * secPerClus) + 2) >> 1;
638 uint32_t fatSz32 = (tmp1 + (tmp2 - 1)) / tmp2;
640 FsDefs::BOOT_SECTOR* bootSector = (FsDefs::BOOT_SECTOR*) sector;
643 memcpy(bootSector->jmpBoot,
"\xEB\xFE\x90" "MSWIN4.1", 11);
644 bootSector->bytsPerSec = LibEndian::hwToLe((uint16_t) drive->mBytesPerSector);
645 bootSector->secPerClus = secPerClus;
646 bootSector->rsvdSecCnt = LibEndian::hwToLe((uint16_t) rsvdSecCnt);
647 bootSector->numFats = numFats;
650 bootSector->media = media;
655 bootSector->totSec32 = LibEndian::hwToLe((uint32_t) drive->mSectorsCount);
656 bootSector->type.fat32.fatSz32 = LibEndian::hwToLe(fatSz32);
659 bootSector->type.fat32.rootClus = LibEndian::hwToLe((uint32_t) 2);
660 bootSector->type.fat32.fsInfo = LibEndian::hwToLe((uint16_t) 1);
661 bootSector->type.fat32.bkBootSec = LibEndian::hwToLe((uint16_t) bkBootSec);
665 bootSector->type.fat32.bootSig = 0x29;
667 uint32_t time = LibEndian::hwToLe((uint32_t) getCurrentTime());
668 memcpy(bootSector->type.fat32.volId, &time, 4);
671 memcpy(bootSector->type.fat32.volLab,
"NO NAME " "FAT32 ", 19);
673 bootSector->type.fat32.checkAA55 = LibEndian::hwToLe((uint16_t) 0xAA55);
676 if (!drive->writeBlocks(sector, 0, 1)) {
677 return FsDefs::RES_DISK_ERROR;
679 if (!drive->writeBlocks(sector, bkBootSec, 1)) {
680 return FsDefs::RES_DISK_ERROR;
684 uint32_t lba = rsvdSecCnt;
685 for (uint8_t i = 0; i < numFats; i++) {
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;
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;
699 listener->formatStatusUpdate(i * fatSz32 + j, (fatSz32 * numFats) - 1);
705 for (uint8_t i = 0; i < secPerClus; i++) {
706 if (!drive->writeBlocks(sector, lba++, 1)) {
707 return FsDefs::RES_DISK_ERROR;
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;
722 if (!drive->writeBlocks(sector, 1 + bkBootSec, 1)) {
723 return FsDefs::RES_DISK_ERROR;
727 return FsDefs::RES_SUCCESS;
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;
736 file->mFlags.bits.sectorCacheInvalid =
false;
740 if (file->mPosition == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
741 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
743 case FsDefs::RES_SUCCESS:
745 case FsDefs::RES_EOF:
746 return FsDefs::RES_ENTRY_NOT_FOUND;
750 if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
751 return FsDefs::RES_DISK_ERROR;
756 FsDefs::DIRECTORY_ENTRY* entry = &file->mSector->dirEntries[file->mPosition++];
758 if (entry->shortEntry.name[0] == FsDefs::ENTRY_UNUSED) {
761 else if (entry->shortEntry.name[0] == FsDefs::ENTRY_LAST) {
762 return FsDefs::RES_EOF;
765 if (isLongFilenameEntry(entry)) {
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;
774 char* dst = (
char*) info->longFileName;
775 memset(dst,
'p', nameLen + 1);
778 for (; order > 0; order--) {
779 for (; posOnEntry >= 0; posOnEntry--) {
781 if (posOnEntry < 5) {
782 p = &entry->longEntry.name1[posOnEntry * 2];
784 else if (posOnEntry < 11) {
785 p = &entry->longEntry.name2[(posOnEntry - 5) * 2];
788 p = &entry->longEntry.name3[(posOnEntry - 11) * 2];
790 uint16_t wideChar = ((uint16_t) p[0]) + (((uint16_t) p[1]) << 8);
791 *dst-- = getAsciiFromWideChar(wideChar);
794 if (file->mPosition == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
795 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mCurrentLba);
797 case FsDefs::RES_SUCCESS:
799 case FsDefs::RES_EOF:
800 return FsDefs::RES_ENTRY_NOT_FOUND;
804 if (!file->mPartition->readBlocks(file->mSector, file->mCurrentLba, 1)) {
805 return FsDefs::RES_DISK_ERROR;
809 entry = &file->mSector->dirEntries[file->mPosition++];
812 initEntryInfoFromShortEntry(&entry->shortEntry, info);
813 return FsDefs::RES_SUCCESS;
816 initEntryInfoFromShortEntry(&entry->shortEntry, info);
817 info->longFileName = 0;
818 return FsDefs::RES_SUCCESS;
822 return FsDefs::RES_NOT_IMPLEMENTED;
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;
832 memset(entry->shortEntry.name,
' ', 11);
834 for (
int i = 0; i < 8; i++) {
835 if (*path ==
'.' || *path ==
'\0' || *path ==
'/') {
838 entry->shortEntry.name[i] = toupper(*path);
844 for (
int i = 0; i < 3; i++) {
845 if (*path ==
'\0' || *path ==
'/') {
848 entry->shortEntry.ext[i] = toupper(*path);
853 entry->shortEntry.attributes.value = 0;
854 entry->shortEntry.attributes.bits.readOnly = file->mFlags.bits.readOnly;
855 entry->shortEntry.attributes.bits.directory = (*path ==
'/');
857 entry->shortEntry.reserved = 0;
860 LibRtc::DATE_AND_TIME dateAndTime;
861 LibRtc::getCurrentDateAndTime(&dateAndTime);
863 entry->shortEntry.createTimeMs = (dateAndTime.time.sec & 0x1) ? 100 : 0;
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;
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;
873 entry->shortEntry.lastModifiedTime.value = entry->shortEntry.createTime.value;
874 entry->shortEntry.lastModifiedDate.value = entry->shortEntry.createDate.value;
876 entry->shortEntry.lastAccess.value = entry->shortEntry.createDate.value;
878 entry->shortEntry.fileSize = 0;
880 if (entry->shortEntry.attributes.bits.directory) {
881 FsDefs::SECTOR* sector = (FsDefs::SECTOR*) malloc(
sizeof(FsDefs::SECTOR));
883 return FsDefs::RES_OUT_OF_MEMORY;
885 uint32_t freeCluster;
886 FsDefs::RESULT result = file->mPartition->getNextFreeCluster(sector, &freeCluster);
887 if (result != FsDefs::RES_SUCCESS) {
890 file->mPartition->setFatValue(sector, freeCluster, FsDefs::FAT_LAST_CLUSTER);
892 memset(sector, 0,
sizeof(FsDefs::SECTOR));
893 if (!file->mPartition->writeBlocks(sector, file->mPartition->getClusterBeginLba(freeCluster), 1)) {
895 return FsDefs::RES_DISK_ERROR;
897 entry->shortEntry.firstClusterHi = LibEndian::hwToLe((uint16_t) (freeCluster >> 16));
898 entry->shortEntry.firstClusterLo = LibEndian::hwToLe((uint16_t) (freeCluster & 0xFFFF));
902 entry->shortEntry.firstClusterHi = 0;
903 entry->shortEntry.firstClusterLo = 0;
904 file->mClusterBegin = 0;
908 if (!file->mPartition->writeBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
909 return FsDefs::RES_DISK_ERROR;
916 return FsDefs::RES_SUCCESS;
919 FsDefs::RESULT Fs::createLongFilenameEntry(
const char** name,
class FsEntry* file,
int len) {
922 const char* path = *name;
924 for (nameLen = 0; nameLen < FsDefs::MAX_LFN_CHARS; nameLen++) {
925 char c = path[nameLen];
927 extIdx = nameLen + 1;
929 if ((c ==
'\0') || (c ==
'/')) {
935 memset(shortName,
' ', 11);
936 shortName[11] = path[nameLen];
937 bool isLossy = (extIdx > 8) || (nameLen - extIdx > 3);
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) {
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) {
963 size_t lfnRequiredEntriesCount = (nameLen + FsDefs::LFN_MAX_CHARS_PER_ENTRY - 1) / FsDefs::LFN_MAX_CHARS_PER_ENTRY;
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;
979 for (
size_t currentIndex = 0;;) {
980 if (currentIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
981 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, ¤tLba);
982 if (result != FsDefs::RES_SUCCESS) {
985 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
986 return FsDefs::RES_DISK_ERROR;
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;
1001 if (!isRequiredEntriesFound) {
1002 if (entry->shortEntry.name[0] == FsDefs::ENTRY_UNUSED) {
1003 if (freeEntriesFoundCount == 0) {
1004 beginLba = currentLba;
1005 beginIndex = currentIndex;
1007 freeEntriesFoundCount++;
1010 freeEntriesFoundCount = 0;
1012 if (freeEntriesFoundCount > lfnRequiredEntriesCount) {
1013 isRequiredEntriesFound =
true;
1017 if (!isLongFilenameEntry(entry)) {
1018 if (memcmp(shortName, entry->shortEntry.name, 11) == 0) {
1020 unsigned int value = ++tailNumber;
1021 if (value > 999999) {
1022 return FsDefs::RES_NO_MORE_SFN_AVAILABLE;
1024 char* p = &shortName[7];
1031 if (currentLba != file->mDirectoryEntryLba) {
1032 currentLba = file->mDirectoryEntryLba;
1033 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1034 return FsDefs::RES_DISK_ERROR;
1043 uint8_t checkSum = calcSfnChecksum(shortName);
1045 if (currentLba != beginLba) {
1046 currentLba = beginLba;
1047 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1048 return FsDefs::RES_DISK_ERROR;
1052 file->mLfnDirectoryEntryLba = currentLba;
1053 file->mLfnDirectoryEntryIndex = beginIndex;
1055 size_t nameIndex = lfnRequiredEntriesCount * 13 - 1;
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;
1062 entry->firstCluster = 0;
1064 entry->order = 0x40 | (lfnRequiredEntriesCount - i);
1067 entry->order = lfnRequiredEntriesCount - i;
1070 for (
int j = 12; j >= 0; j--) {
1073 p = &entry->name1[j * 2];
1076 p = &entry->name2[(j - 5) * 2];
1079 p = &entry->name3[(j - 11) * 2];
1082 if (nameIndex > nameLen) {
1085 else if (nameIndex == nameLen) {
1089 setWideCharFromAscii(p, path[nameIndex]);
1095 if (beginIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
1096 if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
1097 return FsDefs::RES_DISK_ERROR;
1099 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, ¤tLba);
1100 if (result != FsDefs::RES_SUCCESS) {
1103 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1104 return FsDefs::RES_DISK_ERROR;
1111 file->mDirectoryEntryLba = currentLba;
1112 file->mDirectoryEntryIndex = beginIndex;
1114 shortName[12] = shortName[11];
1115 shortName[11] = shortName[10];
1116 shortName[10] = shortName[9];
1117 shortName[9] = shortName[8];
1119 const char* p = shortName;
1120 createShortFilenameEntry(&p, file,
false);
1125 if (beginIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
1126 if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
1127 return FsDefs::RES_DISK_ERROR;
1129 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, ¤tLba);
1130 if (result != FsDefs::RES_SUCCESS) {
1133 if (!file->mPartition->readBlocks(file->mSector, currentLba, 1)) {
1134 return FsDefs::RES_DISK_ERROR;
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;
1145 if (!file->mPartition->writeBlocks(file->mSector, currentLba, 1)) {
1146 return FsDefs::RES_DISK_ERROR;
1156 return FsDefs::RES_SUCCESS;
1159 FsDefs::RESULT Fs::checkShortFilename(
const char** name, FsDefs::DIRECTORY_ENTRY* entry) {
1160 const char* p = *name;
1162 for (
int i = 0; i < 8; i++) {
1163 uint8_t c1 = entry->shortEntry.name[i];
1167 uint8_t c2 = toupper(*p);
1168 if (c2 ==
'\0' || c2 ==
'/') {
1169 return FsDefs::RES_ENTRY_NOT_FOUND;
1172 return FsDefs::RES_ENTRY_NOT_FOUND;
1177 bool isNameEnd =
false;
1178 if (*p ==
'\0' || *p ==
'/') {
1182 if (entry->shortEntry.ext[0] ==
' ') {
1184 return FsDefs::RES_ENTRY_NOT_FOUND;;
1189 return FsDefs::RES_ENTRY_NOT_FOUND;;
1192 return FsDefs::RES_ENTRY_NOT_FOUND;;
1195 for (
int i = 0; i < 3; i++) {
1196 uint8_t c1 = entry->shortEntry.ext[i];
1201 uint8_t c2 = toupper(*p);
1202 if (c2 ==
'\0' || c2 ==
'/') {
1203 return FsDefs::RES_ENTRY_NOT_FOUND;
1206 return FsDefs::RES_ENTRY_NOT_FOUND;
1214 if (!entry->shortEntry.attributes.bits.directory) {
1215 return FsDefs::RES_ENTRY_NOT_FOUND;
1219 else if (*p ==
'\0') {
1220 if (entry->shortEntry.attributes.bits.directory) {
1221 return FsDefs::RES_ENTRY_NOT_FOUND;
1225 return FsDefs::RES_ENTRY_NOT_FOUND;;
1228 return FsDefs::RES_SUCCESS;
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;
1237 const char *parser = *name;
1240 if (c ==
'\0' || c ==
'/') {
1249 getLongNameLenAndOrder(&entry->longEntry, &posOnEntry, &order, &nameLen);
1251 int pathNameLen = (parser - *name) + 1;
1252 if (nameLen != pathNameLen) {
1253 return FsDefs::RES_ENTRY_NOT_FOUND;
1255 const char* end = parser + 1;
1256 uint8_t chksum = entry->longEntry.checksum;
1257 while (parser >= *name) {
1258 for (; posOnEntry >= 0; posOnEntry--) {
1260 if (posOnEntry < 5) {
1261 p = &entry->longEntry.name1[posOnEntry * 2];
1263 else if (posOnEntry < 11) {
1264 p = &entry->longEntry.name2[(posOnEntry - 5) * 2];
1267 p = &entry->longEntry.name3[(posOnEntry - 11) * 2];
1269 uint16_t wideChar = ((uint16_t) p[0]) + (((uint16_t) p[1]) << 8);
1270 if (wideChar == 0) {
1271 return FsDefs::RES_ENTRY_NOT_FOUND;
1273 if (wideChar == 0xFFFF) {
1274 return FsDefs::RES_ENTRY_NOT_FOUND;
1276 if (toupper(*parser) != toupper(getAsciiFromWideChar(wideChar))) {
1278 return FsDefs::RES_ENTRY_NOT_FOUND;
1283 if (parser < *name) {
1288 return FsDefs::RES_ENTRY_NOT_FOUND;
1291 file->mDirectoryEntryIndex++;
1292 if (file->mDirectoryEntryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
1293 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mDirectoryEntryLba);
1295 case FsDefs::RES_SUCCESS:
1298 return FsDefs::RES_ENTRY_NOT_FOUND;
1300 if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
1301 return FsDefs::RES_DISK_ERROR;
1303 file->mDirectoryEntryIndex = 0;
1305 entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
1307 if (entry->longEntry.order != order) {
1308 return FsDefs::RES_ENTRY_NOT_FOUND;
1310 if (!isLongFilenameEntry(entry)) {
1311 return FsDefs::RES_ENTRY_NOT_FOUND;
1313 if (chksum != entry->longEntry.checksum) {
1314 return FsDefs::RES_ENTRY_NOT_FOUND;
1318 file->mDirectoryEntryIndex++;
1319 if (file->mDirectoryEntryIndex == FsDefs::DIRECTORIES_TABLES_PER_SECTOR) {
1320 FsDefs::RESULT result = file->mPartition->getNextBlockLba(file->mSector, &file->mDirectoryEntryLba);
1322 case FsDefs::RES_SUCCESS:
1325 return FsDefs::RES_ENTRY_NOT_FOUND;
1327 if (!file->mPartition->readBlocks(file->mSector, file->mDirectoryEntryLba, 1)) {
1328 return FsDefs::RES_DISK_ERROR;
1330 file->mDirectoryEntryIndex = 0;
1332 entry = &file->mSector->dirEntries[file->mDirectoryEntryIndex];
1333 if (isLongFilenameEntry(entry)) {
1334 return FsDefs::RES_ENTRY_NOT_FOUND;
1337 if (chksum != calcSfnChecksum(entry->shortEntry.name)) {
1338 return FsDefs::RES_ENTRY_NOT_FOUND;
1342 if (!entry->shortEntry.attributes.bits.directory) {
1343 return FsDefs::RES_ENTRY_NOT_FOUND;
1347 else if (*end ==
'\0') {
1348 if (entry->shortEntry.attributes.bits.directory) {
1349 return FsDefs::RES_ENTRY_NOT_FOUND;
1353 return FsDefs::RES_ENTRY_NOT_FOUND;;
1356 return FsDefs::RES_SUCCESS;
1359 Fs::FILENAME_TYPE Fs::getFilenameType(
const char* name,
int& len) {
1361 FILENAME_TYPE type = FT_SHORT_FILENAME;
1362 bool isDotFound =
false;
1368 if (c ==
'\0' || c ==
'/') {
1376 if (!isDotFound && len > 8) {
1377 type = FT_LONG_FILENAME;
1380 type = FT_LONG_FILENAME;
1383 switch (getCharType(c)) {
1386 case CT_LONG_ALLOWED:
1387 type = FT_LONG_FILENAME;
1389 case CT_SHORT_ALLOWED:
1393 type = FT_LONG_FILENAME;
1403 bool Fs::isLongFilenameEntry(FsDefs::DIRECTORY_ENTRY* entry) {
1404 return ((entry->shortEntry.attributes.value & 0x0F) == 0x0F);
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 '$',
'%',
'\'',
'-',
'_',
'@',
'~',
'`',
'!',
'(',
')',
'{',
'}',
'^',
'#',
'&' };
1418 return CT_SHORT_ALLOWED;;
1421 return CT_SHORT_ALLOWED;;
1425 return CT_SHORT_ALLOWED;
1433 return CT_SHORT_ALLOWED;
1436 for (
unsigned int i = 0; i <
sizeof(SFN_SPECIAL_CHARS); i++) {
1437 if (c == SFN_SPECIAL_CHARS[i]) {
1438 return CT_SHORT_ALLOWED;
1443 return CT_LONG_ALLOWED;
1446 for (
unsigned int i = 0; i <
sizeof(LFN_SPECIAL_CHARS); i++) {
1447 if (c == LFN_SPECIAL_CHARS[i]) {
1448 return CT_LONG_ALLOWED;
1455 uint8_t Fs::calcSfnChecksum(
const char* name) {
1457 for (
int i = 0; i < 11; i++) {
1458 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + *name++;
1463 void Fs::setWideCharFromAscii(uint8_t*p,
char value) {
1464 p[0] = (uint8_t) value;
1468 char Fs::getAsciiFromWideChar(uint16_t value) {
1469 return (
char) (value & 0xFF);
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];
1480 if (entry->ext[0] !=
' ') {
1482 for (
int i = 0; i < 3; i++) {
1483 char c = entry->ext[i];
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;
1500 void Fs::getLongNameLenAndOrder(FsDefs::LONG_DIRECTORY_ENTRY* entry,
int* lastOnEntry,
int* order,
int* nameLen) {
1503 for (i = 12; i > 0; i--) {
1506 p = &entry->name1[i * 2];
1509 p = &entry->name2[(i - 5) * 2];
1512 p = &entry->name3[(i - 11) * 2];
1514 uint16_t wideChar = ((uint16_t) p[0]) + (((uint16_t) p[1]) << 8);
1515 if (wideChar == 0) {
1519 if (wideChar != 0xFFFF) {
1525 *lastOnEntry = i - 1;
1526 *order = entry->order & 0x3F;
1527 *nameLen += (*order - 1) * 13;
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);