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