00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <SdFat.h>
00021 #include <avr/pgmspace.h>
00022 #include <WProgram.h>
00023
00024
00025 void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL;
00026
00027 #if ALLOW_DEPRECATED_FUNCTIONS
00028
00029 void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL;
00030 #endif // ALLOW_DEPRECATED_FUNCTIONS
00031
00032
00033 uint8_t SdFile::addCluster() {
00034 if (!vol_->allocContiguous(1, &curCluster_)) return false;
00035
00036
00037 if (firstCluster_ == 0) {
00038 firstCluster_ = curCluster_;
00039 flags_ |= F_FILE_DIR_DIRTY;
00040 }
00041 return true;
00042 }
00043
00044
00045
00046 uint8_t SdFile::addDirCluster(void) {
00047 if (!addCluster()) return false;
00048
00049
00050 uint32_t block = vol_->clusterStartBlock(curCluster_);
00051 for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) {
00052 if (!SdVolume::cacheZeroBlock(block + i - 1)) return false;
00053 }
00054
00055 fileSize_ += 512UL << vol_->clusterSizeShift_;
00056 return true;
00057 }
00058
00059
00060
00061 dir_t* SdFile::cacheDirEntry(uint8_t action) {
00062 if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL;
00063 return SdVolume::cacheBuffer_.dir + dirIndex_;
00064 }
00065
00074 uint8_t SdFile::close(void) {
00075 if (!sync())return false;
00076 type_ = FAT_FILE_TYPE_CLOSED;
00077 return true;
00078 }
00079
00091 uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
00092
00093 if (firstCluster_ == 0) return false;
00094
00095 for (uint32_t c = firstCluster_; ; c++) {
00096 uint32_t next;
00097 if (!vol_->fatGet(c, &next)) return false;
00098
00099
00100 if (next != (c + 1)) {
00101
00102 if (!vol_->isEOC(next)) return false;
00103 *bgnBlock = vol_->clusterStartBlock(firstCluster_);
00104 *endBlock = vol_->clusterStartBlock(c)
00105 + vol_->blocksPerCluster_ - 1;
00106 return true;
00107 }
00108 }
00109 }
00110
00129 uint8_t SdFile::createContiguous(SdFile* dirFile,
00130 const char* fileName, uint32_t size) {
00131
00132 if (size == 0) return false;
00133 if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false;
00134
00135
00136 uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1;
00137
00138
00139 if (!vol_->allocContiguous(count, &firstCluster_)) {
00140 remove();
00141 return false;
00142 }
00143 fileSize_ = size;
00144
00145
00146 flags_ |= F_FILE_DIR_DIRTY;
00147 return sync();
00148 }
00149
00158 uint8_t SdFile::dirEntry(dir_t* dir) {
00159
00160 if (!sync()) return false;
00161
00162
00163 dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
00164 if (!p) return false;
00165
00166
00167 memcpy(dir, p, sizeof(dir_t));
00168 return true;
00169 }
00170
00178 void SdFile::dirName(const dir_t& dir, char* name) {
00179 uint8_t j = 0;
00180 for (uint8_t i = 0; i < 11; i++) {
00181 if (dir.name[i] == ' ')continue;
00182 if (i == 8) name[j++] = '.';
00183 name[j++] = dir.name[i];
00184 }
00185 name[j] = 0;
00186 }
00187
00201 void SdFile::ls(uint8_t flags, uint8_t indent) {
00202 dir_t* p;
00203
00204 rewind();
00205 while ((p = readDirCache())) {
00206
00207 if (p->name[0] == DIR_NAME_FREE) break;
00208
00209
00210 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
00211
00212
00213 if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
00214
00215
00216 for (int8_t i = 0; i < indent; i++) Serial.print(' ');
00217
00218
00219 printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0);
00220
00221
00222 if (flags & LS_DATE) {
00223 printFatDate(p->lastWriteDate);
00224 Serial.print(' ');
00225 printFatTime(p->lastWriteTime);
00226 }
00227
00228 if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) {
00229 Serial.print(' ');
00230 Serial.print(p->fileSize);
00231 }
00232 Serial.println();
00233
00234
00235 if ((flags & LS_R) && DIR_IS_SUBDIR(p)) {
00236 uint16_t index = curPosition()/32 - 1;
00237 SdFile s;
00238 if (s.open(this, index, O_READ)) s.ls(flags, indent + 2);
00239 seekSet(32 * (index + 1));
00240 }
00241 }
00242 }
00243
00244
00245 uint8_t SdFile::make83Name(const char* str, uint8_t* name) {
00246 uint8_t c;
00247 uint8_t n = 7;
00248 uint8_t i = 0;
00249
00250 while (i < 11) name[i++] = ' ';
00251 i = 0;
00252 while ((c = *str++) != '\0') {
00253 if (c == '.') {
00254 if (n == 10) return false;
00255 n = 10;
00256 i = 8;
00257 } else {
00258
00259 PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
00260 uint8_t b;
00261 while ((b = pgm_read_byte(p++))) if (b == c) return false;
00262
00263 if (i > n || c < 0X21 || c > 0X7E)return false;
00264
00265 name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a');
00266 }
00267 }
00268
00269 return name[0] != ' ';
00270 }
00271
00284 uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) {
00285 dir_t d;
00286
00287
00288 if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false;
00289
00290
00291 flags_ = O_READ;
00292 type_ = FAT_FILE_TYPE_SUBDIR;
00293
00294
00295 if (!addDirCluster())return false;
00296
00297
00298 if (!sync()) return false;
00299
00300
00301 dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
00302 if (!p) return false;
00303
00304
00305 p->attributes = DIR_ATT_DIRECTORY;
00306
00307
00308 memcpy(&d, p, sizeof(d));
00309 for (uint8_t i = 1; i < 11; i++) d.name[i] = ' ';
00310 d.name[0] = '.';
00311
00312
00313 uint32_t block = vol_->clusterStartBlock(firstCluster_);
00314 if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false;
00315
00316
00317 memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d));
00318
00319
00320 d.name[1] = '.';
00321 if (dir->isRoot()) {
00322 d.firstClusterLow = 0;
00323 d.firstClusterHigh = 0;
00324 } else {
00325 d.firstClusterLow = dir->firstCluster_ & 0XFFFF;
00326 d.firstClusterHigh = dir->firstCluster_ >> 16;
00327 }
00328
00329 memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d));
00330
00331
00332 curPosition_ = 2 * sizeof(d);
00333
00334
00335 return SdVolume::cacheFlush();
00336 }
00337
00384 uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) {
00385 uint8_t dname[11];
00386 dir_t* p;
00387
00388
00389 if (isOpen())return false;
00390
00391 if (!make83Name(fileName, dname)) return false;
00392 vol_ = dirFile->vol_;
00393 dirFile->rewind();
00394
00395
00396 uint8_t emptyFound = false;
00397
00398
00399 while (dirFile->curPosition_ < dirFile->fileSize_) {
00400 uint8_t index = 0XF & (dirFile->curPosition_ >> 5);
00401 p = dirFile->readDirCache();
00402 if (p == NULL) return false;
00403
00404 if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) {
00405
00406 if (!emptyFound) {
00407 emptyFound = true;
00408 dirIndex_ = index;
00409 dirBlock_ = SdVolume::cacheBlockNumber_;
00410 }
00411
00412 if (p->name[0] == DIR_NAME_FREE) break;
00413 } else if (!memcmp(dname, p->name, 11)) {
00414
00415 if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
00416
00417
00418 return openCachedEntry(0XF & index, oflag);
00419 }
00420 }
00421
00422 if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false;
00423
00424
00425 if (emptyFound) {
00426 p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
00427 if (!p) return false;
00428 } else {
00429 if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false;
00430
00431
00432 if (!dirFile->addDirCluster()) return false;
00433
00434
00435 dirIndex_ = 0;
00436 p = SdVolume::cacheBuffer_.dir;
00437 }
00438
00439 memset(p, 0, sizeof(dir_t));
00440 memcpy(p->name, dname, 11);
00441
00442
00443 if (dateTime_) {
00444
00445 dateTime_(&p->creationDate, &p->creationTime);
00446 } else {
00447
00448 p->creationDate = FAT_DEFAULT_DATE;
00449 p->creationTime = FAT_DEFAULT_TIME;
00450 }
00451 p->lastAccessDate = p->creationDate;
00452 p->lastWriteDate = p->creationDate;
00453 p->lastWriteTime = p->creationTime;
00454
00455
00456 if (!SdVolume::cacheFlush()) return false;
00457
00458
00459 return openCachedEntry(dirIndex_, oflag);
00460 }
00461
00476 uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) {
00477
00478 if (isOpen())return false;
00479
00480
00481 if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false;
00482
00483 vol_ = dirFile->vol_;
00484
00485
00486 if (!dirFile->seekSet(32 * index)) return false;
00487
00488
00489 dir_t* p = dirFile->readDirCache();
00490 if (p == NULL) return false;
00491
00492
00493 if (p->name[0] == DIR_NAME_FREE ||
00494 p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
00495 return false;
00496 }
00497
00498 return openCachedEntry(index & 0XF, oflag);
00499 }
00500
00501
00502 uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
00503
00504 dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex;
00505
00506
00507 if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) {
00508 if (oflag & (O_WRITE | O_TRUNC)) return false;
00509 }
00510
00511 dirIndex_ = dirIndex;
00512 dirBlock_ = SdVolume::cacheBlockNumber_;
00513
00514
00515 firstCluster_ = (uint32_t)p->firstClusterHigh << 16;
00516 firstCluster_ |= p->firstClusterLow;
00517
00518
00519 if (DIR_IS_FILE(p)) {
00520 fileSize_ = p->fileSize;
00521 type_ = FAT_FILE_TYPE_NORMAL;
00522 } else if (DIR_IS_SUBDIR(p)) {
00523 if (!vol_->chainSize(firstCluster_, &fileSize_)) return false;
00524 type_ = FAT_FILE_TYPE_SUBDIR;
00525 } else {
00526 return false;
00527 }
00528
00529 flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND);
00530
00531
00532 curCluster_ = 0;
00533 curPosition_ = 0;
00534
00535
00536 if (oflag & O_TRUNC) return truncate(0);
00537 return true;
00538 }
00539
00550 uint8_t SdFile::openRoot(SdVolume* vol) {
00551
00552 if (isOpen()) return false;
00553
00554 if (vol->fatType() == 16) {
00555 type_ = FAT_FILE_TYPE_ROOT16;
00556 firstCluster_ = 0;
00557 fileSize_ = 32 * vol->rootDirEntryCount();
00558 } else if (vol->fatType() == 32) {
00559 type_ = FAT_FILE_TYPE_ROOT32;
00560 firstCluster_ = vol->rootDirStart();
00561 if (!vol->chainSize(firstCluster_, &fileSize_)) return false;
00562 } else {
00563
00564 return false;
00565 }
00566 vol_ = vol;
00567
00568 flags_ = O_READ;
00569
00570
00571 curCluster_ = 0;
00572 curPosition_ = 0;
00573
00574
00575 dirBlock_ = 0;
00576 dirIndex_ = 0;
00577 return true;
00578 }
00579
00585 void SdFile::printDirName(const dir_t& dir, uint8_t width) {
00586 uint8_t w = 0;
00587 for (uint8_t i = 0; i < 11; i++) {
00588 if (dir.name[i] == ' ')continue;
00589 if (i == 8) {
00590 Serial.print('.');
00591 w++;
00592 }
00593 Serial.print(dir.name[i]);
00594 w++;
00595 }
00596 if (DIR_IS_SUBDIR(&dir)) {
00597 Serial.print('/');
00598 w++;
00599 }
00600 while (w < width) {
00601 Serial.print(' ');
00602 w++;
00603 }
00604 }
00605
00612 void SdFile::printFatDate(uint16_t fatDate) {
00613 Serial.print(FAT_YEAR(fatDate));
00614 Serial.print('-');
00615 printTwoDigits(FAT_MONTH(fatDate));
00616 Serial.print('-');
00617 printTwoDigits(FAT_DAY(fatDate));
00618 }
00619
00626 void SdFile::printFatTime(uint16_t fatTime) {
00627 printTwoDigits(FAT_HOUR(fatTime));
00628 Serial.print(':');
00629 printTwoDigits(FAT_MINUTE(fatTime));
00630 Serial.print(':');
00631 printTwoDigits(FAT_SECOND(fatTime));
00632 }
00633
00638 void SdFile::printTwoDigits(uint8_t v) {
00639 char str[3];
00640 str[0] = '0' + v/10;
00641 str[1] = '0' + v % 10;
00642 str[2] = 0;
00643 Serial.print(str);
00644 }
00645
00660 int16_t SdFile::read(void* buf, uint16_t nbyte) {
00661 uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
00662
00663
00664 if (!isOpen() || !(flags_ & O_READ)) return -1;
00665
00666
00667 if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_;
00668
00669
00670 uint16_t toRead = nbyte;
00671 while (toRead > 0) {
00672 uint32_t block;
00673 uint16_t offset = curPosition_ & 0X1FF;
00674 if (type_ == FAT_FILE_TYPE_ROOT16) {
00675 block = vol_->rootDirStart() + (curPosition_ >> 9);
00676 } else {
00677 uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
00678 if (offset == 0 && blockOfCluster == 0) {
00679
00680 if (curPosition_ == 0) {
00681
00682 curCluster_ = firstCluster_;
00683 } else {
00684
00685 if (!vol_->fatGet(curCluster_, &curCluster_)) return -1;
00686 }
00687 }
00688 block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
00689 }
00690 uint16_t n = toRead;
00691
00692
00693 if (n > (512 - offset)) n = 512 - offset;
00694
00695
00696 if ((unbufferedRead() || n == 512) &&
00697 block != SdVolume::cacheBlockNumber_) {
00698 if (!vol_->readData(block, offset, n, dst)) return -1;
00699 dst += n;
00700 } else {
00701
00702 if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1;
00703 uint8_t* src = SdVolume::cacheBuffer_.data + offset;
00704 uint8_t* end = src + n;
00705 while (src != end) *dst++ = *src++;
00706 }
00707 curPosition_ += n;
00708 toRead -= n;
00709 }
00710 return nbyte;
00711 }
00712
00724 int8_t SdFile::readDir(dir_t* dir) {
00725 int8_t n;
00726
00727 if (!isDir() || (0X1F & curPosition_)) return -1;
00728
00729 while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) {
00730
00731 if (dir->name[0] == DIR_NAME_FREE) break;
00732
00733 if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
00734
00735 if (DIR_IS_FILE_OR_SUBDIR(dir)) return n;
00736 }
00737
00738 return n < 0 ? -1 : 0;
00739 }
00740
00741
00742
00743 dir_t* SdFile::readDirCache(void) {
00744
00745 if (!isDir()) return NULL;
00746
00747
00748 uint8_t i = (curPosition_ >> 5) & 0XF;
00749
00750
00751 if (read() < 0) return NULL;
00752
00753
00754 curPosition_ += 31;
00755
00756
00757 return (SdVolume::cacheBuffer_.dir + i);
00758 }
00759
00774 uint8_t SdFile::remove(void) {
00775
00776 if (!truncate(0)) return false;
00777
00778
00779 dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
00780 if (!d) return false;
00781
00782
00783 d->name[0] = DIR_NAME_DELETED;
00784
00785
00786 type_ = FAT_FILE_TYPE_CLOSED;
00787
00788
00789 return SdVolume::cacheFlush();
00790 }
00791
00810 uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) {
00811 SdFile file;
00812 if (!file.open(dirFile, fileName, O_WRITE)) return false;
00813 return file.remove();
00814 }
00815
00831 uint8_t SdFile::rmDir(void) {
00832
00833 if (!isSubDir()) return false;
00834
00835 rewind();
00836
00837
00838 while (curPosition_ < fileSize_) {
00839 dir_t* p = readDirCache();
00840 if (p == NULL) return false;
00841
00842 if (p->name[0] == DIR_NAME_FREE) break;
00843
00844 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
00845
00846 if (DIR_IS_FILE_OR_SUBDIR(p)) return false;
00847 }
00848
00849 type_ = FAT_FILE_TYPE_NORMAL;
00850 flags_ |= O_WRITE;
00851 return remove();
00852 }
00853
00869 uint8_t SdFile::rmRfStar(void) {
00870 rewind();
00871 while (curPosition_ < fileSize_) {
00872 SdFile f;
00873
00874
00875 uint16_t index = curPosition_/32;
00876
00877 dir_t* p = readDirCache();
00878 if (!p) return false;
00879
00880
00881 if (p->name[0] == DIR_NAME_FREE) break;
00882
00883
00884 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
00885
00886
00887 if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
00888
00889 if (!f.open(this, index, O_READ)) return false;
00890 if (f.isSubDir()) {
00891
00892 if (!f.rmRfStar()) return false;
00893 } else {
00894
00895 f.flags_ |= O_WRITE;
00896 if (!f.remove()) return false;
00897 }
00898
00899 if (curPosition_ != (32*(index + 1))) {
00900 if (!seekSet(32*(index + 1))) return false;
00901 }
00902 }
00903
00904 if (isRoot()) return true;
00905 return rmDir();
00906 }
00907
00916 uint8_t SdFile::seekSet(uint32_t pos) {
00917
00918 if (!isOpen() || pos > fileSize_) return false;
00919
00920 if (type_ == FAT_FILE_TYPE_ROOT16) {
00921 curPosition_ = pos;
00922 return true;
00923 }
00924 if (pos == 0) {
00925
00926 curCluster_ = 0;
00927 curPosition_ = 0;
00928 return true;
00929 }
00930
00931 uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9);
00932 uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9);
00933
00934 if (nNew < nCur || curPosition_ == 0) {
00935
00936 curCluster_ = firstCluster_;
00937 } else {
00938
00939 nNew -= nCur;
00940 }
00941 while (nNew--) {
00942 if (!vol_->fatGet(curCluster_, &curCluster_)) return false;
00943 }
00944 curPosition_ = pos;
00945 return true;
00946 }
00947
00957 uint8_t SdFile::sync(void) {
00958
00959 if (!isOpen()) return false;
00960
00961 if (flags_ & F_FILE_DIR_DIRTY) {
00962 dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
00963 if (!d) return false;
00964
00965
00966 if (!isDir()) d->fileSize = fileSize_;
00967
00968
00969 d->firstClusterLow = firstCluster_ & 0XFFFF;
00970 d->firstClusterHigh = firstCluster_ >> 16;
00971
00972
00973 if (dateTime_) {
00974 dateTime_(&d->lastWriteDate, &d->lastWriteTime);
00975 d->lastAccessDate = d->lastWriteDate;
00976 }
00977
00978 flags_ &= ~F_FILE_DIR_DIRTY;
00979 }
00980 return SdVolume::cacheFlush();
00981 }
00982
01017 uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
01018 uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
01019 if (!isOpen()
01020 || year < 1980
01021 || year > 2107
01022 || month < 1
01023 || month > 12
01024 || day < 1
01025 || day > 31
01026 || hour > 23
01027 || minute > 59
01028 || second > 59) {
01029 return false;
01030 }
01031 dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
01032 if (!d) return false;
01033
01034 uint16_t dirDate = FAT_DATE(year, month, day);
01035 uint16_t dirTime = FAT_TIME(hour, minute, second);
01036 if (flags & T_ACCESS) {
01037 d->lastAccessDate = dirDate;
01038 }
01039 if (flags & T_CREATE) {
01040 d->creationDate = dirDate;
01041 d->creationTime = dirTime;
01042
01043 d->creationTimeTenths = second & 1 ? 100 : 0;
01044 }
01045 if (flags & T_WRITE) {
01046 d->lastWriteDate = dirDate;
01047 d->lastWriteTime = dirTime;
01048 }
01049 SdVolume::cacheSetDirty();
01050 return sync();
01051 }
01052
01065 uint8_t SdFile::truncate(uint32_t length) {
01066
01067 if (!isFile() || !(flags_ & O_WRITE)) return false;
01068
01069
01070 if (length > fileSize_) return false;
01071
01072
01073 if (fileSize_ == 0) return true;
01074
01075
01076 uint32_t newPos = curPosition_ > length ? length : curPosition_;
01077
01078
01079 if (!seekSet(length)) return false;
01080
01081 if (length == 0) {
01082
01083 if (!vol_->freeChain(firstCluster_)) return false;
01084 firstCluster_ = 0;
01085 } else {
01086 uint32_t toFree;
01087 if (!vol_->fatGet(curCluster_, &toFree)) return false;
01088
01089 if (!vol_->isEOC(toFree)) {
01090
01091 if (!vol_->freeChain(toFree)) return false;
01092
01093
01094 if (!vol_->fatPutEOC(curCluster_)) return false;
01095 }
01096 }
01097 fileSize_ = length;
01098
01099
01100 flags_ |= F_FILE_DIR_DIRTY;
01101
01102 if (!sync()) return false;
01103
01104
01105 return seekSet(newPos);
01106 }
01107
01124 int16_t SdFile::write(const void* buf, uint16_t nbyte) {
01125
01126 const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
01127
01128
01129 uint16_t nToWrite = nbyte;
01130
01131
01132 if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn;
01133
01134
01135 if ((flags_ & O_APPEND) && curPosition_ != fileSize_) {
01136 if (!seekEnd()) goto writeErrorReturn;
01137 }
01138
01139 while (nToWrite > 0) {
01140 uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
01141 uint16_t blockOffset = curPosition_ & 0X1FF;
01142 if (blockOfCluster == 0 && blockOffset == 0) {
01143
01144 if (curCluster_ == 0) {
01145 if (firstCluster_ == 0) {
01146
01147 if (!addCluster()) goto writeErrorReturn;
01148 } else {
01149 curCluster_ = firstCluster_;
01150 }
01151 } else {
01152 uint32_t next;
01153 if (!vol_->fatGet(curCluster_, &next)) return false;
01154 if (vol_->isEOC(next)) {
01155
01156 if (!addCluster()) goto writeErrorReturn;
01157 } else {
01158 curCluster_ = next;
01159 }
01160 }
01161 }
01162
01163 uint16_t n = 512 - blockOffset;
01164
01165
01166 if (n > nToWrite) n = nToWrite;
01167
01168
01169 uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
01170 if (n == 512) {
01171
01172
01173 if (SdVolume::cacheBlockNumber_ == block) {
01174 SdVolume::cacheBlockNumber_ = 0XFFFFFFFF;
01175 }
01176 if (!vol_->writeBlock(block, src)) goto writeErrorReturn;
01177 src += 512;
01178 } else {
01179 if (blockOffset == 0 && curPosition_ >= fileSize_) {
01180
01181 if (!SdVolume::cacheFlush()) goto writeErrorReturn;
01182 SdVolume::cacheBlockNumber_ = block;
01183 SdVolume::cacheSetDirty();
01184 } else {
01185
01186 if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) {
01187 goto writeErrorReturn;
01188 }
01189 }
01190 uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset;
01191 uint8_t* end = dst + n;
01192 while (dst != end) *dst++ = *src++;
01193 }
01194 nToWrite -= n;
01195 curPosition_ += n;
01196 }
01197 if (curPosition_ > fileSize_) {
01198
01199 fileSize_ = curPosition_;
01200 flags_ |= F_FILE_DIR_DIRTY;
01201 } else if (dateTime_ && nbyte) {
01202
01203 flags_ |= F_FILE_DIR_DIRTY;
01204 }
01205
01206 if (flags_ & O_SYNC) {
01207 if (!sync()) goto writeErrorReturn;
01208 }
01209 return nbyte;
01210
01211 writeErrorReturn:
01212
01213 writeError = true;
01214 return -1;
01215 }
01216
01222 void SdFile::write(uint8_t b) {
01223 write(&b, 1);
01224 }
01225
01231 void SdFile::write(const char* str) {
01232 write(str, strlen(str));
01233 }
01234
01240 void SdFile::write_P(PGM_P str) {
01241 for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
01242 }
01243
01249 void SdFile::writeln_P(PGM_P str) {
01250 write_P(str);
01251 println();
01252 }