|
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 |
|
21 #include "Marlin.h" |
|
22 #ifdef SDSUPPORT |
|
23 |
|
24 #include "SdBaseFile.h" |
|
25 //------------------------------------------------------------------------------ |
|
26 // pointer to cwd directory |
|
27 SdBaseFile* SdBaseFile::cwd_ = 0; |
|
28 // callback function for date/time |
|
29 void (*SdBaseFile::dateTime_)(uint16_t* date, uint16_t* time) = 0; |
|
30 //------------------------------------------------------------------------------ |
|
31 // add a cluster to a file |
|
32 bool SdBaseFile::addCluster() { |
|
33 if (!vol_->allocContiguous(1, &curCluster_)) goto fail; |
|
34 |
|
35 // if first cluster of file link to directory entry |
|
36 if (firstCluster_ == 0) { |
|
37 firstCluster_ = curCluster_; |
|
38 flags_ |= F_FILE_DIR_DIRTY; |
|
39 } |
|
40 return true; |
|
41 |
|
42 fail: |
|
43 return false; |
|
44 } |
|
45 //------------------------------------------------------------------------------ |
|
46 // Add a cluster to a directory file and zero the cluster. |
|
47 // return with first block of cluster in the cache |
|
48 bool SdBaseFile::addDirCluster() { |
|
49 uint32_t block; |
|
50 // max folder size |
|
51 if (fileSize_/sizeof(dir_t) >= 0XFFFF) goto fail; |
|
52 |
|
53 if (!addCluster()) goto fail; |
|
54 if (!vol_->cacheFlush()) goto fail; |
|
55 |
|
56 block = vol_->clusterStartBlock(curCluster_); |
|
57 |
|
58 // set cache to first block of cluster |
|
59 vol_->cacheSetBlockNumber(block, true); |
|
60 |
|
61 // zero first block of cluster |
|
62 memset(vol_->cacheBuffer_.data, 0, 512); |
|
63 |
|
64 // zero rest of cluster |
|
65 for (uint8_t i = 1; i < vol_->blocksPerCluster_; i++) { |
|
66 if (!vol_->writeBlock(block + i, vol_->cacheBuffer_.data)) goto fail; |
|
67 } |
|
68 // Increase directory file size by cluster size |
|
69 fileSize_ += 512UL << vol_->clusterSizeShift_; |
|
70 return true; |
|
71 |
|
72 fail: |
|
73 return false; |
|
74 } |
|
75 //------------------------------------------------------------------------------ |
|
76 // cache a file's directory entry |
|
77 // return pointer to cached entry or null for failure |
|
78 dir_t* SdBaseFile::cacheDirEntry(uint8_t action) { |
|
79 if (!vol_->cacheRawBlock(dirBlock_, action)) goto fail; |
|
80 return vol_->cache()->dir + dirIndex_; |
|
81 |
|
82 fail: |
|
83 return 0; |
|
84 } |
|
85 //------------------------------------------------------------------------------ |
|
86 /** Close a file and force cached data and directory information |
|
87 * to be written to the storage device. |
|
88 * |
|
89 * \return The value one, true, is returned for success and |
|
90 * the value zero, false, is returned for failure. |
|
91 * Reasons for failure include no file is open or an I/O error. |
|
92 */ |
|
93 bool SdBaseFile::close() { |
|
94 bool rtn = sync(); |
|
95 type_ = FAT_FILE_TYPE_CLOSED; |
|
96 return rtn; |
|
97 } |
|
98 //------------------------------------------------------------------------------ |
|
99 /** Check for contiguous file and return its raw block range. |
|
100 * |
|
101 * \param[out] bgnBlock the first block address for the file. |
|
102 * \param[out] endBlock the last block address for the file. |
|
103 * |
|
104 * \return The value one, true, is returned for success and |
|
105 * the value zero, false, is returned for failure. |
|
106 * Reasons for failure include file is not contiguous, file has zero length |
|
107 * or an I/O error occurred. |
|
108 */ |
|
109 bool SdBaseFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { |
|
110 // error if no blocks |
|
111 if (firstCluster_ == 0) goto fail; |
|
112 |
|
113 for (uint32_t c = firstCluster_; ; c++) { |
|
114 uint32_t next; |
|
115 if (!vol_->fatGet(c, &next)) goto fail; |
|
116 |
|
117 // check for contiguous |
|
118 if (next != (c + 1)) { |
|
119 // error if not end of chain |
|
120 if (!vol_->isEOC(next)) goto fail; |
|
121 *bgnBlock = vol_->clusterStartBlock(firstCluster_); |
|
122 *endBlock = vol_->clusterStartBlock(c) |
|
123 + vol_->blocksPerCluster_ - 1; |
|
124 return true; |
|
125 } |
|
126 } |
|
127 |
|
128 fail: |
|
129 return false; |
|
130 } |
|
131 //------------------------------------------------------------------------------ |
|
132 /** Create and open a new contiguous file of a specified size. |
|
133 * |
|
134 * \note This function only supports short DOS 8.3 names. |
|
135 * See open() for more information. |
|
136 * |
|
137 * \param[in] dirFile The directory where the file will be created. |
|
138 * \param[in] path A path with a valid DOS 8.3 file name. |
|
139 * \param[in] size The desired file size. |
|
140 * |
|
141 * \return The value one, true, is returned for success and |
|
142 * the value zero, false, is returned for failure. |
|
143 * Reasons for failure include \a path contains |
|
144 * an invalid DOS 8.3 file name, the FAT volume has not been initialized, |
|
145 * a file is already open, the file already exists, the root |
|
146 * directory is full or an I/O error. |
|
147 * |
|
148 */ |
|
149 bool SdBaseFile::createContiguous(SdBaseFile* dirFile, |
|
150 const char* path, uint32_t size) { |
|
151 uint32_t count; |
|
152 // don't allow zero length file |
|
153 if (size == 0) goto fail; |
|
154 if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) goto fail; |
|
155 |
|
156 // calculate number of clusters needed |
|
157 count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; |
|
158 |
|
159 // allocate clusters |
|
160 if (!vol_->allocContiguous(count, &firstCluster_)) { |
|
161 remove(); |
|
162 goto fail; |
|
163 } |
|
164 fileSize_ = size; |
|
165 |
|
166 // insure sync() will update dir entry |
|
167 flags_ |= F_FILE_DIR_DIRTY; |
|
168 |
|
169 return sync(); |
|
170 |
|
171 fail: |
|
172 return false; |
|
173 } |
|
174 //------------------------------------------------------------------------------ |
|
175 /** Return a file's directory entry. |
|
176 * |
|
177 * \param[out] dir Location for return of the file's directory entry. |
|
178 * |
|
179 * \return The value one, true, is returned for success and |
|
180 * the value zero, false, is returned for failure. |
|
181 */ |
|
182 bool SdBaseFile::dirEntry(dir_t* dir) { |
|
183 dir_t* p; |
|
184 // make sure fields on SD are correct |
|
185 if (!sync()) goto fail; |
|
186 |
|
187 // read entry |
|
188 p = cacheDirEntry(SdVolume::CACHE_FOR_READ); |
|
189 if (!p) goto fail; |
|
190 |
|
191 // copy to caller's struct |
|
192 memcpy(dir, p, sizeof(dir_t)); |
|
193 return true; |
|
194 |
|
195 fail: |
|
196 return false; |
|
197 } |
|
198 //------------------------------------------------------------------------------ |
|
199 /** Format the name field of \a dir into the 13 byte array |
|
200 * \a name in standard 8.3 short name format. |
|
201 * |
|
202 * \param[in] dir The directory structure containing the name. |
|
203 * \param[out] name A 13 byte char array for the formatted name. |
|
204 */ |
|
205 void SdBaseFile::dirName(const dir_t& dir, char* name) { |
|
206 uint8_t j = 0; |
|
207 for (uint8_t i = 0; i < 11; i++) { |
|
208 if (dir.name[i] == ' ')continue; |
|
209 if (i == 8) name[j++] = '.'; |
|
210 name[j++] = dir.name[i]; |
|
211 } |
|
212 name[j] = 0; |
|
213 } |
|
214 //------------------------------------------------------------------------------ |
|
215 /** Test for the existence of a file in a directory |
|
216 * |
|
217 * \param[in] name Name of the file to be tested for. |
|
218 * |
|
219 * The calling instance must be an open directory file. |
|
220 * |
|
221 * dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory |
|
222 * dirFile. |
|
223 * |
|
224 * \return true if the file exists else false. |
|
225 */ |
|
226 bool SdBaseFile::exists(const char* name) { |
|
227 SdBaseFile file; |
|
228 return file.open(this, name, O_READ); |
|
229 } |
|
230 //------------------------------------------------------------------------------ |
|
231 /** |
|
232 * Get a string from a file. |
|
233 * |
|
234 * fgets() reads bytes from a file into the array pointed to by \a str, until |
|
235 * \a num - 1 bytes are read, or a delimiter is read and transferred to \a str, |
|
236 * or end-of-file is encountered. The string is then terminated |
|
237 * with a null byte. |
|
238 * |
|
239 * fgets() deletes CR, '\\r', from the string. This insures only a '\\n' |
|
240 * terminates the string for Windows text files which use CRLF for newline. |
|
241 * |
|
242 * \param[out] str Pointer to the array where the string is stored. |
|
243 * \param[in] num Maximum number of characters to be read |
|
244 * (including the final null byte). Usually the length |
|
245 * of the array \a str is used. |
|
246 * \param[in] delim Optional set of delimiters. The default is "\n". |
|
247 * |
|
248 * \return For success fgets() returns the length of the string in \a str. |
|
249 * If no data is read, fgets() returns zero for EOF or -1 if an error occurred. |
|
250 **/ |
|
251 int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) { |
|
252 char ch; |
|
253 int16_t n = 0; |
|
254 int16_t r = -1; |
|
255 while ((n + 1) < num && (r = read(&ch, 1)) == 1) { |
|
256 // delete CR |
|
257 if (ch == '\r') continue; |
|
258 str[n++] = ch; |
|
259 if (!delim) { |
|
260 if (ch == '\n') break; |
|
261 } else { |
|
262 if (strchr(delim, ch)) break; |
|
263 } |
|
264 } |
|
265 if (r < 0) { |
|
266 // read error |
|
267 return -1; |
|
268 } |
|
269 str[n] = '\0'; |
|
270 return n; |
|
271 } |
|
272 //------------------------------------------------------------------------------ |
|
273 /** Get a file's name |
|
274 * |
|
275 * \param[out] name An array of 13 characters for the file's name. |
|
276 * |
|
277 * \return The value one, true, is returned for success and |
|
278 * the value zero, false, is returned for failure. |
|
279 */ |
|
280 bool SdBaseFile::getFilename(char* name) { |
|
281 if (!isOpen()) return false; |
|
282 |
|
283 if (isRoot()) { |
|
284 name[0] = '/'; |
|
285 name[1] = '\0'; |
|
286 return true; |
|
287 } |
|
288 // cache entry |
|
289 dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); |
|
290 if (!p) return false; |
|
291 |
|
292 // format name |
|
293 dirName(*p, name); |
|
294 return true; |
|
295 } |
|
296 //------------------------------------------------------------------------------ |
|
297 void SdBaseFile::getpos(fpos_t* pos) { |
|
298 pos->position = curPosition_; |
|
299 pos->cluster = curCluster_; |
|
300 } |
|
301 |
|
302 //------------------------------------------------------------------------------ |
|
303 /** List directory contents. |
|
304 * |
|
305 * \param[in] pr Print stream for list. |
|
306 * |
|
307 * \param[in] flags The inclusive OR of |
|
308 * |
|
309 * LS_DATE - %Print file modification date |
|
310 * |
|
311 * LS_SIZE - %Print file size. |
|
312 * |
|
313 * LS_R - Recursive list of subdirectories. |
|
314 * |
|
315 * \param[in] indent Amount of space before file name. Used for recursive |
|
316 * list to indicate subdirectory level. |
|
317 */ |
|
318 void SdBaseFile::ls(uint8_t flags, uint8_t indent) { |
|
319 rewind(); |
|
320 int8_t status; |
|
321 while ((status = lsPrintNext( flags, indent))) { |
|
322 if (status > 1 && (flags & LS_R)) { |
|
323 uint16_t index = curPosition()/32 - 1; |
|
324 SdBaseFile s; |
|
325 if (s.open(this, index, O_READ)) s.ls( flags, indent + 2); |
|
326 seekSet(32 * (index + 1)); |
|
327 } |
|
328 } |
|
329 } |
|
330 //------------------------------------------------------------------------------ |
|
331 // saves 32 bytes on stack for ls recursion |
|
332 // return 0 - EOF, 1 - normal file, or 2 - directory |
|
333 int8_t SdBaseFile::lsPrintNext( uint8_t flags, uint8_t indent) { |
|
334 dir_t dir; |
|
335 uint8_t w = 0; |
|
336 |
|
337 while (1) { |
|
338 if (read(&dir, sizeof(dir)) != sizeof(dir)) return 0; |
|
339 if (dir.name[0] == DIR_NAME_FREE) return 0; |
|
340 |
|
341 // skip deleted entry and entries for . and .. |
|
342 if (dir.name[0] != DIR_NAME_DELETED && dir.name[0] != '.' |
|
343 && DIR_IS_FILE_OR_SUBDIR(&dir)) break; |
|
344 } |
|
345 // indent for dir level |
|
346 for (uint8_t i = 0; i < indent; i++) MYSERIAL.write(' '); |
|
347 |
|
348 // print name |
|
349 for (uint8_t i = 0; i < 11; i++) { |
|
350 if (dir.name[i] == ' ')continue; |
|
351 if (i == 8) { |
|
352 MYSERIAL.write('.'); |
|
353 w++; |
|
354 } |
|
355 MYSERIAL.write(dir.name[i]); |
|
356 w++; |
|
357 } |
|
358 if (DIR_IS_SUBDIR(&dir)) { |
|
359 MYSERIAL.write('/'); |
|
360 w++; |
|
361 } |
|
362 if (flags & (LS_DATE | LS_SIZE)) { |
|
363 while (w++ < 14) MYSERIAL.write(' '); |
|
364 } |
|
365 // print modify date/time if requested |
|
366 if (flags & LS_DATE) { |
|
367 MYSERIAL.write(' '); |
|
368 printFatDate( dir.lastWriteDate); |
|
369 MYSERIAL.write(' '); |
|
370 printFatTime( dir.lastWriteTime); |
|
371 } |
|
372 // print size if requested |
|
373 if (!DIR_IS_SUBDIR(&dir) && (flags & LS_SIZE)) { |
|
374 MYSERIAL.write(' '); |
|
375 MYSERIAL.print(dir.fileSize); |
|
376 } |
|
377 MYSERIAL.println(); |
|
378 return DIR_IS_FILE(&dir) ? 1 : 2; |
|
379 } |
|
380 //------------------------------------------------------------------------------ |
|
381 // format directory name field from a 8.3 name string |
|
382 bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) { |
|
383 uint8_t c; |
|
384 uint8_t n = 7; // max index for part before dot |
|
385 uint8_t i = 0; |
|
386 // blank fill name and extension |
|
387 while (i < 11) name[i++] = ' '; |
|
388 i = 0; |
|
389 while (*str != '\0' && *str != '/') { |
|
390 c = *str++; |
|
391 if (c == '.') { |
|
392 if (n == 10) goto fail; // only one dot allowed |
|
393 n = 10; // max index for full 8.3 name |
|
394 i = 8; // place for extension |
|
395 } else { |
|
396 // illegal FAT characters |
|
397 PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); |
|
398 uint8_t b; |
|
399 while ((b = pgm_read_byte(p++))) if (b == c) goto fail; |
|
400 // check size and only allow ASCII printable characters |
|
401 if (i > n || c < 0X21 || c > 0X7E)goto fail; |
|
402 // only upper case allowed in 8.3 names - convert lower to upper |
|
403 name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); |
|
404 } |
|
405 } |
|
406 *ptr = str; |
|
407 // must have a file name, extension is optional |
|
408 return name[0] != ' '; |
|
409 |
|
410 fail: |
|
411 return false; |
|
412 } |
|
413 //------------------------------------------------------------------------------ |
|
414 /** Make a new directory. |
|
415 * |
|
416 * \param[in] parent An open SdFat instance for the directory that will contain |
|
417 * the new directory. |
|
418 * |
|
419 * \param[in] path A path with a valid 8.3 DOS name for the new directory. |
|
420 * |
|
421 * \param[in] pFlag Create missing parent directories if true. |
|
422 * |
|
423 * \return The value one, true, is returned for success and |
|
424 * the value zero, false, is returned for failure. |
|
425 * Reasons for failure include this file is already open, \a parent is not a |
|
426 * directory, \a path is invalid or already exists in \a parent. |
|
427 */ |
|
428 bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) { |
|
429 uint8_t dname[11]; |
|
430 SdBaseFile dir1, dir2; |
|
431 SdBaseFile* sub = &dir1; |
|
432 SdBaseFile* start = parent; |
|
433 |
|
434 if (!parent || isOpen()) goto fail; |
|
435 |
|
436 if (*path == '/') { |
|
437 while (*path == '/') path++; |
|
438 if (!parent->isRoot()) { |
|
439 if (!dir2.openRoot(parent->vol_)) goto fail; |
|
440 parent = &dir2; |
|
441 } |
|
442 } |
|
443 while (1) { |
|
444 if (!make83Name(path, dname, &path)) goto fail; |
|
445 while (*path == '/') path++; |
|
446 if (!*path) break; |
|
447 if (!sub->open(parent, dname, O_READ)) { |
|
448 if (!pFlag || !sub->mkdir(parent, dname)) { |
|
449 goto fail; |
|
450 } |
|
451 } |
|
452 if (parent != start) parent->close(); |
|
453 parent = sub; |
|
454 sub = parent != &dir1 ? &dir1 : &dir2; |
|
455 } |
|
456 return mkdir(parent, dname); |
|
457 |
|
458 fail: |
|
459 return false; |
|
460 } |
|
461 //------------------------------------------------------------------------------ |
|
462 bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) { |
|
463 uint32_t block; |
|
464 dir_t d; |
|
465 dir_t* p; |
|
466 |
|
467 if (!parent->isDir()) goto fail; |
|
468 |
|
469 // create a normal file |
|
470 if (!open(parent, dname, O_CREAT | O_EXCL | O_RDWR)) goto fail; |
|
471 |
|
472 // convert file to directory |
|
473 flags_ = O_READ; |
|
474 type_ = FAT_FILE_TYPE_SUBDIR; |
|
475 |
|
476 // allocate and zero first cluster |
|
477 if (!addDirCluster())goto fail; |
|
478 |
|
479 // force entry to SD |
|
480 if (!sync()) goto fail; |
|
481 |
|
482 // cache entry - should already be in cache due to sync() call |
|
483 p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
484 if (!p) goto fail; |
|
485 |
|
486 // change directory entry attribute |
|
487 p->attributes = DIR_ATT_DIRECTORY; |
|
488 |
|
489 // make entry for '.' |
|
490 memcpy(&d, p, sizeof(d)); |
|
491 d.name[0] = '.'; |
|
492 for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; |
|
493 |
|
494 // cache block for '.' and '..' |
|
495 block = vol_->clusterStartBlock(firstCluster_); |
|
496 if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; |
|
497 |
|
498 // copy '.' to block |
|
499 memcpy(&vol_->cache()->dir[0], &d, sizeof(d)); |
|
500 |
|
501 // make entry for '..' |
|
502 d.name[1] = '.'; |
|
503 if (parent->isRoot()) { |
|
504 d.firstClusterLow = 0; |
|
505 d.firstClusterHigh = 0; |
|
506 } else { |
|
507 d.firstClusterLow = parent->firstCluster_ & 0XFFFF; |
|
508 d.firstClusterHigh = parent->firstCluster_ >> 16; |
|
509 } |
|
510 // copy '..' to block |
|
511 memcpy(&vol_->cache()->dir[1], &d, sizeof(d)); |
|
512 |
|
513 // write first block |
|
514 return vol_->cacheFlush(); |
|
515 |
|
516 fail: |
|
517 return false; |
|
518 } |
|
519 //------------------------------------------------------------------------------ |
|
520 /** Open a file in the current working directory. |
|
521 * |
|
522 * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. |
|
523 * |
|
524 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive |
|
525 * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). |
|
526 * |
|
527 * \return The value one, true, is returned for success and |
|
528 * the value zero, false, is returned for failure. |
|
529 */ |
|
530 bool SdBaseFile::open(const char* path, uint8_t oflag) { |
|
531 return open(cwd_, path, oflag); |
|
532 } |
|
533 //------------------------------------------------------------------------------ |
|
534 /** Open a file or directory by name. |
|
535 * |
|
536 * \param[in] dirFile An open SdFat instance for the directory containing the |
|
537 * file to be opened. |
|
538 * |
|
539 * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. |
|
540 * |
|
541 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive |
|
542 * OR of flags from the following list |
|
543 * |
|
544 * O_READ - Open for reading. |
|
545 * |
|
546 * O_RDONLY - Same as O_READ. |
|
547 * |
|
548 * O_WRITE - Open for writing. |
|
549 * |
|
550 * O_WRONLY - Same as O_WRITE. |
|
551 * |
|
552 * O_RDWR - Open for reading and writing. |
|
553 * |
|
554 * O_APPEND - If set, the file offset shall be set to the end of the |
|
555 * file prior to each write. |
|
556 * |
|
557 * O_AT_END - Set the initial position at the end of the file. |
|
558 * |
|
559 * O_CREAT - If the file exists, this flag has no effect except as noted |
|
560 * under O_EXCL below. Otherwise, the file shall be created |
|
561 * |
|
562 * O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists. |
|
563 * |
|
564 * O_SYNC - Call sync() after each write. This flag should not be used with |
|
565 * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. |
|
566 * These functions do character at a time writes so sync() will be called |
|
567 * after each byte. |
|
568 * |
|
569 * O_TRUNC - If the file exists and is a regular file, and the file is |
|
570 * successfully opened and is not read only, its length shall be truncated to 0. |
|
571 * |
|
572 * WARNING: A given file must not be opened by more than one SdBaseFile object |
|
573 * of file corruption may occur. |
|
574 * |
|
575 * \note Directory files must be opened read only. Write and truncation is |
|
576 * not allowed for directory files. |
|
577 * |
|
578 * \return The value one, true, is returned for success and |
|
579 * the value zero, false, is returned for failure. |
|
580 * Reasons for failure include this file is already open, \a dirFile is not |
|
581 * a directory, \a path is invalid, the file does not exist |
|
582 * or can't be opened in the access mode specified by oflag. |
|
583 */ |
|
584 bool SdBaseFile::open(SdBaseFile* dirFile, const char* path, uint8_t oflag) { |
|
585 uint8_t dname[11]; |
|
586 SdBaseFile dir1, dir2; |
|
587 SdBaseFile *parent = dirFile; |
|
588 SdBaseFile *sub = &dir1; |
|
589 |
|
590 if (!dirFile) goto fail; |
|
591 |
|
592 // error if already open |
|
593 if (isOpen()) goto fail; |
|
594 |
|
595 if (*path == '/') { |
|
596 while (*path == '/') path++; |
|
597 if (!dirFile->isRoot()) { |
|
598 if (!dir2.openRoot(dirFile->vol_)) goto fail; |
|
599 parent = &dir2; |
|
600 } |
|
601 } |
|
602 while (1) { |
|
603 if (!make83Name(path, dname, &path)) goto fail; |
|
604 while (*path == '/') path++; |
|
605 if (!*path) break; |
|
606 if (!sub->open(parent, dname, O_READ)) goto fail; |
|
607 if (parent != dirFile) parent->close(); |
|
608 parent = sub; |
|
609 sub = parent != &dir1 ? &dir1 : &dir2; |
|
610 } |
|
611 return open(parent, dname, oflag); |
|
612 |
|
613 fail: |
|
614 return false; |
|
615 } |
|
616 //------------------------------------------------------------------------------ |
|
617 // open with filename in dname |
|
618 bool SdBaseFile::open(SdBaseFile* dirFile, |
|
619 const uint8_t dname[11], uint8_t oflag) { |
|
620 bool emptyFound = false; |
|
621 bool fileFound = false; |
|
622 uint8_t index; |
|
623 dir_t* p; |
|
624 |
|
625 vol_ = dirFile->vol_; |
|
626 |
|
627 dirFile->rewind(); |
|
628 // search for file |
|
629 |
|
630 while (dirFile->curPosition_ < dirFile->fileSize_) { |
|
631 index = 0XF & (dirFile->curPosition_ >> 5); |
|
632 p = dirFile->readDirCache(); |
|
633 if (!p) goto fail; |
|
634 |
|
635 if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { |
|
636 // remember first empty slot |
|
637 if (!emptyFound) { |
|
638 dirBlock_ = dirFile->vol_->cacheBlockNumber(); |
|
639 dirIndex_ = index; |
|
640 emptyFound = true; |
|
641 } |
|
642 // done if no entries follow |
|
643 if (p->name[0] == DIR_NAME_FREE) break; |
|
644 } else if (!memcmp(dname, p->name, 11)) { |
|
645 fileFound = true; |
|
646 break; |
|
647 } |
|
648 } |
|
649 if (fileFound) { |
|
650 // don't open existing file if O_EXCL |
|
651 if (oflag & O_EXCL) goto fail; |
|
652 } else { |
|
653 // don't create unless O_CREAT and O_WRITE |
|
654 if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) goto fail; |
|
655 if (emptyFound) { |
|
656 index = dirIndex_; |
|
657 p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
658 if (!p) goto fail; |
|
659 } else { |
|
660 if (dirFile->type_ == FAT_FILE_TYPE_ROOT_FIXED) goto fail; |
|
661 |
|
662 // add and zero cluster for dirFile - first cluster is in cache for write |
|
663 if (!dirFile->addDirCluster()) goto fail; |
|
664 |
|
665 // use first entry in cluster |
|
666 p = dirFile->vol_->cache()->dir; |
|
667 index = 0; |
|
668 } |
|
669 // initialize as empty file |
|
670 memset(p, 0, sizeof(dir_t)); |
|
671 memcpy(p->name, dname, 11); |
|
672 |
|
673 // set timestamps |
|
674 if (dateTime_) { |
|
675 // call user date/time function |
|
676 dateTime_(&p->creationDate, &p->creationTime); |
|
677 } else { |
|
678 // use default date/time |
|
679 p->creationDate = FAT_DEFAULT_DATE; |
|
680 p->creationTime = FAT_DEFAULT_TIME; |
|
681 } |
|
682 p->lastAccessDate = p->creationDate; |
|
683 p->lastWriteDate = p->creationDate; |
|
684 p->lastWriteTime = p->creationTime; |
|
685 |
|
686 // write entry to SD |
|
687 if (!dirFile->vol_->cacheFlush()) goto fail; |
|
688 } |
|
689 // open entry in cache |
|
690 return openCachedEntry(index, oflag); |
|
691 |
|
692 fail: |
|
693 return false; |
|
694 } |
|
695 //------------------------------------------------------------------------------ |
|
696 /** Open a file by index. |
|
697 * |
|
698 * \param[in] dirFile An open SdFat instance for the directory. |
|
699 * |
|
700 * \param[in] index The \a index of the directory entry for the file to be |
|
701 * opened. The value for \a index is (directory file position)/32. |
|
702 * |
|
703 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive |
|
704 * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. |
|
705 * |
|
706 * See open() by path for definition of flags. |
|
707 * \return true for success or false for failure. |
|
708 */ |
|
709 bool SdBaseFile::open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag) { |
|
710 dir_t* p; |
|
711 |
|
712 vol_ = dirFile->vol_; |
|
713 |
|
714 // error if already open |
|
715 if (isOpen() || !dirFile) goto fail; |
|
716 |
|
717 // don't open existing file if O_EXCL - user call error |
|
718 if (oflag & O_EXCL) goto fail; |
|
719 |
|
720 // seek to location of entry |
|
721 if (!dirFile->seekSet(32 * index)) goto fail; |
|
722 |
|
723 // read entry into cache |
|
724 p = dirFile->readDirCache(); |
|
725 if (!p) goto fail; |
|
726 |
|
727 // error if empty slot or '.' or '..' |
|
728 if (p->name[0] == DIR_NAME_FREE || |
|
729 p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { |
|
730 goto fail; |
|
731 } |
|
732 // open cached entry |
|
733 return openCachedEntry(index & 0XF, oflag); |
|
734 |
|
735 fail: |
|
736 return false; |
|
737 } |
|
738 //------------------------------------------------------------------------------ |
|
739 // open a cached directory entry. Assumes vol_ is initialized |
|
740 bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { |
|
741 // location of entry in cache |
|
742 dir_t* p = &vol_->cache()->dir[dirIndex]; |
|
743 |
|
744 // write or truncate is an error for a directory or read-only file |
|
745 if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { |
|
746 if (oflag & (O_WRITE | O_TRUNC)) goto fail; |
|
747 } |
|
748 // remember location of directory entry on SD |
|
749 dirBlock_ = vol_->cacheBlockNumber(); |
|
750 dirIndex_ = dirIndex; |
|
751 |
|
752 // copy first cluster number for directory fields |
|
753 firstCluster_ = (uint32_t)p->firstClusterHigh << 16; |
|
754 firstCluster_ |= p->firstClusterLow; |
|
755 |
|
756 // make sure it is a normal file or subdirectory |
|
757 if (DIR_IS_FILE(p)) { |
|
758 fileSize_ = p->fileSize; |
|
759 type_ = FAT_FILE_TYPE_NORMAL; |
|
760 } else if (DIR_IS_SUBDIR(p)) { |
|
761 if (!vol_->chainSize(firstCluster_, &fileSize_)) goto fail; |
|
762 type_ = FAT_FILE_TYPE_SUBDIR; |
|
763 } else { |
|
764 goto fail; |
|
765 } |
|
766 // save open flags for read/write |
|
767 flags_ = oflag & F_OFLAG; |
|
768 |
|
769 // set to start of file |
|
770 curCluster_ = 0; |
|
771 curPosition_ = 0; |
|
772 if ((oflag & O_TRUNC) && !truncate(0)) return false; |
|
773 return oflag & O_AT_END ? seekEnd(0) : true; |
|
774 |
|
775 fail: |
|
776 type_ = FAT_FILE_TYPE_CLOSED; |
|
777 return false; |
|
778 } |
|
779 //------------------------------------------------------------------------------ |
|
780 /** Open the next file or subdirectory in a directory. |
|
781 * |
|
782 * \param[in] dirFile An open SdFat instance for the directory containing the |
|
783 * file to be opened. |
|
784 * |
|
785 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive |
|
786 * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. |
|
787 * |
|
788 * See open() by path for definition of flags. |
|
789 * \return true for success or false for failure. |
|
790 */ |
|
791 bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) { |
|
792 dir_t* p; |
|
793 uint8_t index; |
|
794 |
|
795 if (!dirFile) goto fail; |
|
796 |
|
797 // error if already open |
|
798 if (isOpen()) goto fail; |
|
799 |
|
800 vol_ = dirFile->vol_; |
|
801 |
|
802 while (1) { |
|
803 index = 0XF & (dirFile->curPosition_ >> 5); |
|
804 |
|
805 // read entry into cache |
|
806 p = dirFile->readDirCache(); |
|
807 if (!p) goto fail; |
|
808 |
|
809 // done if last entry |
|
810 if (p->name[0] == DIR_NAME_FREE) goto fail; |
|
811 |
|
812 // skip empty slot or '.' or '..' |
|
813 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { |
|
814 continue; |
|
815 } |
|
816 // must be file or dir |
|
817 if (DIR_IS_FILE_OR_SUBDIR(p)) { |
|
818 return openCachedEntry(index, oflag); |
|
819 } |
|
820 } |
|
821 |
|
822 fail: |
|
823 return false; |
|
824 } |
|
825 //------------------------------------------------------------------------------ |
|
826 /** Open a directory's parent directory. |
|
827 * |
|
828 * \param[in] dir Parent of this directory will be opened. Must not be root. |
|
829 * |
|
830 * \return The value one, true, is returned for success and |
|
831 * the value zero, false, is returned for failure. |
|
832 */ |
|
833 bool SdBaseFile::openParent(SdBaseFile* dir) { |
|
834 dir_t entry; |
|
835 dir_t* p; |
|
836 SdBaseFile file; |
|
837 uint32_t c; |
|
838 uint32_t cluster; |
|
839 uint32_t lbn; |
|
840 // error if already open or dir is root or dir is not a directory |
|
841 if (isOpen() || !dir || dir->isRoot() || !dir->isDir()) goto fail; |
|
842 vol_ = dir->vol_; |
|
843 // position to '..' |
|
844 if (!dir->seekSet(32)) goto fail; |
|
845 // read '..' entry |
|
846 if (dir->read(&entry, sizeof(entry)) != 32) goto fail; |
|
847 // verify it is '..' |
|
848 if (entry.name[0] != '.' || entry.name[1] != '.') goto fail; |
|
849 // start cluster for '..' |
|
850 cluster = entry.firstClusterLow; |
|
851 cluster |= (uint32_t)entry.firstClusterHigh << 16; |
|
852 if (cluster == 0) return openRoot(vol_); |
|
853 // start block for '..' |
|
854 lbn = vol_->clusterStartBlock(cluster); |
|
855 // first block of parent dir |
|
856 if (!vol_->cacheRawBlock(lbn, SdVolume::CACHE_FOR_READ)) { |
|
857 goto fail; |
|
858 } |
|
859 p = &vol_->cacheBuffer_.dir[1]; |
|
860 // verify name for '../..' |
|
861 if (p->name[0] != '.' || p->name[1] != '.') goto fail; |
|
862 // '..' is pointer to first cluster of parent. open '../..' to find parent |
|
863 if (p->firstClusterHigh == 0 && p->firstClusterLow == 0) { |
|
864 if (!file.openRoot(dir->volume())) goto fail; |
|
865 } else { |
|
866 if (!file.openCachedEntry(1, O_READ)) goto fail; |
|
867 } |
|
868 // search for parent in '../..' |
|
869 do { |
|
870 if (file.readDir(&entry) != 32) goto fail; |
|
871 c = entry.firstClusterLow; |
|
872 c |= (uint32_t)entry.firstClusterHigh << 16; |
|
873 } while (c != cluster); |
|
874 // open parent |
|
875 return open(&file, file.curPosition()/32 - 1, O_READ); |
|
876 |
|
877 fail: |
|
878 return false; |
|
879 } |
|
880 //------------------------------------------------------------------------------ |
|
881 /** Open a volume's root directory. |
|
882 * |
|
883 * \param[in] vol The FAT volume containing the root directory to be opened. |
|
884 * |
|
885 * \return The value one, true, is returned for success and |
|
886 * the value zero, false, is returned for failure. |
|
887 * Reasons for failure include the file is already open, the FAT volume has |
|
888 * not been initialized or it a FAT12 volume. |
|
889 */ |
|
890 bool SdBaseFile::openRoot(SdVolume* vol) { |
|
891 // error if file is already open |
|
892 if (isOpen()) goto fail; |
|
893 |
|
894 if (vol->fatType() == 16 || (FAT12_SUPPORT && vol->fatType() == 12)) { |
|
895 type_ = FAT_FILE_TYPE_ROOT_FIXED; |
|
896 firstCluster_ = 0; |
|
897 fileSize_ = 32 * vol->rootDirEntryCount(); |
|
898 } else if (vol->fatType() == 32) { |
|
899 type_ = FAT_FILE_TYPE_ROOT32; |
|
900 firstCluster_ = vol->rootDirStart(); |
|
901 if (!vol->chainSize(firstCluster_, &fileSize_)) goto fail; |
|
902 } else { |
|
903 // volume is not initialized, invalid, or FAT12 without support |
|
904 return false; |
|
905 } |
|
906 vol_ = vol; |
|
907 // read only |
|
908 flags_ = O_READ; |
|
909 |
|
910 // set to start of file |
|
911 curCluster_ = 0; |
|
912 curPosition_ = 0; |
|
913 |
|
914 // root has no directory entry |
|
915 dirBlock_ = 0; |
|
916 dirIndex_ = 0; |
|
917 return true; |
|
918 |
|
919 fail: |
|
920 return false; |
|
921 } |
|
922 //------------------------------------------------------------------------------ |
|
923 /** Return the next available byte without consuming it. |
|
924 * |
|
925 * \return The byte if no error and not at eof else -1; |
|
926 */ |
|
927 int SdBaseFile::peek() { |
|
928 fpos_t pos; |
|
929 getpos(&pos); |
|
930 int c = read(); |
|
931 if (c >= 0) setpos(&pos); |
|
932 return c; |
|
933 } |
|
934 |
|
935 //------------------------------------------------------------------------------ |
|
936 /** %Print the name field of a directory entry in 8.3 format. |
|
937 * \param[in] pr Print stream for output. |
|
938 * \param[in] dir The directory structure containing the name. |
|
939 * \param[in] width Blank fill name if length is less than \a width. |
|
940 * \param[in] printSlash Print '/' after directory names if true. |
|
941 */ |
|
942 void SdBaseFile::printDirName(const dir_t& dir, |
|
943 uint8_t width, bool printSlash) { |
|
944 uint8_t w = 0; |
|
945 for (uint8_t i = 0; i < 11; i++) { |
|
946 if (dir.name[i] == ' ')continue; |
|
947 if (i == 8) { |
|
948 MYSERIAL.write('.'); |
|
949 w++; |
|
950 } |
|
951 MYSERIAL.write(dir.name[i]); |
|
952 w++; |
|
953 } |
|
954 if (DIR_IS_SUBDIR(&dir) && printSlash) { |
|
955 MYSERIAL.write('/'); |
|
956 w++; |
|
957 } |
|
958 while (w < width) { |
|
959 MYSERIAL.write(' '); |
|
960 w++; |
|
961 } |
|
962 } |
|
963 //------------------------------------------------------------------------------ |
|
964 // print uint8_t with width 2 |
|
965 static void print2u( uint8_t v) { |
|
966 if (v < 10) MYSERIAL.write('0'); |
|
967 MYSERIAL.print(v, DEC); |
|
968 } |
|
969 //------------------------------------------------------------------------------ |
|
970 /** %Print a directory date field to Serial. |
|
971 * |
|
972 * Format is yyyy-mm-dd. |
|
973 * |
|
974 * \param[in] fatDate The date field from a directory entry. |
|
975 */ |
|
976 |
|
977 //------------------------------------------------------------------------------ |
|
978 /** %Print a directory date field. |
|
979 * |
|
980 * Format is yyyy-mm-dd. |
|
981 * |
|
982 * \param[in] pr Print stream for output. |
|
983 * \param[in] fatDate The date field from a directory entry. |
|
984 */ |
|
985 void SdBaseFile::printFatDate(uint16_t fatDate) { |
|
986 MYSERIAL.print(FAT_YEAR(fatDate)); |
|
987 MYSERIAL.write('-'); |
|
988 print2u( FAT_MONTH(fatDate)); |
|
989 MYSERIAL.write('-'); |
|
990 print2u( FAT_DAY(fatDate)); |
|
991 } |
|
992 |
|
993 //------------------------------------------------------------------------------ |
|
994 /** %Print a directory time field. |
|
995 * |
|
996 * Format is hh:mm:ss. |
|
997 * |
|
998 * \param[in] pr Print stream for output. |
|
999 * \param[in] fatTime The time field from a directory entry. |
|
1000 */ |
|
1001 void SdBaseFile::printFatTime( uint16_t fatTime) { |
|
1002 print2u( FAT_HOUR(fatTime)); |
|
1003 MYSERIAL.write(':'); |
|
1004 print2u( FAT_MINUTE(fatTime)); |
|
1005 MYSERIAL.write(':'); |
|
1006 print2u( FAT_SECOND(fatTime)); |
|
1007 } |
|
1008 //------------------------------------------------------------------------------ |
|
1009 /** Print a file's name to Serial |
|
1010 * |
|
1011 * \return The value one, true, is returned for success and |
|
1012 * the value zero, false, is returned for failure. |
|
1013 */ |
|
1014 bool SdBaseFile::printName() { |
|
1015 char name[13]; |
|
1016 if (!getFilename(name)) return false; |
|
1017 MYSERIAL.print(name); |
|
1018 return true; |
|
1019 } |
|
1020 //------------------------------------------------------------------------------ |
|
1021 /** Read the next byte from a file. |
|
1022 * |
|
1023 * \return For success read returns the next byte in the file as an int. |
|
1024 * If an error occurs or end of file is reached -1 is returned. |
|
1025 */ |
|
1026 int16_t SdBaseFile::read() { |
|
1027 uint8_t b; |
|
1028 return read(&b, 1) == 1 ? b : -1; |
|
1029 } |
|
1030 //------------------------------------------------------------------------------ |
|
1031 /** Read data from a file starting at the current position. |
|
1032 * |
|
1033 * \param[out] buf Pointer to the location that will receive the data. |
|
1034 * |
|
1035 * \param[in] nbyte Maximum number of bytes to read. |
|
1036 * |
|
1037 * \return For success read() returns the number of bytes read. |
|
1038 * A value less than \a nbyte, including zero, will be returned |
|
1039 * if end of file is reached. |
|
1040 * If an error occurs, read() returns -1. Possible errors include |
|
1041 * read() called before a file has been opened, corrupt file system |
|
1042 * or an I/O error occurred. |
|
1043 */ |
|
1044 int16_t SdBaseFile::read(void* buf, uint16_t nbyte) { |
|
1045 uint8_t* dst = reinterpret_cast<uint8_t*>(buf); |
|
1046 uint16_t offset; |
|
1047 uint16_t toRead; |
|
1048 uint32_t block; // raw device block number |
|
1049 |
|
1050 // error if not open or write only |
|
1051 if (!isOpen() || !(flags_ & O_READ)) goto fail; |
|
1052 |
|
1053 // max bytes left in file |
|
1054 if (nbyte >= (fileSize_ - curPosition_)) { |
|
1055 nbyte = fileSize_ - curPosition_; |
|
1056 } |
|
1057 // amount left to read |
|
1058 toRead = nbyte; |
|
1059 while (toRead > 0) { |
|
1060 offset = curPosition_ & 0X1FF; // offset in block |
|
1061 if (type_ == FAT_FILE_TYPE_ROOT_FIXED) { |
|
1062 block = vol_->rootDirStart() + (curPosition_ >> 9); |
|
1063 } else { |
|
1064 uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); |
|
1065 if (offset == 0 && blockOfCluster == 0) { |
|
1066 // start of new cluster |
|
1067 if (curPosition_ == 0) { |
|
1068 // use first cluster in file |
|
1069 curCluster_ = firstCluster_; |
|
1070 } else { |
|
1071 // get next cluster from FAT |
|
1072 if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail; |
|
1073 } |
|
1074 } |
|
1075 block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; |
|
1076 } |
|
1077 uint16_t n = toRead; |
|
1078 |
|
1079 // amount to be read from current block |
|
1080 if (n > (512 - offset)) n = 512 - offset; |
|
1081 |
|
1082 // no buffering needed if n == 512 |
|
1083 if (n == 512 && block != vol_->cacheBlockNumber()) { |
|
1084 if (!vol_->readBlock(block, dst)) goto fail; |
|
1085 } else { |
|
1086 // read block to cache and copy data to caller |
|
1087 if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail; |
|
1088 uint8_t* src = vol_->cache()->data + offset; |
|
1089 memcpy(dst, src, n); |
|
1090 } |
|
1091 dst += n; |
|
1092 curPosition_ += n; |
|
1093 toRead -= n; |
|
1094 } |
|
1095 return nbyte; |
|
1096 |
|
1097 fail: |
|
1098 return -1; |
|
1099 } |
|
1100 //------------------------------------------------------------------------------ |
|
1101 /** Read the next directory entry from a directory file. |
|
1102 * |
|
1103 * \param[out] dir The dir_t struct that will receive the data. |
|
1104 * |
|
1105 * \return For success readDir() returns the number of bytes read. |
|
1106 * A value of zero will be returned if end of file is reached. |
|
1107 * If an error occurs, readDir() returns -1. Possible errors include |
|
1108 * readDir() called before a directory has been opened, this is not |
|
1109 * a directory file or an I/O error occurred. |
|
1110 */ |
|
1111 int8_t SdBaseFile::readDir(dir_t* dir) { |
|
1112 int16_t n; |
|
1113 // if not a directory file or miss-positioned return an error |
|
1114 if (!isDir() || (0X1F & curPosition_)) return -1; |
|
1115 |
|
1116 while (1) { |
|
1117 n = read(dir, sizeof(dir_t)); |
|
1118 if (n != sizeof(dir_t)) return n == 0 ? 0 : -1; |
|
1119 // last entry if DIR_NAME_FREE |
|
1120 if (dir->name[0] == DIR_NAME_FREE) return 0; |
|
1121 // skip empty entries and entry for . and .. |
|
1122 if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; |
|
1123 // return if normal file or subdirectory |
|
1124 if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; |
|
1125 } |
|
1126 } |
|
1127 //------------------------------------------------------------------------------ |
|
1128 // Read next directory entry into the cache |
|
1129 // Assumes file is correctly positioned |
|
1130 dir_t* SdBaseFile::readDirCache() { |
|
1131 uint8_t i; |
|
1132 // error if not directory |
|
1133 if (!isDir()) goto fail; |
|
1134 |
|
1135 // index of entry in cache |
|
1136 i = (curPosition_ >> 5) & 0XF; |
|
1137 |
|
1138 // use read to locate and cache block |
|
1139 if (read() < 0) goto fail; |
|
1140 |
|
1141 // advance to next entry |
|
1142 curPosition_ += 31; |
|
1143 |
|
1144 // return pointer to entry |
|
1145 return vol_->cache()->dir + i; |
|
1146 |
|
1147 fail: |
|
1148 return 0; |
|
1149 } |
|
1150 //------------------------------------------------------------------------------ |
|
1151 /** Remove a file. |
|
1152 * |
|
1153 * The directory entry and all data for the file are deleted. |
|
1154 * |
|
1155 * \note This function should not be used to delete the 8.3 version of a |
|
1156 * file that has a long name. For example if a file has the long name |
|
1157 * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". |
|
1158 * |
|
1159 * \return The value one, true, is returned for success and |
|
1160 * the value zero, false, is returned for failure. |
|
1161 * Reasons for failure include the file read-only, is a directory, |
|
1162 * or an I/O error occurred. |
|
1163 */ |
|
1164 bool SdBaseFile::remove() { |
|
1165 dir_t* d; |
|
1166 // free any clusters - will fail if read-only or directory |
|
1167 if (!truncate(0)) goto fail; |
|
1168 |
|
1169 // cache directory entry |
|
1170 d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
1171 if (!d) goto fail; |
|
1172 |
|
1173 // mark entry deleted |
|
1174 d->name[0] = DIR_NAME_DELETED; |
|
1175 |
|
1176 // set this file closed |
|
1177 type_ = FAT_FILE_TYPE_CLOSED; |
|
1178 |
|
1179 // write entry to SD |
|
1180 return vol_->cacheFlush(); |
|
1181 return true; |
|
1182 |
|
1183 fail: |
|
1184 return false; |
|
1185 } |
|
1186 //------------------------------------------------------------------------------ |
|
1187 /** Remove a file. |
|
1188 * |
|
1189 * The directory entry and all data for the file are deleted. |
|
1190 * |
|
1191 * \param[in] dirFile The directory that contains the file. |
|
1192 * \param[in] path Path for the file to be removed. |
|
1193 * |
|
1194 * \note This function should not be used to delete the 8.3 version of a |
|
1195 * file that has a long name. For example if a file has the long name |
|
1196 * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". |
|
1197 * |
|
1198 * \return The value one, true, is returned for success and |
|
1199 * the value zero, false, is returned for failure. |
|
1200 * Reasons for failure include the file is a directory, is read only, |
|
1201 * \a dirFile is not a directory, \a path is not found |
|
1202 * or an I/O error occurred. |
|
1203 */ |
|
1204 bool SdBaseFile::remove(SdBaseFile* dirFile, const char* path) { |
|
1205 SdBaseFile file; |
|
1206 if (!file.open(dirFile, path, O_WRITE)) goto fail; |
|
1207 return file.remove(); |
|
1208 |
|
1209 fail: |
|
1210 // can't set iostate - static function |
|
1211 return false; |
|
1212 } |
|
1213 //------------------------------------------------------------------------------ |
|
1214 /** Rename a file or subdirectory. |
|
1215 * |
|
1216 * \param[in] dirFile Directory for the new path. |
|
1217 * \param[in] newPath New path name for the file/directory. |
|
1218 * |
|
1219 * \return The value one, true, is returned for success and |
|
1220 * the value zero, false, is returned for failure. |
|
1221 * Reasons for failure include \a dirFile is not open or is not a directory |
|
1222 * file, newPath is invalid or already exists, or an I/O error occurs. |
|
1223 */ |
|
1224 bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) { |
|
1225 dir_t entry; |
|
1226 uint32_t dirCluster = 0; |
|
1227 SdBaseFile file; |
|
1228 dir_t* d; |
|
1229 |
|
1230 // must be an open file or subdirectory |
|
1231 if (!(isFile() || isSubDir())) goto fail; |
|
1232 |
|
1233 // can't move file |
|
1234 if (vol_ != dirFile->vol_) goto fail; |
|
1235 |
|
1236 // sync() and cache directory entry |
|
1237 sync(); |
|
1238 d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
1239 if (!d) goto fail; |
|
1240 |
|
1241 // save directory entry |
|
1242 memcpy(&entry, d, sizeof(entry)); |
|
1243 |
|
1244 // mark entry deleted |
|
1245 d->name[0] = DIR_NAME_DELETED; |
|
1246 |
|
1247 // make directory entry for new path |
|
1248 if (isFile()) { |
|
1249 if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRITE)) { |
|
1250 goto restore; |
|
1251 } |
|
1252 } else { |
|
1253 // don't create missing path prefix components |
|
1254 if (!file.mkdir(dirFile, newPath, false)) { |
|
1255 goto restore; |
|
1256 } |
|
1257 // save cluster containing new dot dot |
|
1258 dirCluster = file.firstCluster_; |
|
1259 } |
|
1260 // change to new directory entry |
|
1261 dirBlock_ = file.dirBlock_; |
|
1262 dirIndex_ = file.dirIndex_; |
|
1263 |
|
1264 // mark closed to avoid possible destructor close call |
|
1265 file.type_ = FAT_FILE_TYPE_CLOSED; |
|
1266 |
|
1267 // cache new directory entry |
|
1268 d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
1269 if (!d) goto fail; |
|
1270 |
|
1271 // copy all but name field to new directory entry |
|
1272 memcpy(&d->attributes, &entry.attributes, sizeof(entry) - sizeof(d->name)); |
|
1273 |
|
1274 // update dot dot if directory |
|
1275 if (dirCluster) { |
|
1276 // get new dot dot |
|
1277 uint32_t block = vol_->clusterStartBlock(dirCluster); |
|
1278 if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail; |
|
1279 memcpy(&entry, &vol_->cache()->dir[1], sizeof(entry)); |
|
1280 |
|
1281 // free unused cluster |
|
1282 if (!vol_->freeChain(dirCluster)) goto fail; |
|
1283 |
|
1284 // store new dot dot |
|
1285 block = vol_->clusterStartBlock(firstCluster_); |
|
1286 if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; |
|
1287 memcpy(&vol_->cache()->dir[1], &entry, sizeof(entry)); |
|
1288 } |
|
1289 return vol_->cacheFlush(); |
|
1290 |
|
1291 restore: |
|
1292 d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
1293 if (!d) goto fail; |
|
1294 // restore entry |
|
1295 d->name[0] = entry.name[0]; |
|
1296 vol_->cacheFlush(); |
|
1297 |
|
1298 fail: |
|
1299 return false; |
|
1300 } |
|
1301 //------------------------------------------------------------------------------ |
|
1302 /** Remove a directory file. |
|
1303 * |
|
1304 * The directory file will be removed only if it is empty and is not the |
|
1305 * root directory. rmdir() follows DOS and Windows and ignores the |
|
1306 * read-only attribute for the directory. |
|
1307 * |
|
1308 * \note This function should not be used to delete the 8.3 version of a |
|
1309 * directory that has a long name. For example if a directory has the |
|
1310 * long name "New folder" you should not delete the 8.3 name "NEWFOL~1". |
|
1311 * |
|
1312 * \return The value one, true, is returned for success and |
|
1313 * the value zero, false, is returned for failure. |
|
1314 * Reasons for failure include the file is not a directory, is the root |
|
1315 * directory, is not empty, or an I/O error occurred. |
|
1316 */ |
|
1317 bool SdBaseFile::rmdir() { |
|
1318 // must be open subdirectory |
|
1319 if (!isSubDir()) goto fail; |
|
1320 |
|
1321 rewind(); |
|
1322 |
|
1323 // make sure directory is empty |
|
1324 while (curPosition_ < fileSize_) { |
|
1325 dir_t* p = readDirCache(); |
|
1326 if (!p) goto fail; |
|
1327 // done if past last used entry |
|
1328 if (p->name[0] == DIR_NAME_FREE) break; |
|
1329 // skip empty slot, '.' or '..' |
|
1330 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; |
|
1331 // error not empty |
|
1332 if (DIR_IS_FILE_OR_SUBDIR(p)) goto fail; |
|
1333 } |
|
1334 // convert empty directory to normal file for remove |
|
1335 type_ = FAT_FILE_TYPE_NORMAL; |
|
1336 flags_ |= O_WRITE; |
|
1337 return remove(); |
|
1338 |
|
1339 fail: |
|
1340 return false; |
|
1341 } |
|
1342 //------------------------------------------------------------------------------ |
|
1343 /** Recursively delete a directory and all contained files. |
|
1344 * |
|
1345 * This is like the Unix/Linux 'rm -rf *' if called with the root directory |
|
1346 * hence the name. |
|
1347 * |
|
1348 * Warning - This will remove all contents of the directory including |
|
1349 * subdirectories. The directory will then be removed if it is not root. |
|
1350 * The read-only attribute for files will be ignored. |
|
1351 * |
|
1352 * \note This function should not be used to delete the 8.3 version of |
|
1353 * a directory that has a long name. See remove() and rmdir(). |
|
1354 * |
|
1355 * \return The value one, true, is returned for success and |
|
1356 * the value zero, false, is returned for failure. |
|
1357 */ |
|
1358 bool SdBaseFile::rmRfStar() { |
|
1359 uint16_t index; |
|
1360 SdBaseFile f; |
|
1361 rewind(); |
|
1362 while (curPosition_ < fileSize_) { |
|
1363 // remember position |
|
1364 index = curPosition_/32; |
|
1365 |
|
1366 dir_t* p = readDirCache(); |
|
1367 if (!p) goto fail; |
|
1368 |
|
1369 // done if past last entry |
|
1370 if (p->name[0] == DIR_NAME_FREE) break; |
|
1371 |
|
1372 // skip empty slot or '.' or '..' |
|
1373 if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; |
|
1374 |
|
1375 // skip if part of long file name or volume label in root |
|
1376 if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; |
|
1377 |
|
1378 if (!f.open(this, index, O_READ)) goto fail; |
|
1379 if (f.isSubDir()) { |
|
1380 // recursively delete |
|
1381 if (!f.rmRfStar()) goto fail; |
|
1382 } else { |
|
1383 // ignore read-only |
|
1384 f.flags_ |= O_WRITE; |
|
1385 if (!f.remove()) goto fail; |
|
1386 } |
|
1387 // position to next entry if required |
|
1388 if (curPosition_ != (32*(index + 1))) { |
|
1389 if (!seekSet(32*(index + 1))) goto fail; |
|
1390 } |
|
1391 } |
|
1392 // don't try to delete root |
|
1393 if (!isRoot()) { |
|
1394 if (!rmdir()) goto fail; |
|
1395 } |
|
1396 return true; |
|
1397 |
|
1398 fail: |
|
1399 return false; |
|
1400 } |
|
1401 //------------------------------------------------------------------------------ |
|
1402 /** Create a file object and open it in the current working directory. |
|
1403 * |
|
1404 * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. |
|
1405 * |
|
1406 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive |
|
1407 * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). |
|
1408 */ |
|
1409 SdBaseFile::SdBaseFile(const char* path, uint8_t oflag) { |
|
1410 type_ = FAT_FILE_TYPE_CLOSED; |
|
1411 writeError = false; |
|
1412 open(path, oflag); |
|
1413 } |
|
1414 //------------------------------------------------------------------------------ |
|
1415 /** Sets a file's position. |
|
1416 * |
|
1417 * \param[in] pos The new position in bytes from the beginning of the file. |
|
1418 * |
|
1419 * \return The value one, true, is returned for success and |
|
1420 * the value zero, false, is returned for failure. |
|
1421 */ |
|
1422 bool SdBaseFile::seekSet(uint32_t pos) { |
|
1423 uint32_t nCur; |
|
1424 uint32_t nNew; |
|
1425 // error if file not open or seek past end of file |
|
1426 if (!isOpen() || pos > fileSize_) goto fail; |
|
1427 |
|
1428 if (type_ == FAT_FILE_TYPE_ROOT_FIXED) { |
|
1429 curPosition_ = pos; |
|
1430 goto done; |
|
1431 } |
|
1432 if (pos == 0) { |
|
1433 // set position to start of file |
|
1434 curCluster_ = 0; |
|
1435 curPosition_ = 0; |
|
1436 goto done; |
|
1437 } |
|
1438 // calculate cluster index for cur and new position |
|
1439 nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); |
|
1440 nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); |
|
1441 |
|
1442 if (nNew < nCur || curPosition_ == 0) { |
|
1443 // must follow chain from first cluster |
|
1444 curCluster_ = firstCluster_; |
|
1445 } else { |
|
1446 // advance from curPosition |
|
1447 nNew -= nCur; |
|
1448 } |
|
1449 while (nNew--) { |
|
1450 if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail; |
|
1451 } |
|
1452 curPosition_ = pos; |
|
1453 |
|
1454 done: |
|
1455 return true; |
|
1456 |
|
1457 fail: |
|
1458 return false; |
|
1459 } |
|
1460 //------------------------------------------------------------------------------ |
|
1461 void SdBaseFile::setpos(fpos_t* pos) { |
|
1462 curPosition_ = pos->position; |
|
1463 curCluster_ = pos->cluster; |
|
1464 } |
|
1465 //------------------------------------------------------------------------------ |
|
1466 /** The sync() call causes all modified data and directory fields |
|
1467 * to be written to the storage device. |
|
1468 * |
|
1469 * \return The value one, true, is returned for success and |
|
1470 * the value zero, false, is returned for failure. |
|
1471 * Reasons for failure include a call to sync() before a file has been |
|
1472 * opened or an I/O error. |
|
1473 */ |
|
1474 bool SdBaseFile::sync() { |
|
1475 // only allow open files and directories |
|
1476 if (!isOpen()) goto fail; |
|
1477 |
|
1478 if (flags_ & F_FILE_DIR_DIRTY) { |
|
1479 dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
1480 // check for deleted by another open file object |
|
1481 if (!d || d->name[0] == DIR_NAME_DELETED) goto fail; |
|
1482 |
|
1483 // do not set filesize for dir files |
|
1484 if (!isDir()) d->fileSize = fileSize_; |
|
1485 |
|
1486 // update first cluster fields |
|
1487 d->firstClusterLow = firstCluster_ & 0XFFFF; |
|
1488 d->firstClusterHigh = firstCluster_ >> 16; |
|
1489 |
|
1490 // set modify time if user supplied a callback date/time function |
|
1491 if (dateTime_) { |
|
1492 dateTime_(&d->lastWriteDate, &d->lastWriteTime); |
|
1493 d->lastAccessDate = d->lastWriteDate; |
|
1494 } |
|
1495 // clear directory dirty |
|
1496 flags_ &= ~F_FILE_DIR_DIRTY; |
|
1497 } |
|
1498 return vol_->cacheFlush(); |
|
1499 |
|
1500 fail: |
|
1501 writeError = true; |
|
1502 return false; |
|
1503 } |
|
1504 //------------------------------------------------------------------------------ |
|
1505 /** Copy a file's timestamps |
|
1506 * |
|
1507 * \param[in] file File to copy timestamps from. |
|
1508 * |
|
1509 * \note |
|
1510 * Modify and access timestamps may be overwritten if a date time callback |
|
1511 * function has been set by dateTimeCallback(). |
|
1512 * |
|
1513 * \return The value one, true, is returned for success and |
|
1514 * the value zero, false, is returned for failure. |
|
1515 */ |
|
1516 bool SdBaseFile::timestamp(SdBaseFile* file) { |
|
1517 dir_t* d; |
|
1518 dir_t dir; |
|
1519 |
|
1520 // get timestamps |
|
1521 if (!file->dirEntry(&dir)) goto fail; |
|
1522 |
|
1523 // update directory fields |
|
1524 if (!sync()) goto fail; |
|
1525 |
|
1526 d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
1527 if (!d) goto fail; |
|
1528 |
|
1529 // copy timestamps |
|
1530 d->lastAccessDate = dir.lastAccessDate; |
|
1531 d->creationDate = dir.creationDate; |
|
1532 d->creationTime = dir.creationTime; |
|
1533 d->creationTimeTenths = dir.creationTimeTenths; |
|
1534 d->lastWriteDate = dir.lastWriteDate; |
|
1535 d->lastWriteTime = dir.lastWriteTime; |
|
1536 |
|
1537 // write back entry |
|
1538 return vol_->cacheFlush(); |
|
1539 |
|
1540 fail: |
|
1541 return false; |
|
1542 } |
|
1543 //------------------------------------------------------------------------------ |
|
1544 /** Set a file's timestamps in its directory entry. |
|
1545 * |
|
1546 * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive |
|
1547 * OR of flags from the following list |
|
1548 * |
|
1549 * T_ACCESS - Set the file's last access date. |
|
1550 * |
|
1551 * T_CREATE - Set the file's creation date and time. |
|
1552 * |
|
1553 * T_WRITE - Set the file's last write/modification date and time. |
|
1554 * |
|
1555 * \param[in] year Valid range 1980 - 2107 inclusive. |
|
1556 * |
|
1557 * \param[in] month Valid range 1 - 12 inclusive. |
|
1558 * |
|
1559 * \param[in] day Valid range 1 - 31 inclusive. |
|
1560 * |
|
1561 * \param[in] hour Valid range 0 - 23 inclusive. |
|
1562 * |
|
1563 * \param[in] minute Valid range 0 - 59 inclusive. |
|
1564 * |
|
1565 * \param[in] second Valid range 0 - 59 inclusive |
|
1566 * |
|
1567 * \note It is possible to set an invalid date since there is no check for |
|
1568 * the number of days in a month. |
|
1569 * |
|
1570 * \note |
|
1571 * Modify and access timestamps may be overwritten if a date time callback |
|
1572 * function has been set by dateTimeCallback(). |
|
1573 * |
|
1574 * \return The value one, true, is returned for success and |
|
1575 * the value zero, false, is returned for failure. |
|
1576 */ |
|
1577 bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, |
|
1578 uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { |
|
1579 uint16_t dirDate; |
|
1580 uint16_t dirTime; |
|
1581 dir_t* d; |
|
1582 |
|
1583 if (!isOpen() |
|
1584 || year < 1980 |
|
1585 || year > 2107 |
|
1586 || month < 1 |
|
1587 || month > 12 |
|
1588 || day < 1 |
|
1589 || day > 31 |
|
1590 || hour > 23 |
|
1591 || minute > 59 |
|
1592 || second > 59) { |
|
1593 goto fail; |
|
1594 } |
|
1595 // update directory entry |
|
1596 if (!sync()) goto fail; |
|
1597 |
|
1598 d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); |
|
1599 if (!d) goto fail; |
|
1600 |
|
1601 dirDate = FAT_DATE(year, month, day); |
|
1602 dirTime = FAT_TIME(hour, minute, second); |
|
1603 if (flags & T_ACCESS) { |
|
1604 d->lastAccessDate = dirDate; |
|
1605 } |
|
1606 if (flags & T_CREATE) { |
|
1607 d->creationDate = dirDate; |
|
1608 d->creationTime = dirTime; |
|
1609 // seems to be units of 1/100 second not 1/10 as Microsoft states |
|
1610 d->creationTimeTenths = second & 1 ? 100 : 0; |
|
1611 } |
|
1612 if (flags & T_WRITE) { |
|
1613 d->lastWriteDate = dirDate; |
|
1614 d->lastWriteTime = dirTime; |
|
1615 } |
|
1616 return vol_->cacheFlush(); |
|
1617 |
|
1618 fail: |
|
1619 return false; |
|
1620 } |
|
1621 //------------------------------------------------------------------------------ |
|
1622 /** Truncate a file to a specified length. The current file position |
|
1623 * will be maintained if it is less than or equal to \a length otherwise |
|
1624 * it will be set to end of file. |
|
1625 * |
|
1626 * \param[in] length The desired length for the file. |
|
1627 * |
|
1628 * \return The value one, true, is returned for success and |
|
1629 * the value zero, false, is returned for failure. |
|
1630 * Reasons for failure include file is read only, file is a directory, |
|
1631 * \a length is greater than the current file size or an I/O error occurs. |
|
1632 */ |
|
1633 bool SdBaseFile::truncate(uint32_t length) { |
|
1634 uint32_t newPos; |
|
1635 // error if not a normal file or read-only |
|
1636 if (!isFile() || !(flags_ & O_WRITE)) goto fail; |
|
1637 |
|
1638 // error if length is greater than current size |
|
1639 if (length > fileSize_) goto fail; |
|
1640 |
|
1641 // fileSize and length are zero - nothing to do |
|
1642 if (fileSize_ == 0) return true; |
|
1643 |
|
1644 // remember position for seek after truncation |
|
1645 newPos = curPosition_ > length ? length : curPosition_; |
|
1646 |
|
1647 // position to last cluster in truncated file |
|
1648 if (!seekSet(length)) goto fail; |
|
1649 |
|
1650 if (length == 0) { |
|
1651 // free all clusters |
|
1652 if (!vol_->freeChain(firstCluster_)) goto fail; |
|
1653 firstCluster_ = 0; |
|
1654 } else { |
|
1655 uint32_t toFree; |
|
1656 if (!vol_->fatGet(curCluster_, &toFree)) goto fail; |
|
1657 |
|
1658 if (!vol_->isEOC(toFree)) { |
|
1659 // free extra clusters |
|
1660 if (!vol_->freeChain(toFree)) goto fail; |
|
1661 |
|
1662 // current cluster is end of chain |
|
1663 if (!vol_->fatPutEOC(curCluster_)) goto fail; |
|
1664 } |
|
1665 } |
|
1666 fileSize_ = length; |
|
1667 |
|
1668 // need to update directory entry |
|
1669 flags_ |= F_FILE_DIR_DIRTY; |
|
1670 |
|
1671 if (!sync()) goto fail; |
|
1672 |
|
1673 // set file to correct position |
|
1674 return seekSet(newPos); |
|
1675 |
|
1676 fail: |
|
1677 return false; |
|
1678 } |
|
1679 //------------------------------------------------------------------------------ |
|
1680 /** Write data to an open file. |
|
1681 * |
|
1682 * \note Data is moved to the cache but may not be written to the |
|
1683 * storage device until sync() is called. |
|
1684 * |
|
1685 * \param[in] buf Pointer to the location of the data to be written. |
|
1686 * |
|
1687 * \param[in] nbyte Number of bytes to write. |
|
1688 * |
|
1689 * \return For success write() returns the number of bytes written, always |
|
1690 * \a nbyte. If an error occurs, write() returns -1. Possible errors |
|
1691 * include write() is called before a file has been opened, write is called |
|
1692 * for a read-only file, device is full, a corrupt file system or an I/O error. |
|
1693 * |
|
1694 */ |
|
1695 int16_t SdBaseFile::write(const void* buf, uint16_t nbyte) { |
|
1696 // convert void* to uint8_t* - must be before goto statements |
|
1697 const uint8_t* src = reinterpret_cast<const uint8_t*>(buf); |
|
1698 |
|
1699 // number of bytes left to write - must be before goto statements |
|
1700 uint16_t nToWrite = nbyte; |
|
1701 |
|
1702 // error if not a normal file or is read-only |
|
1703 if (!isFile() || !(flags_ & O_WRITE)) goto fail; |
|
1704 |
|
1705 // seek to end of file if append flag |
|
1706 if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { |
|
1707 if (!seekEnd()) goto fail; |
|
1708 } |
|
1709 |
|
1710 while (nToWrite > 0) { |
|
1711 uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); |
|
1712 uint16_t blockOffset = curPosition_ & 0X1FF; |
|
1713 if (blockOfCluster == 0 && blockOffset == 0) { |
|
1714 // start of new cluster |
|
1715 if (curCluster_ == 0) { |
|
1716 if (firstCluster_ == 0) { |
|
1717 // allocate first cluster of file |
|
1718 if (!addCluster()) goto fail; |
|
1719 } else { |
|
1720 curCluster_ = firstCluster_; |
|
1721 } |
|
1722 } else { |
|
1723 uint32_t next; |
|
1724 if (!vol_->fatGet(curCluster_, &next)) goto fail; |
|
1725 if (vol_->isEOC(next)) { |
|
1726 // add cluster if at end of chain |
|
1727 if (!addCluster()) goto fail; |
|
1728 } else { |
|
1729 curCluster_ = next; |
|
1730 } |
|
1731 } |
|
1732 } |
|
1733 // max space in block |
|
1734 uint16_t n = 512 - blockOffset; |
|
1735 |
|
1736 // lesser of space and amount to write |
|
1737 if (n > nToWrite) n = nToWrite; |
|
1738 |
|
1739 // block for data write |
|
1740 uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; |
|
1741 if (n == 512) { |
|
1742 // full block - don't need to use cache |
|
1743 if (vol_->cacheBlockNumber() == block) { |
|
1744 // invalidate cache if block is in cache |
|
1745 vol_->cacheSetBlockNumber(0XFFFFFFFF, false); |
|
1746 } |
|
1747 if (!vol_->writeBlock(block, src)) goto fail; |
|
1748 } else { |
|
1749 if (blockOffset == 0 && curPosition_ >= fileSize_) { |
|
1750 // start of new block don't need to read into cache |
|
1751 if (!vol_->cacheFlush()) goto fail; |
|
1752 // set cache dirty and SD address of block |
|
1753 vol_->cacheSetBlockNumber(block, true); |
|
1754 } else { |
|
1755 // rewrite part of block |
|
1756 if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; |
|
1757 } |
|
1758 uint8_t* dst = vol_->cache()->data + blockOffset; |
|
1759 memcpy(dst, src, n); |
|
1760 } |
|
1761 curPosition_ += n; |
|
1762 src += n; |
|
1763 nToWrite -= n; |
|
1764 } |
|
1765 if (curPosition_ > fileSize_) { |
|
1766 // update fileSize and insure sync will update dir entry |
|
1767 fileSize_ = curPosition_; |
|
1768 flags_ |= F_FILE_DIR_DIRTY; |
|
1769 } else if (dateTime_ && nbyte) { |
|
1770 // insure sync will update modified date and time |
|
1771 flags_ |= F_FILE_DIR_DIRTY; |
|
1772 } |
|
1773 |
|
1774 if (flags_ & O_SYNC) { |
|
1775 if (!sync()) goto fail; |
|
1776 } |
|
1777 return nbyte; |
|
1778 |
|
1779 fail: |
|
1780 // return for write error |
|
1781 writeError = true; |
|
1782 return -1; |
|
1783 } |
|
1784 //------------------------------------------------------------------------------ |
|
1785 // suppress cpplint warnings with NOLINT comment |
|
1786 #if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN) |
|
1787 void (*SdBaseFile::oldDateTime_)(uint16_t& date, uint16_t& time) = 0; // NOLINT |
|
1788 #endif // ALLOW_DEPRECATED_FUNCTIONS |
|
1789 |
|
1790 |
|
1791 #endif |