64 return NO_ERROR == this->find(this->
get_name(), &temp);
72 bool exists (PropWare::ErrorCode &err)
const {
74 err = this->find(this->
get_name(), &temp);
75 return NO_ERROR == err;
81 :
File(fs, name, buffer, logger),
83 strcpy(this->m_name, name);
87 const uint8_t get_file_attributes (uint16_t fileEntryOffset)
const {
88 return this->m_buf->buf[fileEntryOffset + FILE_ATTRIBUTE_OFFSET];
91 const bool is_directory (uint16_t fileEntryOffset)
const {
92 return SUB_DIR & this->get_file_attributes(fileEntryOffset);
112 PropWare::ErrorCode find (
const char *filename, uint16_t *fileEntryOffset)
const {
113 PropWare::ErrorCode err;
114 char readEntryName[FILENAME_STR_LEN];
116 *fileEntryOffset = 0;
118 check_errors(this->reload_directory_start());
122 while (this->m_buf->buf[*fileEntryOffset]) {
124 if (!this->file_deleted(*fileEntryOffset)) {
125 this->get_filename(&this->m_buf->buf[*fileEntryOffset], readEntryName);
126 if (!strcmp(filename, readEntryName))
132 *fileEntryOffset += FILE_ENTRY_LENGTH;
136 if (this->m_driver->get_sector_size() == *fileEntryOffset) {
139 check_errors(this->load_next_sector(this->m_buf));
141 *fileEntryOffset = 0;
151 PropWare::ErrorCode open_existing_file (
const uint16_t fileEntryOffset) {
152 PropWare::ErrorCode err;
154 if (this->is_directory(fileEntryOffset))
158 check_errors(this->m_driver->flush(this->m_buf));
161 this->m_dirEntryMeta = *(this->m_buf->meta);
164 if (FatFS::FAT_16 == this->m_fs->m_filesystem)
165 this->firstTier2 = this->m_driver->get_short(fileEntryOffset + FILE_START_CLSTR_LOW,
168 this->firstTier2 = this->m_driver->get_short(fileEntryOffset + FILE_START_CLSTR_LOW,
170 const uint16_t highWord = this->m_driver->get_short(fileEntryOffset + FILE_START_CLSTR_HIGH,
172 this->firstTier2 |= highWord << 16;
175 this->firstTier2 &= 0x0FFFFFFF;
179 this->m_curTier2 = 0;
180 this->fileEntryOffset = fileEntryOffset;
181 this->m_length = this->m_driver->get_long(fileEntryOffset + FatFile::FILE_LEN_OFFSET,
185 this->m_contentMeta.curTier1Offset = 0;
186 this->m_contentMeta.curTier2 = this->firstTier2;
187 this->m_contentMeta.curTier2Addr = this->m_fs->compute_tier1_from_tier2(this->firstTier2);
188 check_errors(this->m_fs->get_fat_value(this->m_contentMeta.curTier2, &(this->m_contentMeta.nextTier2)));
191 this->m_buf->meta = &this->m_contentMeta;
192 return this->m_driver->reload_buffer(this->m_buf);
195 bool file_deleted (
const uint16_t fileEntryOffset)
const {
196 return DELETED_FILE_MARK == this->m_buf->buf[fileEntryOffset];
215 void get_filename (
const uint8_t buf[],
char filename[])
const {
220 for (i = 0; i < FILE_NAME_LEN; ++i) {
222 filename[j++] = (
char) 0xe5;
223 else if (
' ' != buf[i])
224 filename[j++] = buf[i];
229 if (
' ' != buf[FILE_NAME_LEN]) {
231 for (i = FILE_NAME_LEN;
232 i < FILE_NAME_LEN + FILE_EXTENSION_LEN; ++i) {
234 filename[j++] = buf[i];
251 PropWare::ErrorCode load_next_sector (BlockStorage::Buffer *buf)
const {
252 PropWare::ErrorCode err;
255 if (this->m_fs->is_eoc(buf->meta->curTier2))
256 return FatFS::EOC_END;
259 if (FatFS::FAT_16 == this->m_fs->m_filesystem && this->m_fs->m_rootAddr == (buf->meta->curTier2Addr)) {
261 if (this->m_fs->m_rootDirSectors == buf->meta->curTier1Offset)
262 return FatFS::EOC_END;
266 check_errors(this->m_driver->flush(buf));
267 return this->m_driver->read_data_block(++(buf->meta->curTier1Offset), buf->buf);
273 const unsigned int tier1sPerTier2 = (
unsigned int) (1 << this->m_fs->get_tier1s_per_tier2_shift());
274 buf->meta->curTier1Offset++;
275 if (tier1sPerTier2 == buf->meta->curTier1Offset) {
276 return this->inc_cluster();
278 return this->m_driver->read_data_block(
279 buf->meta->curTier1Offset + buf->meta->curTier2Addr, buf->buf);
292 PropWare::ErrorCode inc_cluster ()
const {
293 PropWare::ErrorCode err;
295 BlockStorage::Buffer *buf = this->m_buf;
298 if (this->m_fs->is_eoc(buf->meta->curTier2))
302 check_errors(this->m_driver->flush(buf));
304 buf->meta->curTier2 = buf->meta->nextTier2;
306 if (!this->m_fs->is_eoc(buf->meta->curTier2)) {
308 check_errors(this->m_fs->get_fat_value(buf->meta->curTier2, &(buf->meta->nextTier2)));
310 buf->meta->curTier2Addr = this->m_fs->compute_tier1_from_tier2(buf->meta->curTier2);
311 buf->meta->curTier1Offset = 0;
313 return this->m_driver->read_data_block(buf->meta->curTier2Addr, buf->buf);
316 const bool buffer_holds_directory_start ()
const {
317 const bool bufferIsDirectory = &this->m_fs->m_dirMeta == this->m_buf->meta;
318 const bool tier1AtStart = 0 == this->m_fs->m_dirMeta.curTier1Offset;
319 const bool tier2AtStart = this->m_fs->compute_tier1_from_tier2(this->m_fs->m_dir_firstCluster) ==
320 this->m_fs->m_dirMeta.curTier2Addr;
322 return bufferIsDirectory && tier1AtStart && tier2AtStart;
325 const PropWare::ErrorCode reload_directory_start ()
const {
326 if (!this->buffer_holds_directory_start()) {
327 PropWare::ErrorCode err;
329 this->m_driver->flush(this->m_buf);
330 BlockStorage::MetaData *dirMeta = &this->m_fs->m_dirMeta;
333 dirMeta->curTier2Addr = this->m_fs->compute_tier1_from_tier2(this->m_fs->m_dir_firstCluster);
334 dirMeta->curTier1Offset = 0;
335 dirMeta->curTier2 = this->m_fs->m_dir_firstCluster;
336 check_errors(this->m_fs->get_fat_value(this->m_fsBufMeta->curTier2, &this->m_fsBufMeta->nextTier2));
338 this->m_buf->meta = dirMeta;
339 check_errors(this->m_driver->reload_buffer(this->m_buf));
345 PropWare::ErrorCode load_sector_under_ptr () {
346 PropWare::ErrorCode err;
349 const uint32_t requiredSector = (uint32_t) this->m_ptr >> this->m_driver->get_sector_size_shift();
353 bool wrongData =
false;
354 if (this->m_buf->meta != &this->m_contentMeta) {
355 check_errors(this->m_driver->flush(this->m_buf));
356 this->m_buf->meta = &this->m_contentMeta;
360 if (requiredSector != this->m_curTier1) {
361 check_errors(this->load_sector_from_offset(requiredSector, this->m_buf->meta));
367 check_errors(this->m_driver->reload_buffer(this->m_buf));
384 PropWare::ErrorCode load_sector_from_offset (
const uint32_t requiredSector,
385 BlockStorage::MetaData *bufferMetadata) {
386 PropWare::ErrorCode err;
387 const uint8_t sectorsPerCluster = this->m_fs->m_tier1sPerTier2Shift;
388 unsigned int requiredCluster = requiredSector >> sectorsPerCluster;
390 check_errors(this->m_driver->flush(this->m_buf));
393 if (this->m_curTier2 < requiredCluster) {
397 bufferMetadata->curTier2 = bufferMetadata->nextTier2;
398 check_errors(this->m_fs->get_fat_value(bufferMetadata->curTier2,
399 &(bufferMetadata->nextTier2)));
402 }
while (this->m_curTier2 < requiredCluster);
403 bufferMetadata->curTier2Addr = this->m_fs->compute_tier1_from_tier2(bufferMetadata->curTier2);
404 }
else if (this->m_curTier2 > requiredCluster) {
407 this->m_curTier2 = 0;
408 bufferMetadata->curTier2 = this->firstTier2;
409 check_errors(this->m_fs->get_fat_value(bufferMetadata->curTier2, &(bufferMetadata->nextTier2)));
410 while (requiredCluster--) {
412 bufferMetadata->curTier2 = bufferMetadata->nextTier2;
413 check_errors(this->m_fs->get_fat_value(bufferMetadata->curTier2,
414 &(bufferMetadata->nextTier2)));
416 bufferMetadata->curTier2Addr = this->m_fs->compute_tier1_from_tier2(bufferMetadata->curTier2);
420 bufferMetadata->curTier1Offset = (uint8_t) (requiredSector % (1 << sectorsPerCluster));
421 this->m_curTier1 = requiredSector;
423 check_errors(this->m_driver->read_data_block(
424 bufferMetadata->curTier2Addr + bufferMetadata->curTier1Offset, this->m_buf->buf));
429 PropWare::ErrorCode load_directory_sector () {
430 PropWare::ErrorCode err;
431 if (this->m_buf->meta != &this->m_dirEntryMeta) {
432 this->m_driver->flush(this->m_buf);
433 this->m_buf->meta = &this->m_dirEntryMeta;
434 check_errors(this->m_driver->reload_buffer(this->m_buf));
445 void print_file_entry (
const uint8_t *fileEntry,
char filename[]) {
446 this->print_file_attributes(fileEntry[FILE_ATTRIBUTE_OFFSET]);
447 this->get_filename(fileEntry, filename);
448 this->m_logger->printf(
"\t\t%s", filename);
449 if (SUB_DIR & fileEntry[FILE_ATTRIBUTE_OFFSET])
450 this->m_logger->print(
'/');
451 this->m_logger->println();
460 void print_file_attributes (
const uint8_t flags) {
462 if (READ_ONLY & flags)
463 this->m_logger->print(READ_ONLY_CHAR);
465 this->m_logger->print(READ_ONLY_CHAR_);
467 if (HIDDEN_FILE & flags)
468 this->m_logger->print(HIDDEN_FILE_CHAR);
470 this->m_logger->print(HIDDEN_FILE_CHAR_);
472 if (SYSTEM_FILE & flags)
473 this->m_logger->print(SYSTEM_FILE_CHAR);
475 this->m_logger->print(SYSTEM_FILE_CHAR_);
477 if (VOLUME_ID & flags)
478 this->m_logger->print(VOLUME_ID_CHAR);
480 this->m_logger->print(VOLUME_ID_CHAR_);
483 this->m_logger->print(SUB_DIR_CHAR);
485 this->m_logger->print(SUB_DIR_CHAR_);
488 this->m_logger->print(ARCHIVE_CHAR);
490 this->m_logger->print(ARCHIVE_CHAR_);
493 void print_status (
const bool printBlocks =
false,
const bool printParentStatus =
true)
const {
494 if (printParentStatus)
495 this->File::print_status(
"FatFile", printBlocks);
497 this->m_logger->println(
"FAT-specific");
498 this->m_logger->println(
"------------");
499 this->m_logger->printf(
"\tStarting cluster: 0x%08X/%u\n", this->firstTier2, this->firstTier2);
500 this->m_logger->printf(
"\tCurrent sector (counting from first in file): 0x%08X/%u\n",
501 this->m_curTier1, this->m_curTier1);
502 this->m_logger->printf(
"\tCurrent cluster (counting from first in file): 0x%08X/%u\n",
503 this->m_curTier2, this->m_curTier2);
504 this->m_logger->printf(
"\tDirectory address (sector): 0x%08X/%u\n", this->m_dirTier1Addr,
505 this->m_dirTier1Addr);
506 this->m_logger->printf(
"\tFile entry offset: 0x%04X\n", this->fileEntryOffset);
511 static const uint8_t FILE_LEN_OFFSET = 0x1C;
514 static const uint8_t FILE_ENTRY_LENGTH = 32;
515 static const uint8_t DELETED_FILE_MARK = 0xE5;
516 static const uint8_t FILE_NAME_LEN = 8;
517 static const uint8_t FILE_EXTENSION_LEN = 3;
518 static const uint8_t FILENAME_STR_LEN = FILE_NAME_LEN + FILE_EXTENSION_LEN + 2;
519 static const uint8_t FILE_ATTRIBUTE_OFFSET = 0x0B;
520 static const uint8_t FILE_START_CLSTR_LOW = 0x1A;
521 static const uint8_t FILE_START_CLSTR_HIGH = 0x14;
524 static const uint8_t READ_ONLY = BIT_0;
525 static const char READ_ONLY_CHAR =
'r';
526 static const char READ_ONLY_CHAR_ =
'w';
527 static const uint8_t HIDDEN_FILE = BIT_1;
528 static const char HIDDEN_FILE_CHAR =
'h';
529 static const char HIDDEN_FILE_CHAR_ =
'.';
530 static const uint8_t SYSTEM_FILE = BIT_2;
531 static const char SYSTEM_FILE_CHAR =
's';
532 static const char SYSTEM_FILE_CHAR_ =
'.';
533 static const uint8_t VOLUME_ID = BIT_3;
534 static const char VOLUME_ID_CHAR =
'v';
535 static const char VOLUME_ID_CHAR_ =
'.';
536 static const uint8_t SUB_DIR = BIT_4;
537 static const char SUB_DIR_CHAR =
'd';
538 static const char SUB_DIR_CHAR_ =
'f';
539 static const uint8_t ARCHIVE = BIT_5;
540 static const char ARCHIVE_CHAR =
'a';
541 static const char ARCHIVE_CHAR_ =
'.';
552 uint32_t m_dirTier1Addr;
554 uint16_t fileEntryOffset;