utility
Embed:
(wiki syntax)
Show/hide line numbers
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