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@0:f6c99a47ce43, 2015-07-14 (annotated)
- Committer:
- Jackson_lv
- Date:
- Tue Jul 14 01:58:03 2015 +0000
- Revision:
- 0:f6c99a47ce43
utility;
Who changed what in which revision?
| User | Revision | Line number | New contents of line | 
|---|---|---|---|
| Jackson_lv | 0:f6c99a47ce43 | 1 | /* Arduino SdFat Library | 
| Jackson_lv | 0:f6c99a47ce43 | 2 | * Copyright (C) 2009 by William Greiman | 
| Jackson_lv | 0:f6c99a47ce43 | 3 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 4 | * This file is part of the Arduino SdFat Library | 
| Jackson_lv | 0:f6c99a47ce43 | 5 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 6 | * This Library is free software: you can redistribute it and/or modify | 
| Jackson_lv | 0:f6c99a47ce43 | 7 | * it under the terms of the GNU General Public License as published by | 
| Jackson_lv | 0:f6c99a47ce43 | 8 | * the Free Software Foundation, either version 3 of the License, or | 
| Jackson_lv | 0:f6c99a47ce43 | 9 | * (at your option) any later version. | 
| Jackson_lv | 0:f6c99a47ce43 | 10 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 11 | * This Library is distributed in the hope that it will be useful, | 
| Jackson_lv | 0:f6c99a47ce43 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| Jackson_lv | 0:f6c99a47ce43 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
| Jackson_lv | 0:f6c99a47ce43 | 14 | * GNU General Public License for more details. | 
| Jackson_lv | 0:f6c99a47ce43 | 15 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 16 | * You should have received a copy of the GNU General Public License | 
| Jackson_lv | 0:f6c99a47ce43 | 17 | * along with the Arduino SdFat Library. If not, see | 
| Jackson_lv | 0:f6c99a47ce43 | 18 | * <http://www.gnu.org/licenses/>. | 
| Jackson_lv | 0:f6c99a47ce43 | 19 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 20 | #include <SdFat.h> | 
| Jackson_lv | 0:f6c99a47ce43 | 21 | #include "mbed.h" | 
| Jackson_lv | 0:f6c99a47ce43 | 22 | |
| Jackson_lv | 0:f6c99a47ce43 | 23 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 24 | // callback function for date/time | 
| Jackson_lv | 0:f6c99a47ce43 | 25 | void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL; | 
| Jackson_lv | 0:f6c99a47ce43 | 26 | |
| Jackson_lv | 0:f6c99a47ce43 | 27 | #if ALLOW_DEPRECATED_FUNCTIONS | 
| Jackson_lv | 0:f6c99a47ce43 | 28 | // suppress cpplint warnings with NOLINT comment | 
| Jackson_lv | 0:f6c99a47ce43 | 29 | void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT | 
| Jackson_lv | 0:f6c99a47ce43 | 30 | #endif // ALLOW_DEPRECATED_FUNCTIONS | 
| Jackson_lv | 0:f6c99a47ce43 | 31 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 32 | // add a cluster to a file | 
| Jackson_lv | 0:f6c99a47ce43 | 33 | uint8_t SdFile::addCluster() { | 
| Jackson_lv | 0:f6c99a47ce43 | 34 | if (!vol_->allocContiguous(1, &curCluster_)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 35 | |
| Jackson_lv | 0:f6c99a47ce43 | 36 | // if first cluster of file link to directory entry | 
| Jackson_lv | 0:f6c99a47ce43 | 37 | if (firstCluster_ == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 38 | firstCluster_ = curCluster_; | 
| Jackson_lv | 0:f6c99a47ce43 | 39 | flags_ |= F_FILE_DIR_DIRTY; | 
| Jackson_lv | 0:f6c99a47ce43 | 40 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 41 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 42 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 43 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 44 | // Add a cluster to a directory file and zero the cluster. | 
| Jackson_lv | 0:f6c99a47ce43 | 45 | // return with first block of cluster in the cache | 
| Jackson_lv | 0:f6c99a47ce43 | 46 | uint8_t SdFile::addDirCluster(void) { | 
| Jackson_lv | 0:f6c99a47ce43 | 47 | if (!addCluster()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 48 | |
| Jackson_lv | 0:f6c99a47ce43 | 49 | // zero data in cluster insure first cluster is in cache | 
| Jackson_lv | 0:f6c99a47ce43 | 50 | uint32_t block = vol_->clusterStartBlock(curCluster_); | 
| Jackson_lv | 0:f6c99a47ce43 | 51 | for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) { | 
| Jackson_lv | 0:f6c99a47ce43 | 52 | if (!SdVolume::cacheZeroBlock(block + i - 1)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 53 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 54 | // Increase directory file size by cluster size | 
| Jackson_lv | 0:f6c99a47ce43 | 55 | fileSize_ += 512UL << vol_->clusterSizeShift_; | 
| Jackson_lv | 0:f6c99a47ce43 | 56 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 57 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 58 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 59 | // cache a file's directory entry | 
| Jackson_lv | 0:f6c99a47ce43 | 60 | // return pointer to cached entry or null for failure | 
| Jackson_lv | 0:f6c99a47ce43 | 61 | dir_t* SdFile::cacheDirEntry(uint8_t action) { | 
| Jackson_lv | 0:f6c99a47ce43 | 62 | if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL; | 
| Jackson_lv | 0:f6c99a47ce43 | 63 | return SdVolume::cacheBuffer_.dir + dirIndex_; | 
| Jackson_lv | 0:f6c99a47ce43 | 64 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 65 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 66 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 67 | * Close a file and force cached data and directory information | 
| Jackson_lv | 0:f6c99a47ce43 | 68 | * to be written to the storage device. | 
| Jackson_lv | 0:f6c99a47ce43 | 69 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 70 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 71 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 72 | * Reasons for failure include no file is open or an I/O error. | 
| Jackson_lv | 0:f6c99a47ce43 | 73 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 74 | uint8_t SdFile::close(void) { | 
| Jackson_lv | 0:f6c99a47ce43 | 75 | if (!sync())return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 76 | type_ = FAT_FILE_TYPE_CLOSED; | 
| Jackson_lv | 0:f6c99a47ce43 | 77 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 78 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 79 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 80 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 81 | * Check for contiguous file and return its raw block range. | 
| Jackson_lv | 0:f6c99a47ce43 | 82 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 83 | * \param[out] bgnBlock the first block address for the file. | 
| Jackson_lv | 0:f6c99a47ce43 | 84 | * \param[out] endBlock the last block address for the file. | 
| Jackson_lv | 0:f6c99a47ce43 | 85 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 86 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 87 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 88 | * Reasons for failure include file is not contiguous, file has zero length | 
| Jackson_lv | 0:f6c99a47ce43 | 89 | * or an I/O error occurred. | 
| Jackson_lv | 0:f6c99a47ce43 | 90 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 91 | uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { | 
| Jackson_lv | 0:f6c99a47ce43 | 92 | // error if no blocks | 
| Jackson_lv | 0:f6c99a47ce43 | 93 | if (firstCluster_ == 0) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 94 | |
| Jackson_lv | 0:f6c99a47ce43 | 95 | for (uint32_t c = firstCluster_; ; c++) { | 
| Jackson_lv | 0:f6c99a47ce43 | 96 | uint32_t next; | 
| Jackson_lv | 0:f6c99a47ce43 | 97 | if (!vol_->fatGet(c, &next)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 98 | |
| Jackson_lv | 0:f6c99a47ce43 | 99 | // check for contiguous | 
| Jackson_lv | 0:f6c99a47ce43 | 100 | if (next != (c + 1)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 101 | // error if not end of chain | 
| Jackson_lv | 0:f6c99a47ce43 | 102 | if (!vol_->isEOC(next)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 103 | *bgnBlock = vol_->clusterStartBlock(firstCluster_); | 
| Jackson_lv | 0:f6c99a47ce43 | 104 | *endBlock = vol_->clusterStartBlock(c) | 
| Jackson_lv | 0:f6c99a47ce43 | 105 | + vol_->blocksPerCluster_ - 1; | 
| Jackson_lv | 0:f6c99a47ce43 | 106 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 107 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 108 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 109 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 110 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 111 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 112 | * Create and open a new contiguous file of a specified size. | 
| Jackson_lv | 0:f6c99a47ce43 | 113 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 114 | * \note This function only supports short DOS 8.3 names. | 
| Jackson_lv | 0:f6c99a47ce43 | 115 | * See open() for more information. | 
| Jackson_lv | 0:f6c99a47ce43 | 116 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 117 | * \param[in] dirFile The directory where the file will be created. | 
| Jackson_lv | 0:f6c99a47ce43 | 118 | * \param[in] fileName A valid DOS 8.3 file name. | 
| Jackson_lv | 0:f6c99a47ce43 | 119 | * \param[in] size The desired file size. | 
| Jackson_lv | 0:f6c99a47ce43 | 120 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 121 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 122 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 123 | * Reasons for failure include \a fileName contains | 
| Jackson_lv | 0:f6c99a47ce43 | 124 | * an invalid DOS 8.3 file name, the FAT volume has not been initialized, | 
| Jackson_lv | 0:f6c99a47ce43 | 125 | * a file is already open, the file already exists, the root | 
| Jackson_lv | 0:f6c99a47ce43 | 126 | * directory is full or an I/O error. | 
| Jackson_lv | 0:f6c99a47ce43 | 127 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 128 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 129 | uint8_t SdFile::createContiguous(SdFile* dirFile, | 
| Jackson_lv | 0:f6c99a47ce43 | 130 | const char* fileName, uint32_t size) { | 
| Jackson_lv | 0:f6c99a47ce43 | 131 | // don't allow zero length file | 
| Jackson_lv | 0:f6c99a47ce43 | 132 | if (size == 0) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 133 | if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 134 | |
| Jackson_lv | 0:f6c99a47ce43 | 135 | // calculate number of clusters needed | 
| Jackson_lv | 0:f6c99a47ce43 | 136 | uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; | 
| Jackson_lv | 0:f6c99a47ce43 | 137 | |
| Jackson_lv | 0:f6c99a47ce43 | 138 | // allocate clusters | 
| Jackson_lv | 0:f6c99a47ce43 | 139 | if (!vol_->allocContiguous(count, &firstCluster_)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 140 | remove(); | 
| Jackson_lv | 0:f6c99a47ce43 | 141 | return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 142 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 143 | fileSize_ = size; | 
| Jackson_lv | 0:f6c99a47ce43 | 144 | |
| Jackson_lv | 0:f6c99a47ce43 | 145 | // insure sync() will update dir entry | 
| Jackson_lv | 0:f6c99a47ce43 | 146 | flags_ |= F_FILE_DIR_DIRTY; | 
| Jackson_lv | 0:f6c99a47ce43 | 147 | return sync(); | 
| Jackson_lv | 0:f6c99a47ce43 | 148 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 149 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 150 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 151 | * Return a files directory entry | 
| Jackson_lv | 0:f6c99a47ce43 | 152 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 153 | * \param[out] dir Location for return of the files directory entry. | 
| Jackson_lv | 0:f6c99a47ce43 | 154 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 155 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 156 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 157 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 158 | uint8_t SdFile::dirEntry(dir_t* dir) { | 
| Jackson_lv | 0:f6c99a47ce43 | 159 | // make sure fields on SD are correct | 
| Jackson_lv | 0:f6c99a47ce43 | 160 | if (!sync()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 161 | |
| Jackson_lv | 0:f6c99a47ce43 | 162 | // read entry | 
| Jackson_lv | 0:f6c99a47ce43 | 163 | dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); | 
| Jackson_lv | 0:f6c99a47ce43 | 164 | if (!p) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 165 | |
| Jackson_lv | 0:f6c99a47ce43 | 166 | // copy to caller's struct | 
| Jackson_lv | 0:f6c99a47ce43 | 167 | memcpy(dir, p, sizeof(dir_t)); | 
| Jackson_lv | 0:f6c99a47ce43 | 168 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 169 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 170 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 171 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 172 | * Format the name field of \a dir into the 13 byte array | 
| Jackson_lv | 0:f6c99a47ce43 | 173 | * \a name in standard 8.3 short name format. | 
| Jackson_lv | 0:f6c99a47ce43 | 174 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 175 | * \param[in] dir The directory structure containing the name. | 
| Jackson_lv | 0:f6c99a47ce43 | 176 | * \param[out] name A 13 byte char array for the formatted name. | 
| Jackson_lv | 0:f6c99a47ce43 | 177 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 178 | void SdFile::dirName(const dir_t& dir, char* name) { | 
| Jackson_lv | 0:f6c99a47ce43 | 179 | uint8_t j = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 180 | for (uint8_t i = 0; i < 11; i++) { | 
| Jackson_lv | 0:f6c99a47ce43 | 181 | if (dir.name[i] == ' ')continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 182 | if (i == 8) name[j++] = '.'; | 
| Jackson_lv | 0:f6c99a47ce43 | 183 | name[j++] = dir.name[i]; | 
| Jackson_lv | 0:f6c99a47ce43 | 184 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 185 | name[j] = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 186 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 187 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 188 | /** List directory contents to Serial. | 
| Jackson_lv | 0:f6c99a47ce43 | 189 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 190 | * \param[in] flags The inclusive OR of | 
| Jackson_lv | 0:f6c99a47ce43 | 191 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 192 | * LS_DATE - %Print file modification date | 
| Jackson_lv | 0:f6c99a47ce43 | 193 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 194 | * LS_SIZE - %Print file size. | 
| Jackson_lv | 0:f6c99a47ce43 | 195 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 196 | * LS_R - Recursive list of subdirectories. | 
| Jackson_lv | 0:f6c99a47ce43 | 197 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 198 | * \param[in] indent Amount of space before file name. Used for recursive | 
| Jackson_lv | 0:f6c99a47ce43 | 199 | * list to indicate subdirectory level. | 
| Jackson_lv | 0:f6c99a47ce43 | 200 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 201 | void SdFile::ls(uint8_t flags, uint8_t indent) { | 
| Jackson_lv | 0:f6c99a47ce43 | 202 | dir_t* p; | 
| Jackson_lv | 0:f6c99a47ce43 | 203 | |
| Jackson_lv | 0:f6c99a47ce43 | 204 | rewind(); | 
| Jackson_lv | 0:f6c99a47ce43 | 205 | while ((p = readDirCache())) { | 
| Jackson_lv | 0:f6c99a47ce43 | 206 | // done if past last used entry | 
| Jackson_lv | 0:f6c99a47ce43 | 207 | if (p->name[0] == DIR_NAME_FREE) break; | 
| Jackson_lv | 0:f6c99a47ce43 | 208 | |
| Jackson_lv | 0:f6c99a47ce43 | 209 | // skip deleted entry and entries for . and .. | 
| Jackson_lv | 0:f6c99a47ce43 | 210 | if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 211 | |
| Jackson_lv | 0:f6c99a47ce43 | 212 | // only list subdirectories and files | 
| Jackson_lv | 0:f6c99a47ce43 | 213 | if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 214 | |
| Jackson_lv | 0:f6c99a47ce43 | 215 | // print any indent spaces | 
| Jackson_lv | 0:f6c99a47ce43 | 216 | for (int8_t i = 0; i < indent; i++) Serial.print(' '); | 
| Jackson_lv | 0:f6c99a47ce43 | 217 | |
| Jackson_lv | 0:f6c99a47ce43 | 218 | // print file name with possible blank fill | 
| Jackson_lv | 0:f6c99a47ce43 | 219 | printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); | 
| Jackson_lv | 0:f6c99a47ce43 | 220 | |
| Jackson_lv | 0:f6c99a47ce43 | 221 | // print modify date/time if requested | 
| Jackson_lv | 0:f6c99a47ce43 | 222 | if (flags & LS_DATE) { | 
| Jackson_lv | 0:f6c99a47ce43 | 223 | printFatDate(p->lastWriteDate); | 
| Jackson_lv | 0:f6c99a47ce43 | 224 | Serial.putc(' '); | 
| Jackson_lv | 0:f6c99a47ce43 | 225 | printFatTime(p->lastWriteTime); | 
| Jackson_lv | 0:f6c99a47ce43 | 226 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 227 | // print size if requested | 
| Jackson_lv | 0:f6c99a47ce43 | 228 | if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 229 | Serial.putc(' '); | 
| Jackson_lv | 0:f6c99a47ce43 | 230 | Serial.printf(p->fileSize); | 
| Jackson_lv | 0:f6c99a47ce43 | 231 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 232 | Serial.putc('/n'); | 
| Jackson_lv | 0:f6c99a47ce43 | 233 | |
| Jackson_lv | 0:f6c99a47ce43 | 234 | // list subdirectory content if requested | 
| Jackson_lv | 0:f6c99a47ce43 | 235 | if ((flags & LS_R) && DIR_IS_SUBDIR(p)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 236 | uint16_t index = curPosition()/32 - 1; | 
| Jackson_lv | 0:f6c99a47ce43 | 237 | SdFile s; | 
| Jackson_lv | 0:f6c99a47ce43 | 238 | if (s.open(this, index, O_READ)) s.ls(flags, indent + 2); | 
| Jackson_lv | 0:f6c99a47ce43 | 239 | seekSet(32 * (index + 1)); | 
| Jackson_lv | 0:f6c99a47ce43 | 240 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 241 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 242 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 243 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 244 | // format directory name field from a 8.3 name string | 
| Jackson_lv | 0:f6c99a47ce43 | 245 | uint8_t SdFile::make83Name(const char* str, uint8_t* name) { | 
| Jackson_lv | 0:f6c99a47ce43 | 246 | uint8_t c; | 
| Jackson_lv | 0:f6c99a47ce43 | 247 | uint8_t n = 7; // max index for part before dot | 
| Jackson_lv | 0:f6c99a47ce43 | 248 | uint8_t i = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 249 | // blank fill name and extension | 
| Jackson_lv | 0:f6c99a47ce43 | 250 | while (i < 11) name[i++] = ' '; | 
| Jackson_lv | 0:f6c99a47ce43 | 251 | i = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 252 | while ((c = *str++) != '\0') { | 
| Jackson_lv | 0:f6c99a47ce43 | 253 | if (c == '.') { | 
| Jackson_lv | 0:f6c99a47ce43 | 254 | if (n == 10) return false; // only one dot allowed | 
| Jackson_lv | 0:f6c99a47ce43 | 255 | n = 10; // max index for full 8.3 name | 
| Jackson_lv | 0:f6c99a47ce43 | 256 | i = 8; // place for extension | 
| Jackson_lv | 0:f6c99a47ce43 | 257 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 258 | // illegal FAT characters | 
| Jackson_lv | 0:f6c99a47ce43 | 259 | PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); | 
| Jackson_lv | 0:f6c99a47ce43 | 260 | uint8_t b; | 
| Jackson_lv | 0:f6c99a47ce43 | 261 | while ((b = pgm_read_byte(p++))) if (b == c) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 262 | // check size and only allow ASCII printable characters | 
| Jackson_lv | 0:f6c99a47ce43 | 263 | if (i > n || c < 0X21 || c > 0X7E)return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 264 | // only upper case allowed in 8.3 names - convert lower to upper | 
| Jackson_lv | 0:f6c99a47ce43 | 265 | name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); | 
| Jackson_lv | 0:f6c99a47ce43 | 266 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 267 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 268 | // must have a file name, extension is optional | 
| Jackson_lv | 0:f6c99a47ce43 | 269 | return name[0] != ' '; | 
| Jackson_lv | 0:f6c99a47ce43 | 270 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 271 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 272 | /** Make a new directory. | 
| Jackson_lv | 0:f6c99a47ce43 | 273 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 274 | * \param[in] dir An open SdFat instance for the directory that will containing | 
| Jackson_lv | 0:f6c99a47ce43 | 275 | * the new directory. | 
| Jackson_lv | 0:f6c99a47ce43 | 276 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 277 | * \param[in] dirName A valid 8.3 DOS name for the new directory. | 
| Jackson_lv | 0:f6c99a47ce43 | 278 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 279 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 280 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 281 | * Reasons for failure include this SdFile is already open, \a dir is not a | 
| Jackson_lv | 0:f6c99a47ce43 | 282 | * directory, \a dirName is invalid or already exists in \a dir. | 
| Jackson_lv | 0:f6c99a47ce43 | 283 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 284 | uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { | 
| Jackson_lv | 0:f6c99a47ce43 | 285 | dir_t d; | 
| Jackson_lv | 0:f6c99a47ce43 | 286 | |
| Jackson_lv | 0:f6c99a47ce43 | 287 | // create a normal file | 
| Jackson_lv | 0:f6c99a47ce43 | 288 | if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 289 | |
| Jackson_lv | 0:f6c99a47ce43 | 290 | // convert SdFile to directory | 
| Jackson_lv | 0:f6c99a47ce43 | 291 | flags_ = O_READ; | 
| Jackson_lv | 0:f6c99a47ce43 | 292 | type_ = FAT_FILE_TYPE_SUBDIR; | 
| Jackson_lv | 0:f6c99a47ce43 | 293 | |
| Jackson_lv | 0:f6c99a47ce43 | 294 | // allocate and zero first cluster | 
| Jackson_lv | 0:f6c99a47ce43 | 295 | if (!addDirCluster())return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 296 | |
| Jackson_lv | 0:f6c99a47ce43 | 297 | // force entry to SD | 
| Jackson_lv | 0:f6c99a47ce43 | 298 | if (!sync()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 299 | |
| Jackson_lv | 0:f6c99a47ce43 | 300 | // cache entry - should already be in cache due to sync() call | 
| Jackson_lv | 0:f6c99a47ce43 | 301 | dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); | 
| Jackson_lv | 0:f6c99a47ce43 | 302 | if (!p) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 303 | |
| Jackson_lv | 0:f6c99a47ce43 | 304 | // change directory entry attribute | 
| Jackson_lv | 0:f6c99a47ce43 | 305 | p->attributes = DIR_ATT_DIRECTORY; | 
| Jackson_lv | 0:f6c99a47ce43 | 306 | |
| Jackson_lv | 0:f6c99a47ce43 | 307 | // make entry for '.' | 
| Jackson_lv | 0:f6c99a47ce43 | 308 | memcpy(&d, p, sizeof(d)); | 
| Jackson_lv | 0:f6c99a47ce43 | 309 | for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; | 
| Jackson_lv | 0:f6c99a47ce43 | 310 | d.name[0] = '.'; | 
| Jackson_lv | 0:f6c99a47ce43 | 311 | |
| Jackson_lv | 0:f6c99a47ce43 | 312 | // cache block for '.' and '..' | 
| Jackson_lv | 0:f6c99a47ce43 | 313 | uint32_t block = vol_->clusterStartBlock(firstCluster_); | 
| Jackson_lv | 0:f6c99a47ce43 | 314 | if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 315 | |
| Jackson_lv | 0:f6c99a47ce43 | 316 | // copy '.' to block | 
| Jackson_lv | 0:f6c99a47ce43 | 317 | memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d)); | 
| Jackson_lv | 0:f6c99a47ce43 | 318 | |
| Jackson_lv | 0:f6c99a47ce43 | 319 | // make entry for '..' | 
| Jackson_lv | 0:f6c99a47ce43 | 320 | d.name[1] = '.'; | 
| Jackson_lv | 0:f6c99a47ce43 | 321 | if (dir->isRoot()) { | 
| Jackson_lv | 0:f6c99a47ce43 | 322 | d.firstClusterLow = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 323 | d.firstClusterHigh = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 324 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 325 | d.firstClusterLow = dir->firstCluster_ & 0XFFFF; | 
| Jackson_lv | 0:f6c99a47ce43 | 326 | d.firstClusterHigh = dir->firstCluster_ >> 16; | 
| Jackson_lv | 0:f6c99a47ce43 | 327 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 328 | // copy '..' to block | 
| Jackson_lv | 0:f6c99a47ce43 | 329 | memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d)); | 
| Jackson_lv | 0:f6c99a47ce43 | 330 | |
| Jackson_lv | 0:f6c99a47ce43 | 331 | // set position after '..' | 
| Jackson_lv | 0:f6c99a47ce43 | 332 | curPosition_ = 2 * sizeof(d); | 
| Jackson_lv | 0:f6c99a47ce43 | 333 | |
| Jackson_lv | 0:f6c99a47ce43 | 334 | // write first block | 
| Jackson_lv | 0:f6c99a47ce43 | 335 | return SdVolume::cacheFlush(); | 
| Jackson_lv | 0:f6c99a47ce43 | 336 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 337 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 338 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 339 | * Open a file or directory by name. | 
| Jackson_lv | 0:f6c99a47ce43 | 340 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 341 | * \param[in] dirFile An open SdFat instance for the directory containing the | 
| Jackson_lv | 0:f6c99a47ce43 | 342 | * file to be opened. | 
| Jackson_lv | 0:f6c99a47ce43 | 343 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 344 | * \param[in] fileName A valid 8.3 DOS name for a file to be opened. | 
| Jackson_lv | 0:f6c99a47ce43 | 345 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 346 | * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive | 
| Jackson_lv | 0:f6c99a47ce43 | 347 | * OR of flags from the following list | 
| Jackson_lv | 0:f6c99a47ce43 | 348 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 349 | * O_READ - Open for reading. | 
| Jackson_lv | 0:f6c99a47ce43 | 350 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 351 | * O_RDONLY - Same as O_READ. | 
| Jackson_lv | 0:f6c99a47ce43 | 352 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 353 | * O_WRITE - Open for writing. | 
| Jackson_lv | 0:f6c99a47ce43 | 354 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 355 | * O_WRONLY - Same as O_WRITE. | 
| Jackson_lv | 0:f6c99a47ce43 | 356 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 357 | * O_RDWR - Open for reading and writing. | 
| Jackson_lv | 0:f6c99a47ce43 | 358 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 359 | * O_APPEND - If set, the file offset shall be set to the end of the | 
| Jackson_lv | 0:f6c99a47ce43 | 360 | * file prior to each write. | 
| Jackson_lv | 0:f6c99a47ce43 | 361 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 362 | * O_CREAT - If the file exists, this flag has no effect except as noted | 
| Jackson_lv | 0:f6c99a47ce43 | 363 | * under O_EXCL below. Otherwise, the file shall be created | 
| Jackson_lv | 0:f6c99a47ce43 | 364 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 365 | * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists. | 
| Jackson_lv | 0:f6c99a47ce43 | 366 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 367 | * O_SYNC - Call sync() after each write. This flag should not be used with | 
| Jackson_lv | 0:f6c99a47ce43 | 368 | * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. | 
| Jackson_lv | 0:f6c99a47ce43 | 369 | * These functions do character at a time writes so sync() will be called | 
| Jackson_lv | 0:f6c99a47ce43 | 370 | * after each byte. | 
| Jackson_lv | 0:f6c99a47ce43 | 371 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 372 | * O_TRUNC - If the file exists and is a regular file, and the file is | 
| Jackson_lv | 0:f6c99a47ce43 | 373 | * successfully opened and is not read only, its length shall be truncated to 0. | 
| Jackson_lv | 0:f6c99a47ce43 | 374 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 375 | * \note Directory files must be opened read only. Write and truncation is | 
| Jackson_lv | 0:f6c99a47ce43 | 376 | * not allowed for directory files. | 
| Jackson_lv | 0:f6c99a47ce43 | 377 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 378 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 379 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 380 | * Reasons for failure include this SdFile is already open, \a difFile is not | 
| Jackson_lv | 0:f6c99a47ce43 | 381 | * a directory, \a fileName is invalid, the file does not exist | 
| Jackson_lv | 0:f6c99a47ce43 | 382 | * or can't be opened in the access mode specified by oflag. | 
| Jackson_lv | 0:f6c99a47ce43 | 383 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 384 | uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { | 
| Jackson_lv | 0:f6c99a47ce43 | 385 | uint8_t dname[11]; | 
| Jackson_lv | 0:f6c99a47ce43 | 386 | dir_t* p; | 
| Jackson_lv | 0:f6c99a47ce43 | 387 | |
| Jackson_lv | 0:f6c99a47ce43 | 388 | // error if already open | 
| Jackson_lv | 0:f6c99a47ce43 | 389 | if (isOpen())return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 390 | |
| Jackson_lv | 0:f6c99a47ce43 | 391 | if (!make83Name(fileName, dname)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 392 | vol_ = dirFile->vol_; | 
| Jackson_lv | 0:f6c99a47ce43 | 393 | dirFile->rewind(); | 
| Jackson_lv | 0:f6c99a47ce43 | 394 | |
| Jackson_lv | 0:f6c99a47ce43 | 395 | // bool for empty entry found | 
| Jackson_lv | 0:f6c99a47ce43 | 396 | uint8_t emptyFound = false; | 
| Jackson_lv | 0:f6c99a47ce43 | 397 | |
| Jackson_lv | 0:f6c99a47ce43 | 398 | // search for file | 
| Jackson_lv | 0:f6c99a47ce43 | 399 | while (dirFile->curPosition_ < dirFile->fileSize_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 400 | uint8_t index = 0XF & (dirFile->curPosition_ >> 5); | 
| Jackson_lv | 0:f6c99a47ce43 | 401 | p = dirFile->readDirCache(); | 
| Jackson_lv | 0:f6c99a47ce43 | 402 | if (p == NULL) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 403 | |
| Jackson_lv | 0:f6c99a47ce43 | 404 | if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { | 
| Jackson_lv | 0:f6c99a47ce43 | 405 | // remember first empty slot | 
| Jackson_lv | 0:f6c99a47ce43 | 406 | if (!emptyFound) { | 
| Jackson_lv | 0:f6c99a47ce43 | 407 | emptyFound = true; | 
| Jackson_lv | 0:f6c99a47ce43 | 408 | dirIndex_ = index; | 
| Jackson_lv | 0:f6c99a47ce43 | 409 | dirBlock_ = SdVolume::cacheBlockNumber_; | 
| Jackson_lv | 0:f6c99a47ce43 | 410 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 411 | // done if no entries follow | 
| Jackson_lv | 0:f6c99a47ce43 | 412 | if (p->name[0] == DIR_NAME_FREE) break; | 
| Jackson_lv | 0:f6c99a47ce43 | 413 | } else if (!memcmp(dname, p->name, 11)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 414 | // don't open existing file if O_CREAT and O_EXCL | 
| Jackson_lv | 0:f6c99a47ce43 | 415 | if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 416 | |
| Jackson_lv | 0:f6c99a47ce43 | 417 | // open found file | 
| Jackson_lv | 0:f6c99a47ce43 | 418 | return openCachedEntry(0XF & index, oflag); | 
| Jackson_lv | 0:f6c99a47ce43 | 419 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 420 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 421 | // only create file if O_CREAT and O_WRITE | 
| Jackson_lv | 0:f6c99a47ce43 | 422 | if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 423 | |
| Jackson_lv | 0:f6c99a47ce43 | 424 | // cache found slot or add cluster if end of file | 
| Jackson_lv | 0:f6c99a47ce43 | 425 | if (emptyFound) { | 
| Jackson_lv | 0:f6c99a47ce43 | 426 | p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); | 
| Jackson_lv | 0:f6c99a47ce43 | 427 | if (!p) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 428 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 429 | if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 430 | |
| Jackson_lv | 0:f6c99a47ce43 | 431 | // add and zero cluster for dirFile - first cluster is in cache for write | 
| Jackson_lv | 0:f6c99a47ce43 | 432 | if (!dirFile->addDirCluster()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 433 | |
| Jackson_lv | 0:f6c99a47ce43 | 434 | // use first entry in cluster | 
| Jackson_lv | 0:f6c99a47ce43 | 435 | dirIndex_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 436 | p = SdVolume::cacheBuffer_.dir; | 
| Jackson_lv | 0:f6c99a47ce43 | 437 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 438 | // initialize as empty file | 
| Jackson_lv | 0:f6c99a47ce43 | 439 | memset(p, 0, sizeof(dir_t)); | 
| Jackson_lv | 0:f6c99a47ce43 | 440 | memcpy(p->name, dname, 11); | 
| Jackson_lv | 0:f6c99a47ce43 | 441 | |
| Jackson_lv | 0:f6c99a47ce43 | 442 | // set timestamps | 
| Jackson_lv | 0:f6c99a47ce43 | 443 | if (dateTime_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 444 | // call user function | 
| Jackson_lv | 0:f6c99a47ce43 | 445 | dateTime_(&p->creationDate, &p->creationTime); | 
| Jackson_lv | 0:f6c99a47ce43 | 446 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 447 | // use default date/time | 
| Jackson_lv | 0:f6c99a47ce43 | 448 | p->creationDate = FAT_DEFAULT_DATE; | 
| Jackson_lv | 0:f6c99a47ce43 | 449 | p->creationTime = FAT_DEFAULT_TIME; | 
| Jackson_lv | 0:f6c99a47ce43 | 450 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 451 | p->lastAccessDate = p->creationDate; | 
| Jackson_lv | 0:f6c99a47ce43 | 452 | p->lastWriteDate = p->creationDate; | 
| Jackson_lv | 0:f6c99a47ce43 | 453 | p->lastWriteTime = p->creationTime; | 
| Jackson_lv | 0:f6c99a47ce43 | 454 | |
| Jackson_lv | 0:f6c99a47ce43 | 455 | // force write of entry to SD | 
| Jackson_lv | 0:f6c99a47ce43 | 456 | if (!SdVolume::cacheFlush()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 457 | |
| Jackson_lv | 0:f6c99a47ce43 | 458 | // open entry in cache | 
| Jackson_lv | 0:f6c99a47ce43 | 459 | return openCachedEntry(dirIndex_, oflag); | 
| Jackson_lv | 0:f6c99a47ce43 | 460 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 461 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 462 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 463 | * Open a file by index. | 
| Jackson_lv | 0:f6c99a47ce43 | 464 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 465 | * \param[in] dirFile An open SdFat instance for the directory. | 
| Jackson_lv | 0:f6c99a47ce43 | 466 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 467 | * \param[in] index The \a index of the directory entry for the file to be | 
| Jackson_lv | 0:f6c99a47ce43 | 468 | * opened. The value for \a index is (directory file position)/32. | 
| Jackson_lv | 0:f6c99a47ce43 | 469 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 470 | * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive | 
| Jackson_lv | 0:f6c99a47ce43 | 471 | * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. | 
| Jackson_lv | 0:f6c99a47ce43 | 472 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 473 | * See open() by fileName for definition of flags and return values. | 
| Jackson_lv | 0:f6c99a47ce43 | 474 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 475 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 476 | uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { | 
| Jackson_lv | 0:f6c99a47ce43 | 477 | // error if already open | 
| Jackson_lv | 0:f6c99a47ce43 | 478 | if (isOpen())return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 479 | |
| Jackson_lv | 0:f6c99a47ce43 | 480 | // don't open existing file if O_CREAT and O_EXCL - user call error | 
| Jackson_lv | 0:f6c99a47ce43 | 481 | if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 482 | |
| Jackson_lv | 0:f6c99a47ce43 | 483 | vol_ = dirFile->vol_; | 
| Jackson_lv | 0:f6c99a47ce43 | 484 | |
| Jackson_lv | 0:f6c99a47ce43 | 485 | // seek to location of entry | 
| Jackson_lv | 0:f6c99a47ce43 | 486 | if (!dirFile->seekSet(32 * index)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 487 | |
| Jackson_lv | 0:f6c99a47ce43 | 488 | // read entry into cache | 
| Jackson_lv | 0:f6c99a47ce43 | 489 | dir_t* p = dirFile->readDirCache(); | 
| Jackson_lv | 0:f6c99a47ce43 | 490 | if (p == NULL) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 491 | |
| Jackson_lv | 0:f6c99a47ce43 | 492 | // error if empty slot or '.' or '..' | 
| Jackson_lv | 0:f6c99a47ce43 | 493 | if (p->name[0] == DIR_NAME_FREE || | 
| Jackson_lv | 0:f6c99a47ce43 | 494 | p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { | 
| Jackson_lv | 0:f6c99a47ce43 | 495 | return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 496 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 497 | // open cached entry | 
| Jackson_lv | 0:f6c99a47ce43 | 498 | return openCachedEntry(index & 0XF, oflag); | 
| Jackson_lv | 0:f6c99a47ce43 | 499 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 500 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 501 | // open a cached directory entry. Assumes vol_ is initializes | 
| Jackson_lv | 0:f6c99a47ce43 | 502 | uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { | 
| Jackson_lv | 0:f6c99a47ce43 | 503 | // location of entry in cache | 
| Jackson_lv | 0:f6c99a47ce43 | 504 | dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex; | 
| Jackson_lv | 0:f6c99a47ce43 | 505 | |
| Jackson_lv | 0:f6c99a47ce43 | 506 | // write or truncate is an error for a directory or read-only file | 
| Jackson_lv | 0:f6c99a47ce43 | 507 | if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 508 | if (oflag & (O_WRITE | O_TRUNC)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 509 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 510 | // remember location of directory entry on SD | 
| Jackson_lv | 0:f6c99a47ce43 | 511 | dirIndex_ = dirIndex; | 
| Jackson_lv | 0:f6c99a47ce43 | 512 | dirBlock_ = SdVolume::cacheBlockNumber_; | 
| Jackson_lv | 0:f6c99a47ce43 | 513 | |
| Jackson_lv | 0:f6c99a47ce43 | 514 | // copy first cluster number for directory fields | 
| Jackson_lv | 0:f6c99a47ce43 | 515 | firstCluster_ = (uint32_t)p->firstClusterHigh << 16; | 
| Jackson_lv | 0:f6c99a47ce43 | 516 | firstCluster_ |= p->firstClusterLow; | 
| Jackson_lv | 0:f6c99a47ce43 | 517 | |
| Jackson_lv | 0:f6c99a47ce43 | 518 | // make sure it is a normal file or subdirectory | 
| Jackson_lv | 0:f6c99a47ce43 | 519 | if (DIR_IS_FILE(p)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 520 | fileSize_ = p->fileSize; | 
| Jackson_lv | 0:f6c99a47ce43 | 521 | type_ = FAT_FILE_TYPE_NORMAL; | 
| Jackson_lv | 0:f6c99a47ce43 | 522 | } else if (DIR_IS_SUBDIR(p)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 523 | if (!vol_->chainSize(firstCluster_, &fileSize_)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 524 | type_ = FAT_FILE_TYPE_SUBDIR; | 
| Jackson_lv | 0:f6c99a47ce43 | 525 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 526 | return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 527 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 528 | // save open flags for read/write | 
| Jackson_lv | 0:f6c99a47ce43 | 529 | flags_ = oflag & (O_ACCMODE | O_SYNC | O_APPEND); | 
| Jackson_lv | 0:f6c99a47ce43 | 530 | |
| Jackson_lv | 0:f6c99a47ce43 | 531 | // set to start of file | 
| Jackson_lv | 0:f6c99a47ce43 | 532 | curCluster_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 533 | curPosition_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 534 | |
| Jackson_lv | 0:f6c99a47ce43 | 535 | // truncate file to zero length if requested | 
| Jackson_lv | 0:f6c99a47ce43 | 536 | if (oflag & O_TRUNC) return truncate(0); | 
| Jackson_lv | 0:f6c99a47ce43 | 537 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 538 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 539 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 540 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 541 | * Open a volume's root directory. | 
| Jackson_lv | 0:f6c99a47ce43 | 542 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 543 | * \param[in] vol The FAT volume containing the root directory to be opened. | 
| Jackson_lv | 0:f6c99a47ce43 | 544 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 545 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 546 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 547 | * Reasons for failure include the FAT volume has not been initialized | 
| Jackson_lv | 0:f6c99a47ce43 | 548 | * or it a FAT12 volume. | 
| Jackson_lv | 0:f6c99a47ce43 | 549 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 550 | uint8_t SdFile::openRoot(SdVolume* vol) { | 
| Jackson_lv | 0:f6c99a47ce43 | 551 | // error if file is already open | 
| Jackson_lv | 0:f6c99a47ce43 | 552 | if (isOpen()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 553 | |
| Jackson_lv | 0:f6c99a47ce43 | 554 | if (vol->fatType() == 16) { | 
| Jackson_lv | 0:f6c99a47ce43 | 555 | type_ = FAT_FILE_TYPE_ROOT16; | 
| Jackson_lv | 0:f6c99a47ce43 | 556 | firstCluster_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 557 | fileSize_ = 32 * vol->rootDirEntryCount(); | 
| Jackson_lv | 0:f6c99a47ce43 | 558 | } else if (vol->fatType() == 32) { | 
| Jackson_lv | 0:f6c99a47ce43 | 559 | type_ = FAT_FILE_TYPE_ROOT32; | 
| Jackson_lv | 0:f6c99a47ce43 | 560 | firstCluster_ = vol->rootDirStart(); | 
| Jackson_lv | 0:f6c99a47ce43 | 561 | if (!vol->chainSize(firstCluster_, &fileSize_)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 562 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 563 | // volume is not initialized or FAT12 | 
| Jackson_lv | 0:f6c99a47ce43 | 564 | return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 565 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 566 | vol_ = vol; | 
| Jackson_lv | 0:f6c99a47ce43 | 567 | // read only | 
| Jackson_lv | 0:f6c99a47ce43 | 568 | flags_ = O_READ; | 
| Jackson_lv | 0:f6c99a47ce43 | 569 | |
| Jackson_lv | 0:f6c99a47ce43 | 570 | // set to start of file | 
| Jackson_lv | 0:f6c99a47ce43 | 571 | curCluster_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 572 | curPosition_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 573 | |
| Jackson_lv | 0:f6c99a47ce43 | 574 | // root has no directory entry | 
| Jackson_lv | 0:f6c99a47ce43 | 575 | dirBlock_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 576 | dirIndex_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 577 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 578 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 579 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 580 | /** %Print the name field of a directory entry in 8.3 format to Serial. | 
| Jackson_lv | 0:f6c99a47ce43 | 581 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 582 | * \param[in] dir The directory structure containing the name. | 
| Jackson_lv | 0:f6c99a47ce43 | 583 | * \param[in] width Blank fill name if length is less than \a width. | 
| Jackson_lv | 0:f6c99a47ce43 | 584 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 585 | void SdFile::printDirName(const dir_t& dir, uint8_t width) { | 
| Jackson_lv | 0:f6c99a47ce43 | 586 | uint8_t w = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 587 | for (uint8_t i = 0; i < 11; i++) { | 
| Jackson_lv | 0:f6c99a47ce43 | 588 | if (dir.name[i] == ' ')continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 589 | if (i == 8) { | 
| Jackson_lv | 0:f6c99a47ce43 | 590 | Serial.print('.'); | 
| Jackson_lv | 0:f6c99a47ce43 | 591 | w++; | 
| Jackson_lv | 0:f6c99a47ce43 | 592 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 593 | Serial.write(dir.name[i]); | 
| Jackson_lv | 0:f6c99a47ce43 | 594 | w++; | 
| Jackson_lv | 0:f6c99a47ce43 | 595 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 596 | if (DIR_IS_SUBDIR(&dir)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 597 | Serial.print('/'); | 
| Jackson_lv | 0:f6c99a47ce43 | 598 | w++; | 
| Jackson_lv | 0:f6c99a47ce43 | 599 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 600 | while (w < width) { | 
| Jackson_lv | 0:f6c99a47ce43 | 601 | Serial.print(' '); | 
| Jackson_lv | 0:f6c99a47ce43 | 602 | w++; | 
| Jackson_lv | 0:f6c99a47ce43 | 603 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 604 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 605 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 606 | /** %Print a directory date field to Serial. | 
| Jackson_lv | 0:f6c99a47ce43 | 607 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 608 | * Format is yyyy-mm-dd. | 
| Jackson_lv | 0:f6c99a47ce43 | 609 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 610 | * \param[in] fatDate The date field from a directory entry. | 
| Jackson_lv | 0:f6c99a47ce43 | 611 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 612 | void SdFile::printFatDate(uint16_t fatDate) { | 
| Jackson_lv | 0:f6c99a47ce43 | 613 | Serial.print(FAT_YEAR(fatDate)); | 
| Jackson_lv | 0:f6c99a47ce43 | 614 | Serial.print('-'); | 
| Jackson_lv | 0:f6c99a47ce43 | 615 | printTwoDigits(FAT_MONTH(fatDate)); | 
| Jackson_lv | 0:f6c99a47ce43 | 616 | Serial.print('-'); | 
| Jackson_lv | 0:f6c99a47ce43 | 617 | printTwoDigits(FAT_DAY(fatDate)); | 
| Jackson_lv | 0:f6c99a47ce43 | 618 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 619 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 620 | /** %Print a directory time field to Serial. | 
| Jackson_lv | 0:f6c99a47ce43 | 621 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 622 | * Format is hh:mm:ss. | 
| Jackson_lv | 0:f6c99a47ce43 | 623 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 624 | * \param[in] fatTime The time field from a directory entry. | 
| Jackson_lv | 0:f6c99a47ce43 | 625 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 626 | void SdFile::printFatTime(uint16_t fatTime) { | 
| Jackson_lv | 0:f6c99a47ce43 | 627 | printTwoDigits(FAT_HOUR(fatTime)); | 
| Jackson_lv | 0:f6c99a47ce43 | 628 | Serial.print(':'); | 
| Jackson_lv | 0:f6c99a47ce43 | 629 | printTwoDigits(FAT_MINUTE(fatTime)); | 
| Jackson_lv | 0:f6c99a47ce43 | 630 | Serial.print(':'); | 
| Jackson_lv | 0:f6c99a47ce43 | 631 | printTwoDigits(FAT_SECOND(fatTime)); | 
| Jackson_lv | 0:f6c99a47ce43 | 632 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 633 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 634 | /** %Print a value as two digits to Serial. | 
| Jackson_lv | 0:f6c99a47ce43 | 635 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 636 | * \param[in] v Value to be printed, 0 <= \a v <= 99 | 
| Jackson_lv | 0:f6c99a47ce43 | 637 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 638 | void SdFile::printTwoDigits(uint8_t v) { | 
| Jackson_lv | 0:f6c99a47ce43 | 639 | char str[3]; | 
| Jackson_lv | 0:f6c99a47ce43 | 640 | str[0] = '0' + v/10; | 
| Jackson_lv | 0:f6c99a47ce43 | 641 | str[1] = '0' + v % 10; | 
| Jackson_lv | 0:f6c99a47ce43 | 642 | str[2] = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 643 | Serial.print(str); | 
| Jackson_lv | 0:f6c99a47ce43 | 644 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 645 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 646 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 647 | * Read data from a file starting at the current position. | 
| Jackson_lv | 0:f6c99a47ce43 | 648 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 649 | * \param[out] buf Pointer to the location that will receive the data. | 
| Jackson_lv | 0:f6c99a47ce43 | 650 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 651 | * \param[in] nbyte Maximum number of bytes to read. | 
| Jackson_lv | 0:f6c99a47ce43 | 652 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 653 | * \return For success read() returns the number of bytes read. | 
| Jackson_lv | 0:f6c99a47ce43 | 654 | * A value less than \a nbyte, including zero, will be returned | 
| Jackson_lv | 0:f6c99a47ce43 | 655 | * if end of file is reached. | 
| Jackson_lv | 0:f6c99a47ce43 | 656 | * If an error occurs, read() returns -1. Possible errors include | 
| Jackson_lv | 0:f6c99a47ce43 | 657 | * read() called before a file has been opened, corrupt file system | 
| Jackson_lv | 0:f6c99a47ce43 | 658 | * or an I/O error occurred. | 
| Jackson_lv | 0:f6c99a47ce43 | 659 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 660 | int16_t SdFile::read(void* buf, uint16_t nbyte) { | 
| Jackson_lv | 0:f6c99a47ce43 | 661 | uint8_t* dst = reinterpret_cast<uint8_t*>(buf); | 
| Jackson_lv | 0:f6c99a47ce43 | 662 | |
| Jackson_lv | 0:f6c99a47ce43 | 663 | // error if not open or write only | 
| Jackson_lv | 0:f6c99a47ce43 | 664 | if (!isOpen() || !(flags_ & O_READ)) return -1; | 
| Jackson_lv | 0:f6c99a47ce43 | 665 | |
| Jackson_lv | 0:f6c99a47ce43 | 666 | // max bytes left in file | 
| Jackson_lv | 0:f6c99a47ce43 | 667 | if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; | 
| Jackson_lv | 0:f6c99a47ce43 | 668 | |
| Jackson_lv | 0:f6c99a47ce43 | 669 | // amount left to read | 
| Jackson_lv | 0:f6c99a47ce43 | 670 | uint16_t toRead = nbyte; | 
| Jackson_lv | 0:f6c99a47ce43 | 671 | while (toRead > 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 672 | uint32_t block; // raw device block number | 
| Jackson_lv | 0:f6c99a47ce43 | 673 | uint16_t offset = curPosition_ & 0X1FF; // offset in block | 
| Jackson_lv | 0:f6c99a47ce43 | 674 | if (type_ == FAT_FILE_TYPE_ROOT16) { | 
| Jackson_lv | 0:f6c99a47ce43 | 675 | block = vol_->rootDirStart() + (curPosition_ >> 9); | 
| Jackson_lv | 0:f6c99a47ce43 | 676 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 677 | uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); | 
| Jackson_lv | 0:f6c99a47ce43 | 678 | if (offset == 0 && blockOfCluster == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 679 | // start of new cluster | 
| Jackson_lv | 0:f6c99a47ce43 | 680 | if (curPosition_ == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 681 | // use first cluster in file | 
| Jackson_lv | 0:f6c99a47ce43 | 682 | curCluster_ = firstCluster_; | 
| Jackson_lv | 0:f6c99a47ce43 | 683 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 684 | // get next cluster from FAT | 
| Jackson_lv | 0:f6c99a47ce43 | 685 | if (!vol_->fatGet(curCluster_, &curCluster_)) return -1; | 
| Jackson_lv | 0:f6c99a47ce43 | 686 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 687 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 688 | block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; | 
| Jackson_lv | 0:f6c99a47ce43 | 689 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 690 | uint16_t n = toRead; | 
| Jackson_lv | 0:f6c99a47ce43 | 691 | |
| Jackson_lv | 0:f6c99a47ce43 | 692 | // amount to be read from current block | 
| Jackson_lv | 0:f6c99a47ce43 | 693 | if (n > (512 - offset)) n = 512 - offset; | 
| Jackson_lv | 0:f6c99a47ce43 | 694 | |
| Jackson_lv | 0:f6c99a47ce43 | 695 | // no buffering needed if n == 512 or user requests no buffering | 
| Jackson_lv | 0:f6c99a47ce43 | 696 | if ((unbufferedRead() || n == 512) && | 
| Jackson_lv | 0:f6c99a47ce43 | 697 | block != SdVolume::cacheBlockNumber_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 698 | if (!vol_->readData(block, offset, n, dst)) return -1; | 
| Jackson_lv | 0:f6c99a47ce43 | 699 | dst += n; | 
| Jackson_lv | 0:f6c99a47ce43 | 700 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 701 | // read block to cache and copy data to caller | 
| Jackson_lv | 0:f6c99a47ce43 | 702 | if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1; | 
| Jackson_lv | 0:f6c99a47ce43 | 703 | uint8_t* src = SdVolume::cacheBuffer_.data + offset; | 
| Jackson_lv | 0:f6c99a47ce43 | 704 | uint8_t* end = src + n; | 
| Jackson_lv | 0:f6c99a47ce43 | 705 | while (src != end) *dst++ = *src++; | 
| Jackson_lv | 0:f6c99a47ce43 | 706 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 707 | curPosition_ += n; | 
| Jackson_lv | 0:f6c99a47ce43 | 708 | toRead -= n; | 
| Jackson_lv | 0:f6c99a47ce43 | 709 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 710 | return nbyte; | 
| Jackson_lv | 0:f6c99a47ce43 | 711 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 712 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 713 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 714 | * Read the next directory entry from a directory file. | 
| Jackson_lv | 0:f6c99a47ce43 | 715 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 716 | * \param[out] dir The dir_t struct that will receive the data. | 
| Jackson_lv | 0:f6c99a47ce43 | 717 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 718 | * \return For success readDir() returns the number of bytes read. | 
| Jackson_lv | 0:f6c99a47ce43 | 719 | * A value of zero will be returned if end of file is reached. | 
| Jackson_lv | 0:f6c99a47ce43 | 720 | * If an error occurs, readDir() returns -1. Possible errors include | 
| Jackson_lv | 0:f6c99a47ce43 | 721 | * readDir() called before a directory has been opened, this is not | 
| Jackson_lv | 0:f6c99a47ce43 | 722 | * a directory file or an I/O error occurred. | 
| Jackson_lv | 0:f6c99a47ce43 | 723 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 724 | int8_t SdFile::readDir(dir_t* dir) { | 
| Jackson_lv | 0:f6c99a47ce43 | 725 | int8_t n; | 
| Jackson_lv | 0:f6c99a47ce43 | 726 | // if not a directory file or miss-positioned return an error | 
| Jackson_lv | 0:f6c99a47ce43 | 727 | if (!isDir() || (0X1F & curPosition_)) return -1; | 
| Jackson_lv | 0:f6c99a47ce43 | 728 | |
| Jackson_lv | 0:f6c99a47ce43 | 729 | while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 730 | // last entry if DIR_NAME_FREE | 
| Jackson_lv | 0:f6c99a47ce43 | 731 | if (dir->name[0] == DIR_NAME_FREE) break; | 
| Jackson_lv | 0:f6c99a47ce43 | 732 | // skip empty entries and entry for . and .. | 
| Jackson_lv | 0:f6c99a47ce43 | 733 | if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 734 | // return if normal file or subdirectory | 
| Jackson_lv | 0:f6c99a47ce43 | 735 | if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; | 
| Jackson_lv | 0:f6c99a47ce43 | 736 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 737 | // error, end of file, or past last entry | 
| Jackson_lv | 0:f6c99a47ce43 | 738 | return n < 0 ? -1 : 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 739 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 740 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 741 | // Read next directory entry into the cache | 
| Jackson_lv | 0:f6c99a47ce43 | 742 | // Assumes file is correctly positioned | 
| Jackson_lv | 0:f6c99a47ce43 | 743 | dir_t* SdFile::readDirCache(void) { | 
| Jackson_lv | 0:f6c99a47ce43 | 744 | // error if not directory | 
| Jackson_lv | 0:f6c99a47ce43 | 745 | if (!isDir()) return NULL; | 
| Jackson_lv | 0:f6c99a47ce43 | 746 | |
| Jackson_lv | 0:f6c99a47ce43 | 747 | // index of entry in cache | 
| Jackson_lv | 0:f6c99a47ce43 | 748 | uint8_t i = (curPosition_ >> 5) & 0XF; | 
| Jackson_lv | 0:f6c99a47ce43 | 749 | |
| Jackson_lv | 0:f6c99a47ce43 | 750 | // use read to locate and cache block | 
| Jackson_lv | 0:f6c99a47ce43 | 751 | if (read() < 0) return NULL; | 
| Jackson_lv | 0:f6c99a47ce43 | 752 | |
| Jackson_lv | 0:f6c99a47ce43 | 753 | // advance to next entry | 
| Jackson_lv | 0:f6c99a47ce43 | 754 | curPosition_ += 31; | 
| Jackson_lv | 0:f6c99a47ce43 | 755 | |
| Jackson_lv | 0:f6c99a47ce43 | 756 | // return pointer to entry | 
| Jackson_lv | 0:f6c99a47ce43 | 757 | return (SdVolume::cacheBuffer_.dir + i); | 
| Jackson_lv | 0:f6c99a47ce43 | 758 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 759 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 760 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 761 | * Remove a file. | 
| Jackson_lv | 0:f6c99a47ce43 | 762 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 763 | * The directory entry and all data for the file are deleted. | 
| Jackson_lv | 0:f6c99a47ce43 | 764 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 765 | * \note This function should not be used to delete the 8.3 version of a | 
| Jackson_lv | 0:f6c99a47ce43 | 766 | * file that has a long name. For example if a file has the long name | 
| Jackson_lv | 0:f6c99a47ce43 | 767 | * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". | 
| Jackson_lv | 0:f6c99a47ce43 | 768 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 769 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 770 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 771 | * Reasons for failure include the file read-only, is a directory, | 
| Jackson_lv | 0:f6c99a47ce43 | 772 | * or an I/O error occurred. | 
| Jackson_lv | 0:f6c99a47ce43 | 773 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 774 | uint8_t SdFile::remove(void) { | 
| Jackson_lv | 0:f6c99a47ce43 | 775 | // free any clusters - will fail if read-only or directory | 
| Jackson_lv | 0:f6c99a47ce43 | 776 | if (!truncate(0)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 777 | |
| Jackson_lv | 0:f6c99a47ce43 | 778 | // cache directory entry | 
| Jackson_lv | 0:f6c99a47ce43 | 779 | dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); | 
| Jackson_lv | 0:f6c99a47ce43 | 780 | if (!d) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 781 | |
| Jackson_lv | 0:f6c99a47ce43 | 782 | // mark entry deleted | 
| Jackson_lv | 0:f6c99a47ce43 | 783 | d->name[0] = DIR_NAME_DELETED; | 
| Jackson_lv | 0:f6c99a47ce43 | 784 | |
| Jackson_lv | 0:f6c99a47ce43 | 785 | // set this SdFile closed | 
| Jackson_lv | 0:f6c99a47ce43 | 786 | type_ = FAT_FILE_TYPE_CLOSED; | 
| Jackson_lv | 0:f6c99a47ce43 | 787 | |
| Jackson_lv | 0:f6c99a47ce43 | 788 | // write entry to SD | 
| Jackson_lv | 0:f6c99a47ce43 | 789 | return SdVolume::cacheFlush(); | 
| Jackson_lv | 0:f6c99a47ce43 | 790 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 791 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 792 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 793 | * Remove a file. | 
| Jackson_lv | 0:f6c99a47ce43 | 794 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 795 | * The directory entry and all data for the file are deleted. | 
| Jackson_lv | 0:f6c99a47ce43 | 796 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 797 | * \param[in] dirFile The directory that contains the file. | 
| Jackson_lv | 0:f6c99a47ce43 | 798 | * \param[in] fileName The name of the file to be removed. | 
| Jackson_lv | 0:f6c99a47ce43 | 799 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 800 | * \note This function should not be used to delete the 8.3 version of a | 
| Jackson_lv | 0:f6c99a47ce43 | 801 | * file that has a long name. For example if a file has the long name | 
| Jackson_lv | 0:f6c99a47ce43 | 802 | * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". | 
| Jackson_lv | 0:f6c99a47ce43 | 803 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 804 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 805 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 806 | * Reasons for failure include the file is a directory, is read only, | 
| Jackson_lv | 0:f6c99a47ce43 | 807 | * \a dirFile is not a directory, \a fileName is not found | 
| Jackson_lv | 0:f6c99a47ce43 | 808 | * or an I/O error occurred. | 
| Jackson_lv | 0:f6c99a47ce43 | 809 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 810 | uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) { | 
| Jackson_lv | 0:f6c99a47ce43 | 811 | SdFile file; | 
| Jackson_lv | 0:f6c99a47ce43 | 812 | if (!file.open(dirFile, fileName, O_WRITE)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 813 | return file.remove(); | 
| Jackson_lv | 0:f6c99a47ce43 | 814 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 815 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 816 | /** Remove a directory file. | 
| Jackson_lv | 0:f6c99a47ce43 | 817 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 818 | * The directory file will be removed only if it is empty and is not the | 
| Jackson_lv | 0:f6c99a47ce43 | 819 | * root directory. rmDir() follows DOS and Windows and ignores the | 
| Jackson_lv | 0:f6c99a47ce43 | 820 | * read-only attribute for the directory. | 
| Jackson_lv | 0:f6c99a47ce43 | 821 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 822 | * \note This function should not be used to delete the 8.3 version of a | 
| Jackson_lv | 0:f6c99a47ce43 | 823 | * directory that has a long name. For example if a directory has the | 
| Jackson_lv | 0:f6c99a47ce43 | 824 | * long name "New folder" you should not delete the 8.3 name "NEWFOL~1". | 
| Jackson_lv | 0:f6c99a47ce43 | 825 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 826 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 827 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 828 | * Reasons for failure include the file is not a directory, is the root | 
| Jackson_lv | 0:f6c99a47ce43 | 829 | * directory, is not empty, or an I/O error occurred. | 
| Jackson_lv | 0:f6c99a47ce43 | 830 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 831 | uint8_t SdFile::rmDir(void) { | 
| Jackson_lv | 0:f6c99a47ce43 | 832 | // must be open subdirectory | 
| Jackson_lv | 0:f6c99a47ce43 | 833 | if (!isSubDir()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 834 | |
| Jackson_lv | 0:f6c99a47ce43 | 835 | rewind(); | 
| Jackson_lv | 0:f6c99a47ce43 | 836 | |
| Jackson_lv | 0:f6c99a47ce43 | 837 | // make sure directory is empty | 
| Jackson_lv | 0:f6c99a47ce43 | 838 | while (curPosition_ < fileSize_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 839 | dir_t* p = readDirCache(); | 
| Jackson_lv | 0:f6c99a47ce43 | 840 | if (p == NULL) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 841 | // done if past last used entry | 
| Jackson_lv | 0:f6c99a47ce43 | 842 | if (p->name[0] == DIR_NAME_FREE) break; | 
| Jackson_lv | 0:f6c99a47ce43 | 843 | // skip empty slot or '.' or '..' | 
| Jackson_lv | 0:f6c99a47ce43 | 844 | if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 845 | // error not empty | 
| Jackson_lv | 0:f6c99a47ce43 | 846 | if (DIR_IS_FILE_OR_SUBDIR(p)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 847 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 848 | // convert empty directory to normal file for remove | 
| Jackson_lv | 0:f6c99a47ce43 | 849 | type_ = FAT_FILE_TYPE_NORMAL; | 
| Jackson_lv | 0:f6c99a47ce43 | 850 | flags_ |= O_WRITE; | 
| Jackson_lv | 0:f6c99a47ce43 | 851 | return remove(); | 
| Jackson_lv | 0:f6c99a47ce43 | 852 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 853 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 854 | /** Recursively delete a directory and all contained files. | 
| Jackson_lv | 0:f6c99a47ce43 | 855 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 856 | * This is like the Unix/Linux 'rm -rf *' if called with the root directory | 
| Jackson_lv | 0:f6c99a47ce43 | 857 | * hence the name. | 
| Jackson_lv | 0:f6c99a47ce43 | 858 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 859 | * Warning - This will remove all contents of the directory including | 
| Jackson_lv | 0:f6c99a47ce43 | 860 | * subdirectories. The directory will then be removed if it is not root. | 
| Jackson_lv | 0:f6c99a47ce43 | 861 | * The read-only attribute for files will be ignored. | 
| Jackson_lv | 0:f6c99a47ce43 | 862 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 863 | * \note This function should not be used to delete the 8.3 version of | 
| Jackson_lv | 0:f6c99a47ce43 | 864 | * a directory that has a long name. See remove() and rmDir(). | 
| Jackson_lv | 0:f6c99a47ce43 | 865 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 866 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 867 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 868 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 869 | uint8_t SdFile::rmRfStar(void) { | 
| Jackson_lv | 0:f6c99a47ce43 | 870 | rewind(); | 
| Jackson_lv | 0:f6c99a47ce43 | 871 | while (curPosition_ < fileSize_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 872 | SdFile f; | 
| Jackson_lv | 0:f6c99a47ce43 | 873 | |
| Jackson_lv | 0:f6c99a47ce43 | 874 | // remember position | 
| Jackson_lv | 0:f6c99a47ce43 | 875 | uint16_t index = curPosition_/32; | 
| Jackson_lv | 0:f6c99a47ce43 | 876 | |
| Jackson_lv | 0:f6c99a47ce43 | 877 | dir_t* p = readDirCache(); | 
| Jackson_lv | 0:f6c99a47ce43 | 878 | if (!p) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 879 | |
| Jackson_lv | 0:f6c99a47ce43 | 880 | // done if past last entry | 
| Jackson_lv | 0:f6c99a47ce43 | 881 | if (p->name[0] == DIR_NAME_FREE) break; | 
| Jackson_lv | 0:f6c99a47ce43 | 882 | |
| Jackson_lv | 0:f6c99a47ce43 | 883 | // skip empty slot or '.' or '..' | 
| Jackson_lv | 0:f6c99a47ce43 | 884 | if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 885 | |
| Jackson_lv | 0:f6c99a47ce43 | 886 | // skip if part of long file name or volume label in root | 
| Jackson_lv | 0:f6c99a47ce43 | 887 | if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; | 
| Jackson_lv | 0:f6c99a47ce43 | 888 | |
| Jackson_lv | 0:f6c99a47ce43 | 889 | if (!f.open(this, index, O_READ)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 890 | if (f.isSubDir()) { | 
| Jackson_lv | 0:f6c99a47ce43 | 891 | // recursively delete | 
| Jackson_lv | 0:f6c99a47ce43 | 892 | if (!f.rmRfStar()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 893 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 894 | // ignore read-only | 
| Jackson_lv | 0:f6c99a47ce43 | 895 | f.flags_ |= O_WRITE; | 
| Jackson_lv | 0:f6c99a47ce43 | 896 | if (!f.remove()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 897 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 898 | // position to next entry if required | 
| Jackson_lv | 0:f6c99a47ce43 | 899 | if (curPosition_ != (32*(index + 1))) { | 
| Jackson_lv | 0:f6c99a47ce43 | 900 | if (!seekSet(32*(index + 1))) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 901 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 902 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 903 | // don't try to delete root | 
| Jackson_lv | 0:f6c99a47ce43 | 904 | if (isRoot()) return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 905 | return rmDir(); | 
| Jackson_lv | 0:f6c99a47ce43 | 906 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 907 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 908 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 909 | * Sets a file's position. | 
| Jackson_lv | 0:f6c99a47ce43 | 910 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 911 | * \param[in] pos The new position in bytes from the beginning of the file. | 
| Jackson_lv | 0:f6c99a47ce43 | 912 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 913 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 914 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 915 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 916 | uint8_t SdFile::seekSet(uint32_t pos) { | 
| Jackson_lv | 0:f6c99a47ce43 | 917 | // error if file not open or seek past end of file | 
| Jackson_lv | 0:f6c99a47ce43 | 918 | if (!isOpen() || pos > fileSize_) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 919 | |
| Jackson_lv | 0:f6c99a47ce43 | 920 | if (type_ == FAT_FILE_TYPE_ROOT16) { | 
| Jackson_lv | 0:f6c99a47ce43 | 921 | curPosition_ = pos; | 
| Jackson_lv | 0:f6c99a47ce43 | 922 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 923 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 924 | if (pos == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 925 | // set position to start of file | 
| Jackson_lv | 0:f6c99a47ce43 | 926 | curCluster_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 927 | curPosition_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 928 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 929 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 930 | // calculate cluster index for cur and new position | 
| Jackson_lv | 0:f6c99a47ce43 | 931 | uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); | 
| Jackson_lv | 0:f6c99a47ce43 | 932 | uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); | 
| Jackson_lv | 0:f6c99a47ce43 | 933 | |
| Jackson_lv | 0:f6c99a47ce43 | 934 | if (nNew < nCur || curPosition_ == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 935 | // must follow chain from first cluster | 
| Jackson_lv | 0:f6c99a47ce43 | 936 | curCluster_ = firstCluster_; | 
| Jackson_lv | 0:f6c99a47ce43 | 937 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 938 | // advance from curPosition | 
| Jackson_lv | 0:f6c99a47ce43 | 939 | nNew -= nCur; | 
| Jackson_lv | 0:f6c99a47ce43 | 940 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 941 | while (nNew--) { | 
| Jackson_lv | 0:f6c99a47ce43 | 942 | if (!vol_->fatGet(curCluster_, &curCluster_)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 943 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 944 | curPosition_ = pos; | 
| Jackson_lv | 0:f6c99a47ce43 | 945 | return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 946 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 947 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 948 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 949 | * The sync() call causes all modified data and directory fields | 
| Jackson_lv | 0:f6c99a47ce43 | 950 | * to be written to the storage device. | 
| Jackson_lv | 0:f6c99a47ce43 | 951 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 952 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 953 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 954 | * Reasons for failure include a call to sync() before a file has been | 
| Jackson_lv | 0:f6c99a47ce43 | 955 | * opened or an I/O error. | 
| Jackson_lv | 0:f6c99a47ce43 | 956 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 957 | uint8_t SdFile::sync(void) { | 
| Jackson_lv | 0:f6c99a47ce43 | 958 | // only allow open files and directories | 
| Jackson_lv | 0:f6c99a47ce43 | 959 | if (!isOpen()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 960 | |
| Jackson_lv | 0:f6c99a47ce43 | 961 | if (flags_ & F_FILE_DIR_DIRTY) { | 
| Jackson_lv | 0:f6c99a47ce43 | 962 | dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); | 
| Jackson_lv | 0:f6c99a47ce43 | 963 | if (!d) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 964 | |
| Jackson_lv | 0:f6c99a47ce43 | 965 | // do not set filesize for dir files | 
| Jackson_lv | 0:f6c99a47ce43 | 966 | if (!isDir()) d->fileSize = fileSize_; | 
| Jackson_lv | 0:f6c99a47ce43 | 967 | |
| Jackson_lv | 0:f6c99a47ce43 | 968 | // update first cluster fields | 
| Jackson_lv | 0:f6c99a47ce43 | 969 | d->firstClusterLow = firstCluster_ & 0XFFFF; | 
| Jackson_lv | 0:f6c99a47ce43 | 970 | d->firstClusterHigh = firstCluster_ >> 16; | 
| Jackson_lv | 0:f6c99a47ce43 | 971 | |
| Jackson_lv | 0:f6c99a47ce43 | 972 | // set modify time if user supplied a callback date/time function | 
| Jackson_lv | 0:f6c99a47ce43 | 973 | if (dateTime_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 974 | dateTime_(&d->lastWriteDate, &d->lastWriteTime); | 
| Jackson_lv | 0:f6c99a47ce43 | 975 | d->lastAccessDate = d->lastWriteDate; | 
| Jackson_lv | 0:f6c99a47ce43 | 976 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 977 | // clear directory dirty | 
| Jackson_lv | 0:f6c99a47ce43 | 978 | flags_ &= ~F_FILE_DIR_DIRTY; | 
| Jackson_lv | 0:f6c99a47ce43 | 979 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 980 | return SdVolume::cacheFlush(); | 
| Jackson_lv | 0:f6c99a47ce43 | 981 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 982 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 983 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 984 | * Set a file's timestamps in its directory entry. | 
| Jackson_lv | 0:f6c99a47ce43 | 985 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 986 | * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive | 
| Jackson_lv | 0:f6c99a47ce43 | 987 | * OR of flags from the following list | 
| Jackson_lv | 0:f6c99a47ce43 | 988 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 989 | * T_ACCESS - Set the file's last access date. | 
| Jackson_lv | 0:f6c99a47ce43 | 990 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 991 | * T_CREATE - Set the file's creation date and time. | 
| Jackson_lv | 0:f6c99a47ce43 | 992 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 993 | * T_WRITE - Set the file's last write/modification date and time. | 
| Jackson_lv | 0:f6c99a47ce43 | 994 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 995 | * \param[in] year Valid range 1980 - 2107 inclusive. | 
| Jackson_lv | 0:f6c99a47ce43 | 996 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 997 | * \param[in] month Valid range 1 - 12 inclusive. | 
| Jackson_lv | 0:f6c99a47ce43 | 998 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 999 | * \param[in] day Valid range 1 - 31 inclusive. | 
| Jackson_lv | 0:f6c99a47ce43 | 1000 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1001 | * \param[in] hour Valid range 0 - 23 inclusive. | 
| Jackson_lv | 0:f6c99a47ce43 | 1002 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1003 | * \param[in] minute Valid range 0 - 59 inclusive. | 
| Jackson_lv | 0:f6c99a47ce43 | 1004 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1005 | * \param[in] second Valid range 0 - 59 inclusive | 
| Jackson_lv | 0:f6c99a47ce43 | 1006 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1007 | * \note It is possible to set an invalid date since there is no check for | 
| Jackson_lv | 0:f6c99a47ce43 | 1008 | * the number of days in a month. | 
| Jackson_lv | 0:f6c99a47ce43 | 1009 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1010 | * \note | 
| Jackson_lv | 0:f6c99a47ce43 | 1011 | * Modify and access timestamps may be overwritten if a date time callback | 
| Jackson_lv | 0:f6c99a47ce43 | 1012 | * function has been set by dateTimeCallback(). | 
| Jackson_lv | 0:f6c99a47ce43 | 1013 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1014 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 1015 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 1016 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 1017 | uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, | 
| Jackson_lv | 0:f6c99a47ce43 | 1018 | uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1019 | if (!isOpen() | 
| Jackson_lv | 0:f6c99a47ce43 | 1020 | || year < 1980 | 
| Jackson_lv | 0:f6c99a47ce43 | 1021 | || year > 2107 | 
| Jackson_lv | 0:f6c99a47ce43 | 1022 | || month < 1 | 
| Jackson_lv | 0:f6c99a47ce43 | 1023 | || month > 12 | 
| Jackson_lv | 0:f6c99a47ce43 | 1024 | || day < 1 | 
| Jackson_lv | 0:f6c99a47ce43 | 1025 | || day > 31 | 
| Jackson_lv | 0:f6c99a47ce43 | 1026 | || hour > 23 | 
| Jackson_lv | 0:f6c99a47ce43 | 1027 | || minute > 59 | 
| Jackson_lv | 0:f6c99a47ce43 | 1028 | || second > 59) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1029 | return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1030 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1031 | dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); | 
| Jackson_lv | 0:f6c99a47ce43 | 1032 | if (!d) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1033 | |
| Jackson_lv | 0:f6c99a47ce43 | 1034 | uint16_t dirDate = FAT_DATE(year, month, day); | 
| Jackson_lv | 0:f6c99a47ce43 | 1035 | uint16_t dirTime = FAT_TIME(hour, minute, second); | 
| Jackson_lv | 0:f6c99a47ce43 | 1036 | if (flags & T_ACCESS) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1037 | d->lastAccessDate = dirDate; | 
| Jackson_lv | 0:f6c99a47ce43 | 1038 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1039 | if (flags & T_CREATE) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1040 | d->creationDate = dirDate; | 
| Jackson_lv | 0:f6c99a47ce43 | 1041 | d->creationTime = dirTime; | 
| Jackson_lv | 0:f6c99a47ce43 | 1042 | // seems to be units of 1/100 second not 1/10 as Microsoft states | 
| Jackson_lv | 0:f6c99a47ce43 | 1043 | d->creationTimeTenths = second & 1 ? 100 : 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 1044 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1045 | if (flags & T_WRITE) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1046 | d->lastWriteDate = dirDate; | 
| Jackson_lv | 0:f6c99a47ce43 | 1047 | d->lastWriteTime = dirTime; | 
| Jackson_lv | 0:f6c99a47ce43 | 1048 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1049 | SdVolume::cacheSetDirty(); | 
| Jackson_lv | 0:f6c99a47ce43 | 1050 | return sync(); | 
| Jackson_lv | 0:f6c99a47ce43 | 1051 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1052 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 1053 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 1054 | * Truncate a file to a specified length. The current file position | 
| Jackson_lv | 0:f6c99a47ce43 | 1055 | * will be maintained if it is less than or equal to \a length otherwise | 
| Jackson_lv | 0:f6c99a47ce43 | 1056 | * it will be set to end of file. | 
| Jackson_lv | 0:f6c99a47ce43 | 1057 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1058 | * \param[in] length The desired length for the file. | 
| Jackson_lv | 0:f6c99a47ce43 | 1059 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1060 | * \return The value one, true, is returned for success and | 
| Jackson_lv | 0:f6c99a47ce43 | 1061 | * the value zero, false, is returned for failure. | 
| Jackson_lv | 0:f6c99a47ce43 | 1062 | * Reasons for failure include file is read only, file is a directory, | 
| Jackson_lv | 0:f6c99a47ce43 | 1063 | * \a length is greater than the current file size or an I/O error occurs. | 
| Jackson_lv | 0:f6c99a47ce43 | 1064 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 1065 | uint8_t SdFile::truncate(uint32_t length) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1066 | // error if not a normal file or read-only | 
| Jackson_lv | 0:f6c99a47ce43 | 1067 | if (!isFile() || !(flags_ & O_WRITE)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1068 | |
| Jackson_lv | 0:f6c99a47ce43 | 1069 | // error if length is greater than current size | 
| Jackson_lv | 0:f6c99a47ce43 | 1070 | if (length > fileSize_) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1071 | |
| Jackson_lv | 0:f6c99a47ce43 | 1072 | // fileSize and length are zero - nothing to do | 
| Jackson_lv | 0:f6c99a47ce43 | 1073 | if (fileSize_ == 0) return true; | 
| Jackson_lv | 0:f6c99a47ce43 | 1074 | |
| Jackson_lv | 0:f6c99a47ce43 | 1075 | // remember position for seek after truncation | 
| Jackson_lv | 0:f6c99a47ce43 | 1076 | uint32_t newPos = curPosition_ > length ? length : curPosition_; | 
| Jackson_lv | 0:f6c99a47ce43 | 1077 | |
| Jackson_lv | 0:f6c99a47ce43 | 1078 | // position to last cluster in truncated file | 
| Jackson_lv | 0:f6c99a47ce43 | 1079 | if (!seekSet(length)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1080 | |
| Jackson_lv | 0:f6c99a47ce43 | 1081 | if (length == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1082 | // free all clusters | 
| Jackson_lv | 0:f6c99a47ce43 | 1083 | if (!vol_->freeChain(firstCluster_)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1084 | firstCluster_ = 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 1085 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 1086 | uint32_t toFree; | 
| Jackson_lv | 0:f6c99a47ce43 | 1087 | if (!vol_->fatGet(curCluster_, &toFree)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1088 | |
| Jackson_lv | 0:f6c99a47ce43 | 1089 | if (!vol_->isEOC(toFree)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1090 | // free extra clusters | 
| Jackson_lv | 0:f6c99a47ce43 | 1091 | if (!vol_->freeChain(toFree)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1092 | |
| Jackson_lv | 0:f6c99a47ce43 | 1093 | // current cluster is end of chain | 
| Jackson_lv | 0:f6c99a47ce43 | 1094 | if (!vol_->fatPutEOC(curCluster_)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1095 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1096 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1097 | fileSize_ = length; | 
| Jackson_lv | 0:f6c99a47ce43 | 1098 | |
| Jackson_lv | 0:f6c99a47ce43 | 1099 | // need to update directory entry | 
| Jackson_lv | 0:f6c99a47ce43 | 1100 | flags_ |= F_FILE_DIR_DIRTY; | 
| Jackson_lv | 0:f6c99a47ce43 | 1101 | |
| Jackson_lv | 0:f6c99a47ce43 | 1102 | if (!sync()) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1103 | |
| Jackson_lv | 0:f6c99a47ce43 | 1104 | // set file to correct position | 
| Jackson_lv | 0:f6c99a47ce43 | 1105 | return seekSet(newPos); | 
| Jackson_lv | 0:f6c99a47ce43 | 1106 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1107 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 1108 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 1109 | * Write data to an open file. | 
| Jackson_lv | 0:f6c99a47ce43 | 1110 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1111 | * \note Data is moved to the cache but may not be written to the | 
| Jackson_lv | 0:f6c99a47ce43 | 1112 | * storage device until sync() is called. | 
| Jackson_lv | 0:f6c99a47ce43 | 1113 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1114 | * \param[in] buf Pointer to the location of the data to be written. | 
| Jackson_lv | 0:f6c99a47ce43 | 1115 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1116 | * \param[in] nbyte Number of bytes to write. | 
| Jackson_lv | 0:f6c99a47ce43 | 1117 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1118 | * \return For success write() returns the number of bytes written, always | 
| Jackson_lv | 0:f6c99a47ce43 | 1119 | * \a nbyte. If an error occurs, write() returns -1. Possible errors | 
| Jackson_lv | 0:f6c99a47ce43 | 1120 | * include write() is called before a file has been opened, write is called | 
| Jackson_lv | 0:f6c99a47ce43 | 1121 | * for a read-only file, device is full, a corrupt file system or an I/O error. | 
| Jackson_lv | 0:f6c99a47ce43 | 1122 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1123 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 1124 | size_t SdFile::write(const void* buf, uint16_t nbyte) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1125 | // convert void* to uint8_t* - must be before goto statements | 
| Jackson_lv | 0:f6c99a47ce43 | 1126 | const uint8_t* src = reinterpret_cast<const uint8_t*>(buf); | 
| Jackson_lv | 0:f6c99a47ce43 | 1127 | |
| Jackson_lv | 0:f6c99a47ce43 | 1128 | // number of bytes left to write - must be before goto statements | 
| Jackson_lv | 0:f6c99a47ce43 | 1129 | uint16_t nToWrite = nbyte; | 
| Jackson_lv | 0:f6c99a47ce43 | 1130 | |
| Jackson_lv | 0:f6c99a47ce43 | 1131 | // error if not a normal file or is read-only | 
| Jackson_lv | 0:f6c99a47ce43 | 1132 | if (!isFile() || !(flags_ & O_WRITE)) goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1133 | |
| Jackson_lv | 0:f6c99a47ce43 | 1134 | // seek to end of file if append flag | 
| Jackson_lv | 0:f6c99a47ce43 | 1135 | if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1136 | if (!seekEnd()) goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1137 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1138 | |
| Jackson_lv | 0:f6c99a47ce43 | 1139 | while (nToWrite > 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1140 | uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); | 
| Jackson_lv | 0:f6c99a47ce43 | 1141 | uint16_t blockOffset = curPosition_ & 0X1FF; | 
| Jackson_lv | 0:f6c99a47ce43 | 1142 | if (blockOfCluster == 0 && blockOffset == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1143 | // start of new cluster | 
| Jackson_lv | 0:f6c99a47ce43 | 1144 | if (curCluster_ == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1145 | if (firstCluster_ == 0) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1146 | // allocate first cluster of file | 
| Jackson_lv | 0:f6c99a47ce43 | 1147 | if (!addCluster()) goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1148 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 1149 | curCluster_ = firstCluster_; | 
| Jackson_lv | 0:f6c99a47ce43 | 1150 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1151 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 1152 | uint32_t next; | 
| Jackson_lv | 0:f6c99a47ce43 | 1153 | if (!vol_->fatGet(curCluster_, &next)) return false; | 
| Jackson_lv | 0:f6c99a47ce43 | 1154 | if (vol_->isEOC(next)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1155 | // add cluster if at end of chain | 
| Jackson_lv | 0:f6c99a47ce43 | 1156 | if (!addCluster()) goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1157 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 1158 | curCluster_ = next; | 
| Jackson_lv | 0:f6c99a47ce43 | 1159 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1160 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1161 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1162 | // max space in block | 
| Jackson_lv | 0:f6c99a47ce43 | 1163 | uint16_t n = 512 - blockOffset; | 
| Jackson_lv | 0:f6c99a47ce43 | 1164 | |
| Jackson_lv | 0:f6c99a47ce43 | 1165 | // lesser of space and amount to write | 
| Jackson_lv | 0:f6c99a47ce43 | 1166 | if (n > nToWrite) n = nToWrite; | 
| Jackson_lv | 0:f6c99a47ce43 | 1167 | |
| Jackson_lv | 0:f6c99a47ce43 | 1168 | // block for data write | 
| Jackson_lv | 0:f6c99a47ce43 | 1169 | uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; | 
| Jackson_lv | 0:f6c99a47ce43 | 1170 | if (n == 512) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1171 | // full block - don't need to use cache | 
| Jackson_lv | 0:f6c99a47ce43 | 1172 | // invalidate cache if block is in cache | 
| Jackson_lv | 0:f6c99a47ce43 | 1173 | if (SdVolume::cacheBlockNumber_ == block) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1174 | SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; | 
| Jackson_lv | 0:f6c99a47ce43 | 1175 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1176 | if (!vol_->writeBlock(block, src)) goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1177 | src += 512; | 
| Jackson_lv | 0:f6c99a47ce43 | 1178 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 1179 | if (blockOffset == 0 && curPosition_ >= fileSize_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1180 | // start of new block don't need to read into cache | 
| Jackson_lv | 0:f6c99a47ce43 | 1181 | if (!SdVolume::cacheFlush()) goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1182 | SdVolume::cacheBlockNumber_ = block; | 
| Jackson_lv | 0:f6c99a47ce43 | 1183 | SdVolume::cacheSetDirty(); | 
| Jackson_lv | 0:f6c99a47ce43 | 1184 | } else { | 
| Jackson_lv | 0:f6c99a47ce43 | 1185 | // rewrite part of block | 
| Jackson_lv | 0:f6c99a47ce43 | 1186 | if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1187 | goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1188 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1189 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1190 | uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset; | 
| Jackson_lv | 0:f6c99a47ce43 | 1191 | uint8_t* end = dst + n; | 
| Jackson_lv | 0:f6c99a47ce43 | 1192 | while (dst != end) *dst++ = *src++; | 
| Jackson_lv | 0:f6c99a47ce43 | 1193 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1194 | nToWrite -= n; | 
| Jackson_lv | 0:f6c99a47ce43 | 1195 | curPosition_ += n; | 
| Jackson_lv | 0:f6c99a47ce43 | 1196 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1197 | if (curPosition_ > fileSize_) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1198 | // update fileSize and insure sync will update dir entry | 
| Jackson_lv | 0:f6c99a47ce43 | 1199 | fileSize_ = curPosition_; | 
| Jackson_lv | 0:f6c99a47ce43 | 1200 | flags_ |= F_FILE_DIR_DIRTY; | 
| Jackson_lv | 0:f6c99a47ce43 | 1201 | } else if (dateTime_ && nbyte) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1202 | // insure sync will update modified date and time | 
| Jackson_lv | 0:f6c99a47ce43 | 1203 | flags_ |= F_FILE_DIR_DIRTY; | 
| Jackson_lv | 0:f6c99a47ce43 | 1204 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1205 | |
| Jackson_lv | 0:f6c99a47ce43 | 1206 | if (flags_ & O_SYNC) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1207 | if (!sync()) goto writeErrorReturn; | 
| Jackson_lv | 0:f6c99a47ce43 | 1208 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1209 | return nbyte; | 
| Jackson_lv | 0:f6c99a47ce43 | 1210 | |
| Jackson_lv | 0:f6c99a47ce43 | 1211 | writeErrorReturn: | 
| Jackson_lv | 0:f6c99a47ce43 | 1212 | // return for write error | 
| Jackson_lv | 0:f6c99a47ce43 | 1213 | //writeError = true; | 
| Jackson_lv | 0:f6c99a47ce43 | 1214 | setWriteError(); | 
| Jackson_lv | 0:f6c99a47ce43 | 1215 | return 0; | 
| Jackson_lv | 0:f6c99a47ce43 | 1216 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1217 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 1218 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 1219 | * Write a byte to a file. Required by the Arduino Print class. | 
| Jackson_lv | 0:f6c99a47ce43 | 1220 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1221 | * Use SdFile::writeError to check for errors. | 
| Jackson_lv | 0:f6c99a47ce43 | 1222 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 1223 | size_t SdFile::write(uint8_t b) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1224 | return write(&b, 1); | 
| Jackson_lv | 0:f6c99a47ce43 | 1225 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1226 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 1227 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 1228 | * Write a string to a file. Used by the Arduino Print class. | 
| Jackson_lv | 0:f6c99a47ce43 | 1229 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1230 | * Use SdFile::writeError to check for errors. | 
| Jackson_lv | 0:f6c99a47ce43 | 1231 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 1232 | size_t SdFile::write(const char* str) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1233 | return write(str, strlen(str)); | 
| Jackson_lv | 0:f6c99a47ce43 | 1234 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1235 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 1236 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 1237 | * Write a PROGMEM string to a file. | 
| Jackson_lv | 0:f6c99a47ce43 | 1238 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1239 | * Use SdFile::writeError to check for errors. | 
| Jackson_lv | 0:f6c99a47ce43 | 1240 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 1241 | void SdFile::write_P(PGM_P str) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1242 | for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); | 
| Jackson_lv | 0:f6c99a47ce43 | 1243 | } | 
| Jackson_lv | 0:f6c99a47ce43 | 1244 | //------------------------------------------------------------------------------ | 
| Jackson_lv | 0:f6c99a47ce43 | 1245 | /** | 
| Jackson_lv | 0:f6c99a47ce43 | 1246 | * Write a PROGMEM string followed by CR/LF to a file. | 
| Jackson_lv | 0:f6c99a47ce43 | 1247 | * | 
| Jackson_lv | 0:f6c99a47ce43 | 1248 | * Use SdFile::writeError to check for errors. | 
| Jackson_lv | 0:f6c99a47ce43 | 1249 | */ | 
| Jackson_lv | 0:f6c99a47ce43 | 1250 | void SdFile::writeln_P(PGM_P str) { | 
| Jackson_lv | 0:f6c99a47ce43 | 1251 | write_P(str); | 
| Jackson_lv | 0:f6c99a47ce43 | 1252 | println(); | 
| Jackson_lv | 0:f6c99a47ce43 | 1253 | } |