Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SdFile.cpp
00001 /* Arduino SdFat Library 00002 * Copyright (C) 2009 by William Greiman 00003 * 00004 * This file is part of the Arduino SdFat Library 00005 * 00006 * This Library is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This Library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with the Arduino SdFat Library. If not, see 00018 * <http://www.gnu.org/licenses/>. 00019 */ 00020 #include <SdFat.h> 00021 #include "mbed.h" 00022 00023 //------------------------------------------------------------------------------ 00024 // callback function for date/time 00025 void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL; 00026 00027 #if ALLOW_DEPRECATED_FUNCTIONS 00028 // suppress cpplint warnings with NOLINT comment 00029 void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT 00030 #endif // ALLOW_DEPRECATED_FUNCTIONS 00031 //------------------------------------------------------------------------------ 00032 // add a cluster to a file 00033 uint8_t SdFile::addCluster() { 00034 if (!vol_->allocContiguous(1, &curCluster_)) return false; 00035 00036 // if first cluster of file link to directory entry 00037 if (firstCluster_ == 0) { 00038 firstCluster_ = curCluster_; 00039 flags_ |= F_FILE_DIR_DIRTY; 00040 } 00041 return true; 00042 } 00043 //------------------------------------------------------------------------------ 00044 // Add a cluster to a directory file and zero the cluster. 00045 // return with first block of cluster in the cache 00046 uint8_t SdFile::addDirCluster(void) { 00047 if (!addCluster()) return false; 00048 00049 // zero data in cluster insure first cluster is in cache 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 // Increase directory file size by cluster size 00055 fileSize_ += 512UL << vol_->clusterSizeShift_; 00056 return true; 00057 } 00058 //------------------------------------------------------------------------------ 00059 // cache a file's directory entry 00060 // return pointer to cached entry or null for failure 00061 dir_t* SdFile::cacheDirEntry(uint8_t action) { 00062 if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL; 00063 return SdVolume::cacheBuffer_.dir + dirIndex_; 00064 } 00065 //------------------------------------------------------------------------------ 00066 /** 00067 * Close a file and force cached data and directory information 00068 * to be written to the storage device. 00069 * 00070 * \return The value one, true, is returned for success and 00071 * the value zero, false, is returned for failure. 00072 * Reasons for failure include no file is open or an I/O error. 00073 */ 00074 uint8_t SdFile::close(void) { 00075 if (!sync())return false; 00076 type_ = FAT_FILE_TYPE_CLOSED; 00077 return true; 00078 } 00079 //------------------------------------------------------------------------------ 00080 /** 00081 * Check for contiguous file and return its raw block range. 00082 * 00083 * \param[out] bgnBlock the first block address for the file. 00084 * \param[out] endBlock the last block address for the file. 00085 * 00086 * \return The value one, true, is returned for success and 00087 * the value zero, false, is returned for failure. 00088 * Reasons for failure include file is not contiguous, file has zero length 00089 * or an I/O error occurred. 00090 */ 00091 uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { 00092 // error if no blocks 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 // check for contiguous 00100 if (next != (c + 1)) { 00101 // error if not end of chain 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 //------------------------------------------------------------------------------ 00111 /** 00112 * Create and open a new contiguous file of a specified size. 00113 * 00114 * \note This function only supports short DOS 8.3 names. 00115 * See open() for more information. 00116 * 00117 * \param[in] dirFile The directory where the file will be created. 00118 * \param[in] fileName A valid DOS 8.3 file name. 00119 * \param[in] size The desired file size. 00120 * 00121 * \return The value one, true, is returned for success and 00122 * the value zero, false, is returned for failure. 00123 * Reasons for failure include \a fileName contains 00124 * an invalid DOS 8.3 file name, the FAT volume has not been initialized, 00125 * a file is already open, the file already exists, the root 00126 * directory is full or an I/O error. 00127 * 00128 */ 00129 uint8_t SdFile::createContiguous(SdFile* dirFile, 00130 const char* fileName, uint32_t size) { 00131 // don't allow zero length file 00132 if (size == 0) return false; 00133 if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false; 00134 00135 // calculate number of clusters needed 00136 uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; 00137 00138 // allocate clusters 00139 if (!vol_->allocContiguous(count, &firstCluster_)) { 00140 remove(); 00141 return false; 00142 } 00143 fileSize_ = size; 00144 00145 // insure sync() will update dir entry 00146 flags_ |= F_FILE_DIR_DIRTY; 00147 return sync(); 00148 } 00149 //------------------------------------------------------------------------------ 00150 /** 00151 * Return a files directory entry 00152 * 00153 * \param[out] dir Location for return of the files directory entry. 00154 * 00155 * \return The value one, true, is returned for success and 00156 * the value zero, false, is returned for failure. 00157 */ 00158 uint8_t SdFile::dirEntry(dir_t* dir) { 00159 // make sure fields on SD are correct 00160 if (!sync()) return false; 00161 00162 // read entry 00163 dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); 00164 if (!p) return false; 00165 00166 // copy to caller's struct 00167 memcpy(dir, p, sizeof(dir_t)); 00168 return true; 00169 } 00170 //------------------------------------------------------------------------------ 00171 /** 00172 * Format the name field of \a dir into the 13 byte array 00173 * \a name in standard 8.3 short name format. 00174 * 00175 * \param[in] dir The directory structure containing the name. 00176 * \param[out] name A 13 byte char array for the formatted name. 00177 */ 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 //------------------------------------------------------------------------------ 00188 /** List directory contents to Serial. 00189 * 00190 * \param[in] flags The inclusive OR of 00191 * 00192 * LS_DATE - %Print file modification date 00193 * 00194 * LS_SIZE - %Print file size. 00195 * 00196 * LS_R - Recursive list of subdirectories. 00197 * 00198 * \param[in] indent Amount of space before file name. Used for recursive 00199 * list to indicate subdirectory level. 00200 */ 00201 void SdFile::ls(uint8_t flags, uint8_t indent) { 00202 dir_t* p; 00203 00204 rewind(); 00205 while ((p = readDirCache())) { 00206 // done if past last used entry 00207 if (p->name[0] == DIR_NAME_FREE) break; 00208 00209 // skip deleted entry and entries for . and .. 00210 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; 00211 00212 // only list subdirectories and files 00213 if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; 00214 00215 // print any indent spaces 00216 for (int8_t i = 0; i < indent; i++) Serial.print(' '); 00217 00218 // print file name with possible blank fill 00219 printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); 00220 00221 // print modify date/time if requested 00222 if (flags & LS_DATE) { 00223 printFatDate(p->lastWriteDate); 00224 Serial.putc(' '); 00225 printFatTime(p->lastWriteTime); 00226 } 00227 // print size if requested 00228 if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { 00229 Serial.putc(' '); 00230 Serial.printf(p->fileSize); 00231 } 00232 Serial.putc('/n'); 00233 00234 // list subdirectory content if requested 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 // format directory name field from a 8.3 name string 00245 uint8_t SdFile::make83Name(const char* str, uint8_t* name) { 00246 uint8_t c; 00247 uint8_t n = 7; // max index for part before dot 00248 uint8_t i = 0; 00249 // blank fill name and extension 00250 while (i < 11) name[i++] = ' '; 00251 i = 0; 00252 while ((c = *str++) != '\0') { 00253 if (c == '.') { 00254 if (n == 10) return false; // only one dot allowed 00255 n = 10; // max index for full 8.3 name 00256 i = 8; // place for extension 00257 } else { 00258 // illegal FAT characters 00259 PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); 00260 uint8_t b; 00261 while ((b = pgm_read_byte(p++))) if (b == c) return false; 00262 // check size and only allow ASCII printable characters 00263 if (i > n || c < 0X21 || c > 0X7E)return false; 00264 // only upper case allowed in 8.3 names - convert lower to upper 00265 name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); 00266 } 00267 } 00268 // must have a file name, extension is optional 00269 return name[0] != ' '; 00270 } 00271 //------------------------------------------------------------------------------ 00272 /** Make a new directory. 00273 * 00274 * \param[in] dir An open SdFat instance for the directory that will containing 00275 * the new directory. 00276 * 00277 * \param[in] dirName A valid 8.3 DOS name for the new directory. 00278 * 00279 * \return The value one, true, is returned for success and 00280 * the value zero, false, is returned for failure. 00281 * Reasons for failure include this SdFile is already open, \a dir is not a 00282 * directory, \a dirName is invalid or already exists in \a dir. 00283 */ 00284 uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { 00285 dir_t d; 00286 00287 // create a normal file 00288 if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false; 00289 00290 // convert SdFile to directory 00291 flags_ = O_READ; 00292 type_ = FAT_FILE_TYPE_SUBDIR; 00293 00294 // allocate and zero first cluster 00295 if (!addDirCluster())return false; 00296 00297 // force entry to SD 00298 if (!sync()) return false; 00299 00300 // cache entry - should already be in cache due to sync() call 00301 dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); 00302 if (!p) return false; 00303 00304 // change directory entry attribute 00305 p->attributes = DIR_ATT_DIRECTORY; 00306 00307 // make entry for '.' 00308 memcpy(&d, p, sizeof(d)); 00309 for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; 00310 d.name[0] = '.'; 00311 00312 // cache block for '.' and '..' 00313 uint32_t block = vol_->clusterStartBlock(firstCluster_); 00314 if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false; 00315 00316 // copy '.' to block 00317 memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d)); 00318 00319 // make entry for '..' 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 // copy '..' to block 00329 memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d)); 00330 00331 // set position after '..' 00332 curPosition_ = 2 * sizeof(d); 00333 00334 // write first block 00335 return SdVolume::cacheFlush(); 00336 } 00337 //------------------------------------------------------------------------------ 00338 /** 00339 * Open a file or directory by name. 00340 * 00341 * \param[in] dirFile An open SdFat instance for the directory containing the 00342 * file to be opened. 00343 * 00344 * \param[in] fileName A valid 8.3 DOS name for a file to be opened. 00345 * 00346 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive 00347 * OR of flags from the following list 00348 * 00349 * O_READ - Open for reading. 00350 * 00351 * O_RDONLY - Same as O_READ. 00352 * 00353 * O_WRITE - Open for writing. 00354 * 00355 * O_WRONLY - Same as O_WRITE. 00356 * 00357 * O_RDWR - Open for reading and writing. 00358 * 00359 * O_APPEND - If set, the file offset shall be set to the end of the 00360 * file prior to each write. 00361 * 00362 * O_CREAT - If the file exists, this flag has no effect except as noted 00363 * under O_EXCL below. Otherwise, the file shall be created 00364 * 00365 * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists. 00366 * 00367 * O_SYNC - Call sync() after each write. This flag should not be used with 00368 * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. 00369 * These functions do character at a time writes so sync() will be called 00370 * after each byte. 00371 * 00372 * O_TRUNC - If the file exists and is a regular file, and the file is 00373 * successfully opened and is not read only, its length shall be truncated to 0. 00374 * 00375 * \note Directory files must be opened read only. Write and truncation is 00376 * not allowed for directory files. 00377 * 00378 * \return The value one, true, is returned for success and 00379 * the value zero, false, is returned for failure. 00380 * Reasons for failure include this SdFile is already open, \a difFile is not 00381 * a directory, \a fileName is invalid, the file does not exist 00382 * or can't be opened in the access mode specified by oflag. 00383 */ 00384 uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { 00385 uint8_t dname[11]; 00386 dir_t* p; 00387 00388 // error if already open 00389 if (isOpen ())return false; 00390 00391 if (!make83Name(fileName, dname)) return false; 00392 vol_ = dirFile->vol_; 00393 dirFile->rewind(); 00394 00395 // bool for empty entry found 00396 uint8_t emptyFound = false; 00397 00398 // search for file 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 // remember first empty slot 00406 if (!emptyFound) { 00407 emptyFound = true; 00408 dirIndex_ = index; 00409 dirBlock_ = SdVolume::cacheBlockNumber_; 00410 } 00411 // done if no entries follow 00412 if (p->name[0] == DIR_NAME_FREE) break; 00413 } else if (!memcmp(dname, p->name, 11)) { 00414 // don't open existing file if O_CREAT and O_EXCL 00415 if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; 00416 00417 // open found file 00418 return openCachedEntry(0XF & index, oflag); 00419 } 00420 } 00421 // only create file if O_CREAT and O_WRITE 00422 if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false; 00423 00424 // cache found slot or add cluster if end of file 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 // add and zero cluster for dirFile - first cluster is in cache for write 00432 if (!dirFile->addDirCluster()) return false; 00433 00434 // use first entry in cluster 00435 dirIndex_ = 0; 00436 p = SdVolume::cacheBuffer_.dir; 00437 } 00438 // initialize as empty file 00439 memset(p, 0, sizeof(dir_t)); 00440 memcpy(p->name, dname, 11); 00441 00442 // set timestamps 00443 if (dateTime_) { 00444 // call user function 00445 dateTime_(&p->creationDate, &p->creationTime); 00446 } else { 00447 // use default date/time 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 // force write of entry to SD 00456 if (!SdVolume::cacheFlush()) return false; 00457 00458 // open entry in cache 00459 return openCachedEntry(dirIndex_, oflag); 00460 } 00461 //------------------------------------------------------------------------------ 00462 /** 00463 * Open a file by index. 00464 * 00465 * \param[in] dirFile An open SdFat instance for the directory. 00466 * 00467 * \param[in] index The \a index of the directory entry for the file to be 00468 * opened. The value for \a index is (directory file position)/32. 00469 * 00470 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive 00471 * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. 00472 * 00473 * See open() by fileName for definition of flags and return values. 00474 * 00475 */ 00476 uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { 00477 // error if already open 00478 if (isOpen ())return false; 00479 00480 // don't open existing file if O_CREAT and O_EXCL - user call error 00481 if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; 00482 00483 vol_ = dirFile->vol_; 00484 00485 // seek to location of entry 00486 if (!dirFile->seekSet(32 * index)) return false; 00487 00488 // read entry into cache 00489 dir_t* p = dirFile->readDirCache(); 00490 if (p == NULL) return false; 00491 00492 // error if empty slot or '.' or '..' 00493 if (p->name[0] == DIR_NAME_FREE || 00494 p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { 00495 return false; 00496 } 00497 // open cached entry 00498 return openCachedEntry(index & 0XF, oflag); 00499 } 00500 //------------------------------------------------------------------------------ 00501 // open a cached directory entry. Assumes vol_ is initializes 00502 uint8_t SdFile::openCachedEntry(uint8_t dirIndex , uint8_t oflag) { 00503 // location of entry in cache 00504 dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex ; 00505 00506 // write or truncate is an error for a directory or read-only file 00507 if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { 00508 if (oflag & (O_WRITE | O_TRUNC)) return false; 00509 } 00510 // remember location of directory entry on SD 00511 dirIndex_ = dirIndex ; 00512 dirBlock_ = SdVolume::cacheBlockNumber_; 00513 00514 // copy first cluster number for directory fields 00515 firstCluster_ = (uint32_t)p->firstClusterHigh << 16; 00516 firstCluster_ |= p->firstClusterLow; 00517 00518 // make sure it is a normal file or subdirectory 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 // save open flags for read/write 00529 flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND); 00530 00531 // set to start of file 00532 curCluster_ = 0; 00533 curPosition_ = 0; 00534 00535 // truncate file to zero length if requested 00536 if (oflag & O_TRUNC) return truncate(0); 00537 return true; 00538 } 00539 //------------------------------------------------------------------------------ 00540 /** 00541 * Open a volume's root directory. 00542 * 00543 * \param[in] vol The FAT volume containing the root directory to be opened. 00544 * 00545 * \return The value one, true, is returned for success and 00546 * the value zero, false, is returned for failure. 00547 * Reasons for failure include the FAT volume has not been initialized 00548 * or it a FAT12 volume. 00549 */ 00550 uint8_t SdFile::openRoot(SdVolume* vol) { 00551 // error if file is already open 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 // volume is not initialized or FAT12 00564 return false; 00565 } 00566 vol_ = vol; 00567 // read only 00568 flags_ = O_READ; 00569 00570 // set to start of file 00571 curCluster_ = 0; 00572 curPosition_ = 0; 00573 00574 // root has no directory entry 00575 dirBlock_ = 0; 00576 dirIndex_ = 0; 00577 return true; 00578 } 00579 //------------------------------------------------------------------------------ 00580 /** %Print the name field of a directory entry in 8.3 format to Serial. 00581 * 00582 * \param[in] dir The directory structure containing the name. 00583 * \param[in] width Blank fill name if length is less than \a width. 00584 */ 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.write(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 //------------------------------------------------------------------------------ 00606 /** %Print a directory date field to Serial. 00607 * 00608 * Format is yyyy-mm-dd. 00609 * 00610 * \param[in] fatDate The date field from a directory entry. 00611 */ 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 //------------------------------------------------------------------------------ 00620 /** %Print a directory time field to Serial. 00621 * 00622 * Format is hh:mm:ss. 00623 * 00624 * \param[in] fatTime The time field from a directory entry. 00625 */ 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 //------------------------------------------------------------------------------ 00634 /** %Print a value as two digits to Serial. 00635 * 00636 * \param[in] v Value to be printed, 0 <= \a v <= 99 00637 */ 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 //------------------------------------------------------------------------------ 00646 /** 00647 * Read data from a file starting at the current position. 00648 * 00649 * \param[out] buf Pointer to the location that will receive the data. 00650 * 00651 * \param[in] nbyte Maximum number of bytes to read. 00652 * 00653 * \return For success read() returns the number of bytes read. 00654 * A value less than \a nbyte, including zero, will be returned 00655 * if end of file is reached. 00656 * If an error occurs, read() returns -1. Possible errors include 00657 * read() called before a file has been opened, corrupt file system 00658 * or an I/O error occurred. 00659 */ 00660 int16_t SdFile::read(void* buf, uint16_t nbyte) { 00661 uint8_t* dst = reinterpret_cast<uint8_t*>(buf); 00662 00663 // error if not open or write only 00664 if (!isOpen () || !(flags_ & O_READ)) return -1; 00665 00666 // max bytes left in file 00667 if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; 00668 00669 // amount left to read 00670 uint16_t toRead = nbyte; 00671 while (toRead > 0) { 00672 uint32_t block; // raw device block number 00673 uint16_t offset = curPosition_ & 0X1FF; // offset in block 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 // start of new cluster 00680 if (curPosition_ == 0) { 00681 // use first cluster in file 00682 curCluster_ = firstCluster_; 00683 } else { 00684 // get next cluster from FAT 00685 if (!vol_->fatGet(curCluster_, &curCluster_)) return -1; 00686 } 00687 } 00688 block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; 00689 } 00690 uint16_t n = toRead; 00691 00692 // amount to be read from current block 00693 if (n > (512 - offset)) n = 512 - offset; 00694 00695 // no buffering needed if n == 512 or user requests no buffering 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 // read block to cache and copy data to caller 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 //------------------------------------------------------------------------------ 00713 /** 00714 * Read the next directory entry from a directory file. 00715 * 00716 * \param[out] dir The dir_t struct that will receive the data. 00717 * 00718 * \return For success readDir() returns the number of bytes read. 00719 * A value of zero will be returned if end of file is reached. 00720 * If an error occurs, readDir() returns -1. Possible errors include 00721 * readDir() called before a directory has been opened, this is not 00722 * a directory file or an I/O error occurred. 00723 */ 00724 int8_t SdFile::readDir(dir_t* dir) { 00725 int8_t n; 00726 // if not a directory file or miss-positioned return an error 00727 if (!isDir () || (0X1F & curPosition_)) return -1; 00728 00729 while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) { 00730 // last entry if DIR_NAME_FREE 00731 if (dir->name[0] == DIR_NAME_FREE) break; 00732 // skip empty entries and entry for . and .. 00733 if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; 00734 // return if normal file or subdirectory 00735 if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; 00736 } 00737 // error, end of file, or past last entry 00738 return n < 0 ? -1 : 0; 00739 } 00740 //------------------------------------------------------------------------------ 00741 // Read next directory entry into the cache 00742 // Assumes file is correctly positioned 00743 dir_t* SdFile::readDirCache(void) { 00744 // error if not directory 00745 if (!isDir ()) return NULL; 00746 00747 // index of entry in cache 00748 uint8_t i = (curPosition_ >> 5) & 0XF; 00749 00750 // use read to locate and cache block 00751 if (read() < 0) return NULL; 00752 00753 // advance to next entry 00754 curPosition_ += 31; 00755 00756 // return pointer to entry 00757 return (SdVolume::cacheBuffer_.dir + i); 00758 } 00759 //------------------------------------------------------------------------------ 00760 /** 00761 * Remove a file. 00762 * 00763 * The directory entry and all data for the file are deleted. 00764 * 00765 * \note This function should not be used to delete the 8.3 version of a 00766 * file that has a long name. For example if a file has the long name 00767 * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". 00768 * 00769 * \return The value one, true, is returned for success and 00770 * the value zero, false, is returned for failure. 00771 * Reasons for failure include the file read-only, is a directory, 00772 * or an I/O error occurred. 00773 */ 00774 uint8_t SdFile::remove(void) { 00775 // free any clusters - will fail if read-only or directory 00776 if (!truncate(0)) return false; 00777 00778 // cache directory entry 00779 dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); 00780 if (!d) return false; 00781 00782 // mark entry deleted 00783 d->name[0] = DIR_NAME_DELETED; 00784 00785 // set this SdFile closed 00786 type_ = FAT_FILE_TYPE_CLOSED; 00787 00788 // write entry to SD 00789 return SdVolume::cacheFlush(); 00790 } 00791 //------------------------------------------------------------------------------ 00792 /** 00793 * Remove a file. 00794 * 00795 * The directory entry and all data for the file are deleted. 00796 * 00797 * \param[in] dirFile The directory that contains the file. 00798 * \param[in] fileName The name of the file to be removed. 00799 * 00800 * \note This function should not be used to delete the 8.3 version of a 00801 * file that has a long name. For example if a file has the long name 00802 * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". 00803 * 00804 * \return The value one, true, is returned for success and 00805 * the value zero, false, is returned for failure. 00806 * Reasons for failure include the file is a directory, is read only, 00807 * \a dirFile is not a directory, \a fileName is not found 00808 * or an I/O error occurred. 00809 */ 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 //------------------------------------------------------------------------------ 00816 /** Remove a directory file. 00817 * 00818 * The directory file will be removed only if it is empty and is not the 00819 * root directory. rmDir() follows DOS and Windows and ignores the 00820 * read-only attribute for the directory. 00821 * 00822 * \note This function should not be used to delete the 8.3 version of a 00823 * directory that has a long name. For example if a directory has the 00824 * long name "New folder" you should not delete the 8.3 name "NEWFOL~1". 00825 * 00826 * \return The value one, true, is returned for success and 00827 * the value zero, false, is returned for failure. 00828 * Reasons for failure include the file is not a directory, is the root 00829 * directory, is not empty, or an I/O error occurred. 00830 */ 00831 uint8_t SdFile::rmDir(void) { 00832 // must be open subdirectory 00833 if (!isSubDir ()) return false; 00834 00835 rewind(); 00836 00837 // make sure directory is empty 00838 while (curPosition_ < fileSize_) { 00839 dir_t* p = readDirCache(); 00840 if (p == NULL) return false; 00841 // done if past last used entry 00842 if (p->name[0] == DIR_NAME_FREE) break; 00843 // skip empty slot or '.' or '..' 00844 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; 00845 // error not empty 00846 if (DIR_IS_FILE_OR_SUBDIR(p)) return false; 00847 } 00848 // convert empty directory to normal file for remove 00849 type_ = FAT_FILE_TYPE_NORMAL; 00850 flags_ |= O_WRITE; 00851 return remove(); 00852 } 00853 //------------------------------------------------------------------------------ 00854 /** Recursively delete a directory and all contained files. 00855 * 00856 * This is like the Unix/Linux 'rm -rf *' if called with the root directory 00857 * hence the name. 00858 * 00859 * Warning - This will remove all contents of the directory including 00860 * subdirectories. The directory will then be removed if it is not root. 00861 * The read-only attribute for files will be ignored. 00862 * 00863 * \note This function should not be used to delete the 8.3 version of 00864 * a directory that has a long name. See remove() and rmDir(). 00865 * 00866 * \return The value one, true, is returned for success and 00867 * the value zero, false, is returned for failure. 00868 */ 00869 uint8_t SdFile::rmRfStar(void) { 00870 rewind(); 00871 while (curPosition_ < fileSize_) { 00872 SdFile f; 00873 00874 // remember position 00875 uint16_t index = curPosition_/32; 00876 00877 dir_t* p = readDirCache(); 00878 if (!p) return false; 00879 00880 // done if past last entry 00881 if (p->name[0] == DIR_NAME_FREE) break; 00882 00883 // skip empty slot or '.' or '..' 00884 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; 00885 00886 // skip if part of long file name or volume label in root 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 // recursively delete 00892 if (!f.rmRfStar()) return false; 00893 } else { 00894 // ignore read-only 00895 f.flags_ |= O_WRITE; 00896 if (!f.remove()) return false; 00897 } 00898 // position to next entry if required 00899 if (curPosition_ != (32*(index + 1))) { 00900 if (!seekSet(32*(index + 1))) return false; 00901 } 00902 } 00903 // don't try to delete root 00904 if (isRoot ()) return true; 00905 return rmDir(); 00906 } 00907 //------------------------------------------------------------------------------ 00908 /** 00909 * Sets a file's position. 00910 * 00911 * \param[in] pos The new position in bytes from the beginning of the file. 00912 * 00913 * \return The value one, true, is returned for success and 00914 * the value zero, false, is returned for failure. 00915 */ 00916 uint8_t SdFile::seekSet(uint32_t pos) { 00917 // error if file not open or seek past end of file 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 // set position to start of file 00926 curCluster_ = 0; 00927 curPosition_ = 0; 00928 return true; 00929 } 00930 // calculate cluster index for cur and new position 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 // must follow chain from first cluster 00936 curCluster_ = firstCluster_; 00937 } else { 00938 // advance from curPosition 00939 nNew -= nCur; 00940 } 00941 while (nNew--) { 00942 if (!vol_->fatGet(curCluster_, &curCluster_)) return false; 00943 } 00944 curPosition_ = pos; 00945 return true; 00946 } 00947 //------------------------------------------------------------------------------ 00948 /** 00949 * The sync() call causes all modified data and directory fields 00950 * to be written to the storage device. 00951 * 00952 * \return The value one, true, is returned for success and 00953 * the value zero, false, is returned for failure. 00954 * Reasons for failure include a call to sync() before a file has been 00955 * opened or an I/O error. 00956 */ 00957 uint8_t SdFile::sync(void) { 00958 // only allow open files and directories 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 // do not set filesize for dir files 00966 if (!isDir ()) d->fileSize = fileSize_; 00967 00968 // update first cluster fields 00969 d->firstClusterLow = firstCluster_ & 0XFFFF; 00970 d->firstClusterHigh = firstCluster_ >> 16; 00971 00972 // set modify time if user supplied a callback date/time function 00973 if (dateTime_) { 00974 dateTime_(&d->lastWriteDate, &d->lastWriteTime); 00975 d->lastAccessDate = d->lastWriteDate; 00976 } 00977 // clear directory dirty 00978 flags_ &= ~F_FILE_DIR_DIRTY; 00979 } 00980 return SdVolume::cacheFlush(); 00981 } 00982 //------------------------------------------------------------------------------ 00983 /** 00984 * Set a file's timestamps in its directory entry. 00985 * 00986 * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive 00987 * OR of flags from the following list 00988 * 00989 * T_ACCESS - Set the file's last access date. 00990 * 00991 * T_CREATE - Set the file's creation date and time. 00992 * 00993 * T_WRITE - Set the file's last write/modification date and time. 00994 * 00995 * \param[in] year Valid range 1980 - 2107 inclusive. 00996 * 00997 * \param[in] month Valid range 1 - 12 inclusive. 00998 * 00999 * \param[in] day Valid range 1 - 31 inclusive. 01000 * 01001 * \param[in] hour Valid range 0 - 23 inclusive. 01002 * 01003 * \param[in] minute Valid range 0 - 59 inclusive. 01004 * 01005 * \param[in] second Valid range 0 - 59 inclusive 01006 * 01007 * \note It is possible to set an invalid date since there is no check for 01008 * the number of days in a month. 01009 * 01010 * \note 01011 * Modify and access timestamps may be overwritten if a date time callback 01012 * function has been set by dateTimeCallback(). 01013 * 01014 * \return The value one, true, is returned for success and 01015 * the value zero, false, is returned for failure. 01016 */ 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 // seems to be units of 1/100 second not 1/10 as Microsoft states 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 //------------------------------------------------------------------------------ 01053 /** 01054 * Truncate a file to a specified length. The current file position 01055 * will be maintained if it is less than or equal to \a length otherwise 01056 * it will be set to end of file. 01057 * 01058 * \param[in] length The desired length for the file. 01059 * 01060 * \return The value one, true, is returned for success and 01061 * the value zero, false, is returned for failure. 01062 * Reasons for failure include file is read only, file is a directory, 01063 * \a length is greater than the current file size or an I/O error occurs. 01064 */ 01065 uint8_t SdFile::truncate(uint32_t length) { 01066 // error if not a normal file or read-only 01067 if (!isFile () || !(flags_ & O_WRITE)) return false; 01068 01069 // error if length is greater than current size 01070 if (length > fileSize_) return false; 01071 01072 // fileSize and length are zero - nothing to do 01073 if (fileSize_ == 0) return true; 01074 01075 // remember position for seek after truncation 01076 uint32_t newPos = curPosition_ > length ? length : curPosition_; 01077 01078 // position to last cluster in truncated file 01079 if (!seekSet(length)) return false; 01080 01081 if (length == 0) { 01082 // free all clusters 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 // free extra clusters 01091 if (!vol_->freeChain(toFree)) return false; 01092 01093 // current cluster is end of chain 01094 if (!vol_->fatPutEOC(curCluster_)) return false; 01095 } 01096 } 01097 fileSize_ = length; 01098 01099 // need to update directory entry 01100 flags_ |= F_FILE_DIR_DIRTY; 01101 01102 if (!sync()) return false; 01103 01104 // set file to correct position 01105 return seekSet(newPos); 01106 } 01107 //------------------------------------------------------------------------------ 01108 /** 01109 * Write data to an open file. 01110 * 01111 * \note Data is moved to the cache but may not be written to the 01112 * storage device until sync() is called. 01113 * 01114 * \param[in] buf Pointer to the location of the data to be written. 01115 * 01116 * \param[in] nbyte Number of bytes to write. 01117 * 01118 * \return For success write() returns the number of bytes written, always 01119 * \a nbyte. If an error occurs, write() returns -1. Possible errors 01120 * include write() is called before a file has been opened, write is called 01121 * for a read-only file, device is full, a corrupt file system or an I/O error. 01122 * 01123 */ 01124 size_t SdFile::write(const void* buf, uint16_t nbyte) { 01125 // convert void* to uint8_t* - must be before goto statements 01126 const uint8_t* src = reinterpret_cast<const uint8_t*>(buf); 01127 01128 // number of bytes left to write - must be before goto statements 01129 uint16_t nToWrite = nbyte; 01130 01131 // error if not a normal file or is read-only 01132 if (!isFile () || !(flags_ & O_WRITE)) goto writeErrorReturn; 01133 01134 // seek to end of file if append flag 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 // start of new cluster 01144 if (curCluster_ == 0) { 01145 if (firstCluster_ == 0) { 01146 // allocate first cluster of file 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 // add cluster if at end of chain 01156 if (!addCluster()) goto writeErrorReturn; 01157 } else { 01158 curCluster_ = next; 01159 } 01160 } 01161 } 01162 // max space in block 01163 uint16_t n = 512 - blockOffset; 01164 01165 // lesser of space and amount to write 01166 if (n > nToWrite) n = nToWrite; 01167 01168 // block for data write 01169 uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; 01170 if (n == 512) { 01171 // full block - don't need to use cache 01172 // invalidate cache if block is in cache 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 // start of new block don't need to read into cache 01181 if (!SdVolume::cacheFlush()) goto writeErrorReturn; 01182 SdVolume::cacheBlockNumber_ = block; 01183 SdVolume::cacheSetDirty(); 01184 } else { 01185 // rewrite part of block 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 // update fileSize and insure sync will update dir entry 01199 fileSize_ = curPosition_; 01200 flags_ |= F_FILE_DIR_DIRTY; 01201 } else if (dateTime_ && nbyte) { 01202 // insure sync will update modified date and time 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 // return for write error 01213 //writeError = true; 01214 setWriteError(); 01215 return 0; 01216 } 01217 //------------------------------------------------------------------------------ 01218 /** 01219 * Write a byte to a file. Required by the Arduino Print class. 01220 * 01221 * Use SdFile::writeError to check for errors. 01222 */ 01223 size_t SdFile::write(uint8_t b) { 01224 return write(&b, 1); 01225 } 01226 //------------------------------------------------------------------------------ 01227 /** 01228 * Write a string to a file. Used by the Arduino Print class. 01229 * 01230 * Use SdFile::writeError to check for errors. 01231 */ 01232 size_t SdFile::write(const char* str) { 01233 return write(str, strlen(str)); 01234 } 01235 //------------------------------------------------------------------------------ 01236 /** 01237 * Write a PROGMEM string to a file. 01238 * 01239 * Use SdFile::writeError to check for errors. 01240 */ 01241 void SdFile::write_P(PGM_P str) { 01242 for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); 01243 } 01244 //------------------------------------------------------------------------------ 01245 /** 01246 * Write a PROGMEM string followed by CR/LF to a file. 01247 * 01248 * Use SdFile::writeError to check for errors. 01249 */ 01250 void SdFile::writeln_P(PGM_P str) { 01251 write_P(str); 01252 println(); 01253 }
Generated on Thu Jul 14 2022 02:07:54 by
1.7.2