You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
6.7KB

  1. /* FatLib Library
  2. * Copyright (C) 2012 by William Greiman
  3. *
  4. * This file is part of the FatLib 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 FatLib Library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include "FatFile.h"
  21. #include "FatFileSystem.h"
  22. //------------------------------------------------------------------------------
  23. bool FatFile::getSFN(char* name) {
  24. dir_t* dir;
  25. if (!isOpen()) {
  26. DBG_FAIL_MACRO;
  27. goto fail;
  28. }
  29. if (isRoot()) {
  30. name[0] = '/';
  31. name[1] = '\0';
  32. return true;
  33. }
  34. // cache entry
  35. dir = cacheDirEntry(FatCache::CACHE_FOR_READ);
  36. if (!dir) {
  37. DBG_FAIL_MACRO;
  38. goto fail;
  39. }
  40. // format name
  41. dirName(dir, name);
  42. return true;
  43. fail:
  44. return false;
  45. }
  46. //------------------------------------------------------------------------------
  47. size_t FatFile::printSFN(print_t* pr) {
  48. char name[13];
  49. if (!getSFN(name)) {
  50. DBG_FAIL_MACRO;
  51. goto fail;
  52. }
  53. return pr->write(name);
  54. fail:
  55. return 0;
  56. }
  57. #if !USE_LONG_FILE_NAMES
  58. //------------------------------------------------------------------------------
  59. bool FatFile::getName(char* name, size_t size) {
  60. return size < 13 ? 0 : getSFN(name);
  61. }
  62. //------------------------------------------------------------------------------
  63. // format directory name field from a 8.3 name string
  64. bool FatFile::parsePathName(const char* path, fname_t* fname,
  65. const char** ptr) {
  66. uint8_t uc = 0;
  67. uint8_t lc = 0;
  68. uint8_t bit = FNAME_FLAG_LC_BASE;
  69. // blank fill name and extension
  70. for (uint8_t i = 0; i < 11; i++) {
  71. fname->sfn[i] = ' ';
  72. }
  73. for (uint8_t i = 0, n = 7;; path++) {
  74. uint8_t c = *path;
  75. if (c == 0 || isDirSeparator(c)) {
  76. // Done.
  77. break;
  78. }
  79. if (c == '.' && n == 7) {
  80. n = 10; // max index for full 8.3 name
  81. i = 8; // place for extension
  82. // bit for extension.
  83. bit = FNAME_FLAG_LC_EXT;
  84. } else {
  85. if (!legal83Char(c) || i > n) {
  86. DBG_FAIL_MACRO;
  87. goto fail;
  88. }
  89. if ('a' <= c && c <= 'z') {
  90. c += 'A' - 'a';
  91. lc |= bit;
  92. } else if ('A' <= c && c <= 'Z') {
  93. uc |= bit;
  94. }
  95. fname->sfn[i++] = c;
  96. }
  97. }
  98. // must have a file name, extension is optional
  99. if (fname->sfn[0] == ' ') {
  100. DBG_FAIL_MACRO;
  101. goto fail;
  102. }
  103. // Set base-name and extension bits.
  104. fname->flags = lc & uc ? 0 : lc;
  105. while (isDirSeparator(*path)) {
  106. path++;
  107. }
  108. *ptr = path;
  109. return true;
  110. fail:
  111. return false;
  112. }
  113. //------------------------------------------------------------------------------
  114. // open with filename in fname
  115. #define SFN_OPEN_USES_CHKSUM 0
  116. bool FatFile::open(FatFile* dirFile, fname_t* fname, uint8_t oflag) {
  117. bool emptyFound = false;
  118. #if SFN_OPEN_USES_CHKSUM
  119. uint8_t chksum;
  120. #endif
  121. uint8_t lfnOrd = 0;
  122. uint16_t emptyIndex;
  123. uint16_t index = 0;
  124. dir_t* dir;
  125. ldir_t* ldir;
  126. dirFile->rewind();
  127. while (1) {
  128. if (!emptyFound) {
  129. emptyIndex = index;
  130. }
  131. dir = dirFile->readDirCache(true);
  132. if (!dir) {
  133. if (dirFile->getError()) {
  134. DBG_FAIL_MACRO;
  135. goto fail;
  136. }
  137. // At EOF if no error.
  138. break;
  139. }
  140. if (dir->name[0] == DIR_NAME_FREE) {
  141. emptyFound = true;
  142. break;
  143. }
  144. if (dir->name[0] == DIR_NAME_DELETED) {
  145. lfnOrd = 0;
  146. emptyFound = true;
  147. } else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
  148. if (!memcmp(fname->sfn, dir->name, 11)) {
  149. // don't open existing file if O_EXCL
  150. if (oflag & O_EXCL) {
  151. DBG_FAIL_MACRO;
  152. goto fail;
  153. }
  154. #if SFN_OPEN_USES_CHKSUM
  155. if (lfnOrd && chksum != lfnChecksum(dir->name)) {
  156. DBG_FAIL_MACRO;
  157. goto fail;
  158. }
  159. #endif // SFN_OPEN_USES_CHKSUM
  160. if (!openCachedEntry(dirFile, index, oflag, lfnOrd)) {
  161. DBG_FAIL_MACRO;
  162. goto fail;
  163. }
  164. return true;
  165. } else {
  166. lfnOrd = 0;
  167. }
  168. } else if (DIR_IS_LONG_NAME(dir)) {
  169. ldir = reinterpret_cast<ldir_t*>(dir);
  170. if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
  171. lfnOrd = ldir->ord & 0X1F;
  172. #if SFN_OPEN_USES_CHKSUM
  173. chksum = ldir->chksum;
  174. #endif // SFN_OPEN_USES_CHKSUM
  175. }
  176. } else {
  177. lfnOrd = 0;
  178. }
  179. index++;
  180. }
  181. // don't create unless O_CREAT and O_WRITE
  182. if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) {
  183. DBG_FAIL_MACRO;
  184. goto fail;
  185. }
  186. if (emptyFound) {
  187. index = emptyIndex;
  188. } else {
  189. if (!dirFile->addDirCluster()) {
  190. DBG_FAIL_MACRO;
  191. goto fail;
  192. }
  193. }
  194. if (!dirFile->seekSet(32UL*index)) {
  195. DBG_FAIL_MACRO;
  196. goto fail;
  197. }
  198. dir = dirFile->readDirCache();
  199. if (!dir) {
  200. DBG_FAIL_MACRO;
  201. goto fail;
  202. }
  203. // initialize as empty file
  204. memset(dir, 0, sizeof(dir_t));
  205. memcpy(dir->name, fname->sfn, 11);
  206. // Set base-name and extension lower case bits.
  207. dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;
  208. // set timestamps
  209. if (m_dateTime) {
  210. // call user date/time function
  211. m_dateTime(&dir->creationDate, &dir->creationTime);
  212. } else {
  213. // use default date/time
  214. dir->creationDate = FAT_DEFAULT_DATE;
  215. dir->creationTime = FAT_DEFAULT_TIME;
  216. }
  217. dir->lastAccessDate = dir->creationDate;
  218. dir->lastWriteDate = dir->creationDate;
  219. dir->lastWriteTime = dir->creationTime;
  220. // Force write of entry to device.
  221. dirFile->m_vol->cacheDirty();
  222. // open entry in cache.
  223. return openCachedEntry(dirFile, index, oflag, 0);
  224. fail:
  225. return false;
  226. }
  227. //------------------------------------------------------------------------------
  228. size_t FatFile::printName(print_t* pr) {
  229. return printSFN(pr);
  230. }
  231. //------------------------------------------------------------------------------
  232. bool FatFile::remove() {
  233. dir_t* dir;
  234. // Can't remove if LFN or not open for write.
  235. if (!isFile() || isLFN() || !(m_flags & O_WRITE)) {
  236. DBG_FAIL_MACRO;
  237. goto fail;
  238. }
  239. // Free any clusters.
  240. if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
  241. DBG_FAIL_MACRO;
  242. goto fail;
  243. }
  244. // Cache directory entry.
  245. dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
  246. if (!dir) {
  247. DBG_FAIL_MACRO;
  248. goto fail;
  249. }
  250. // Mark entry deleted.
  251. dir->name[0] = DIR_NAME_DELETED;
  252. // Set this file closed.
  253. m_attr = FILE_ATTR_CLOSED;
  254. // Write entry to device.
  255. return m_vol->cacheSync();
  256. fail:
  257. return false;
  258. }
  259. #endif // !USE_LONG_FILE_NAMES