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.

пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
пре 10 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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