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.

375 lines
12KB

  1. /**
  2. * Copyright (c) 2011-2019 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #ifndef FsVolume_h
  26. #define FsVolume_h
  27. /**
  28. * \file
  29. * \brief FsVolume include file.
  30. */
  31. #include "FsNew.h"
  32. #include "../FatLib/FatLib.h"
  33. #include "../ExFatLib/ExFatLib.h"
  34. class FsFile;
  35. /**
  36. * \class FsVolume
  37. * \brief FsVolume class.
  38. */
  39. class FsVolume {
  40. public:
  41. FsVolume() : m_fVol(nullptr), m_xVol(nullptr) {}
  42. ~FsVolume() {end();}
  43. /**
  44. * Initialize an FatVolume object.
  45. * \param[in] blockDev Device block driver.
  46. * \return true for success or false for failure.
  47. */
  48. bool begin(BlockDevice* blockDev);
  49. /** \return the number of bytes in a cluster. */
  50. uint32_t bytesPerCluster() {
  51. return m_fVol ? m_fVol->bytesPerCluster() :
  52. m_xVol ? m_xVol->bytesPerCluster() : 0;
  53. }
  54. /** \return current working volume. */
  55. static FsVolume* cwv() {return m_cwv;}
  56. /** Change global working volume to this volume. */
  57. void chvol() {m_cwv = this;}
  58. /** \return The total number of clusters in the volume. */
  59. uint32_t clusterCount() {
  60. return m_fVol ? m_fVol->clusterCount() :
  61. m_xVol ? m_xVol->clusterCount() : 0;
  62. }
  63. /** \return The logical sector number for the start of file data. */
  64. uint32_t dataStartSector() const {
  65. return m_fVol ? m_fVol->dataStartSector() :
  66. m_xVol ? m_xVol->clusterHeapStartSector() : 0;
  67. }
  68. /** \return The logical sector number for the start of the first FAT. */
  69. uint32_t fatStartSector() const {
  70. return m_fVol ? m_fVol->fatStartSector() :
  71. m_xVol ? m_xVol->fatStartSector() : 0;
  72. }
  73. /** \return the free cluster count. */
  74. uint32_t freeClusterCount() {
  75. return m_fVol ? m_fVol->freeClusterCount() :
  76. m_xVol ? m_xVol->freeClusterCount() : 0;
  77. }
  78. /** \return The volume's cluster size in sectors. */
  79. uint32_t sectorsPerCluster() const {
  80. return m_fVol ? m_fVol->sectorsPerCluster() :
  81. m_xVol ? m_xVol->sectorsPerCluster() : 0;
  82. }
  83. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  84. // Use sectorsPerCluster(). blocksPerCluster() will be removed in the future.
  85. uint32_t blocksPerCluster() __attribute__ ((deprecated)) {return sectorsPerCluster();} //NOLINT
  86. #endif // DOXYGEN_SHOULD_SKIP_THIS
  87. /**
  88. * Set volume working directory to root.
  89. * \return true for success or false for failure.
  90. */
  91. bool chdir() {
  92. return m_fVol ? m_fVol->chdir() :
  93. m_xVol ? m_xVol->chdir() : false;
  94. }
  95. /**
  96. * Set volume working directory.
  97. * \param[in] path Path for volume working directory.
  98. * \return true for success or false for failure.
  99. */
  100. bool chdir(const char* path) {
  101. return m_fVol ? m_fVol->chdir(path) :
  102. m_xVol ? m_xVol->chdir(path) : false;
  103. }
  104. /** free dynamic memory and end access to volume */
  105. void end() {
  106. m_fVol = nullptr;
  107. m_xVol = nullptr;
  108. }
  109. /** Test for the existence of a file in a directory
  110. *
  111. * \param[in] path Path of the file to be tested for.
  112. *
  113. * \return true if the file exists else false.
  114. */
  115. bool exists(const char* path) {
  116. return m_fVol ? m_fVol->exists(path) :
  117. m_xVol ? m_xVol->exists(path) : false;
  118. }
  119. /** \return Partition type, FAT_TYPE_EXFAT, FAT_TYPE_FAT32,
  120. * FAT_TYPE_FAT16, or zero for error.
  121. */
  122. uint8_t fatType() const {
  123. return m_fVol ? m_fVol->fatType() :
  124. m_xVol ? m_xVol->fatType() : 0;
  125. }
  126. /** List directory contents.
  127. *
  128. * \param[in] pr Print object.
  129. *
  130. * \return true for success or false for failure.
  131. */
  132. bool ls(print_t* pr) {
  133. return m_fVol ? m_fVol->ls(pr) :
  134. m_xVol ? m_xVol->ls(pr) : false;
  135. }
  136. /** List directory contents.
  137. *
  138. * \param[in] pr Print object.
  139. * \param[in] flags The inclusive OR of
  140. *
  141. * LS_DATE - %Print file modification date
  142. *
  143. * LS_SIZE - %Print file size.
  144. *
  145. * LS_R - Recursive list of subdirectories.
  146. *
  147. * \return true for success or false for failure.
  148. */
  149. bool ls(print_t* pr, uint8_t flags) {
  150. return m_fVol ? m_fVol->ls(pr, flags) :
  151. m_xVol ? m_xVol->ls(pr, flags) : false;
  152. }
  153. /** List the directory contents of a directory.
  154. *
  155. * \param[in] pr Print stream for list.
  156. *
  157. * \param[in] path directory to list.
  158. *
  159. * \param[in] flags The inclusive OR of
  160. *
  161. * LS_DATE - %Print file modification date
  162. *
  163. * LS_SIZE - %Print file size.
  164. *
  165. * LS_R - Recursive list of subdirectories.
  166. *
  167. * \return true for success or false for failure.
  168. */
  169. bool ls(print_t* pr, const char* path, uint8_t flags);
  170. /** Make a subdirectory in the volume root directory.
  171. *
  172. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  173. *
  174. * \param[in] pFlag Create missing parent directories if true.
  175. *
  176. * \return true for success or false for failure.
  177. */
  178. bool mkdir(const char *path, bool pFlag = true) {
  179. return m_fVol ? m_fVol->mkdir(path, pFlag) :
  180. m_xVol ? m_xVol->mkdir(path, pFlag) : false;
  181. }
  182. /** open a file
  183. *
  184. * \param[in] path location of file to be opened.
  185. * \param[in] oflag open flags.
  186. * \return a FsBaseFile object.
  187. */
  188. FsFile open(const char* path, oflag_t oflag = O_RDONLY);
  189. /** Remove a file from the volume root directory.
  190. *
  191. * \param[in] path A path with a valid 8.3 DOS name for the file.
  192. *
  193. * \return true for success or false for failure.
  194. */
  195. bool remove(const char *path) {
  196. return m_fVol ? m_fVol->remove(path) :
  197. m_xVol ? m_xVol->remove(path) : false;
  198. }
  199. /** Rename a file or subdirectory.
  200. *
  201. * \param[in] oldPath Path name to the file or subdirectory to be renamed.
  202. *
  203. * \param[in] newPath New path name of the file or subdirectory.
  204. *
  205. * The \a newPath object must not exist before the rename call.
  206. *
  207. * The file to be renamed must not be open. The directory entry may be
  208. * moved and file system corruption could occur if the file is accessed by
  209. * a file object that was opened before the rename() call.
  210. *
  211. * \return true for success or false for failure.
  212. */
  213. bool rename(const char *oldPath, const char *newPath) {
  214. return m_fVol ? m_fVol->rename(oldPath, newPath) :
  215. m_xVol ? m_xVol->rename(oldPath, newPath) : false;
  216. }
  217. /** Remove a subdirectory from the volume's root directory.
  218. *
  219. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  220. *
  221. * The subdirectory file will be removed only if it is empty.
  222. *
  223. * \return true for success or false for failure.
  224. */
  225. bool rmdir(const char *path) {
  226. return m_fVol ? m_fVol->rmdir(path) :
  227. m_xVol ? m_xVol->rmdir(path) : false;
  228. }
  229. #if ENABLE_ARDUINO_SERIAL
  230. /** List directory contents.
  231. * \return true for success or false for failure.
  232. */
  233. bool ls() {
  234. return ls(&Serial);
  235. }
  236. /** List directory contents.
  237. *
  238. * \param[in] flags The inclusive OR of
  239. *
  240. * LS_DATE - %Print file modification date
  241. *
  242. * LS_SIZE - %Print file size.
  243. *
  244. * LS_R - Recursive list of subdirectories.
  245. *
  246. * \return true for success or false for failure.
  247. */
  248. bool ls(uint8_t flags) {
  249. return ls(&Serial, flags);
  250. }
  251. /** List the directory contents of a directory to Serial.
  252. *
  253. * \param[in] path directory to list.
  254. *
  255. * \param[in] flags The inclusive OR of
  256. *
  257. * LS_DATE - %Print file modification date
  258. *
  259. * LS_SIZE - %Print file size.
  260. *
  261. * LS_R - Recursive list of subdirectories.
  262. *
  263. * \return true for success or false for failure.
  264. *
  265. * \return true for success or false for failure.
  266. */
  267. bool ls(const char* path, uint8_t flags = 0) {
  268. return ls(&Serial, path, flags);
  269. }
  270. #endif // ENABLE_ARDUINO_SERIAL
  271. #if ENABLE_ARDUINO_STRING
  272. /**
  273. * Set volume working directory.
  274. * \param[in] path Path for volume working directory.
  275. * \return true for success or false for failure.
  276. */
  277. bool chdir(const String& path) {
  278. return chdir(path.c_str());
  279. }
  280. /** Test for the existence of a file in a directory
  281. *
  282. * \param[in] path Path of the file to be tested for.
  283. *
  284. * \return true if the file exists else false.
  285. */
  286. bool exists(const String &path) {
  287. return exists(path.c_str());
  288. }
  289. /** Make a subdirectory in the volume root directory.
  290. *
  291. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  292. *
  293. * \param[in] pFlag Create missing parent directories if true.
  294. *
  295. * \return true for success or false for failure.
  296. */
  297. bool mkdir(const String &path, bool pFlag = true) {
  298. return mkdir(path.c_str(), pFlag);
  299. }
  300. /** open a file
  301. *
  302. * \param[in] path location of file to be opened.
  303. * \param[in] oflag open flags.
  304. * \return a FsBaseFile object.
  305. */
  306. FsFile open(const String &path, oflag_t oflag = O_RDONLY);
  307. /** Remove a file from the volume root directory.
  308. *
  309. * \param[in] path A path with a valid 8.3 DOS name for the file.
  310. *
  311. * \return true for success or false for failure.
  312. */
  313. bool remove(const String &path) {
  314. return remove(path.c_str());
  315. }
  316. /** Rename a file or subdirectory.
  317. *
  318. * \param[in] oldPath Path name to the file or subdirectory to be renamed.
  319. *
  320. * \param[in] newPath New path name of the file or subdirectory.
  321. *
  322. * The \a newPath object must not exist before the rename call.
  323. *
  324. * The file to be renamed must not be open. The directory entry may be
  325. * moved and file system corruption could occur if the file is accessed by
  326. * a file object that was opened before the rename() call.
  327. *
  328. * \return true for success or false for failure.
  329. */
  330. bool rename(const String& oldPath, const String& newPath) {
  331. return rename(oldPath.c_str(), newPath.c_str());
  332. }
  333. /** Remove a subdirectory from the volume's root directory.
  334. *
  335. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  336. *
  337. * The subdirectory file will be removed only if it is empty.
  338. *
  339. * \return true for success or false for failure.
  340. */
  341. bool rmdir(const String &path) {
  342. return rmdir(path.c_str());
  343. }
  344. /** Rename a file or subdirectory.
  345. *
  346. * \param[in] oldPath Path name to the file or subdirectory to be renamed.
  347. *
  348. * \param[in] newPath New path name of the file or subdirectory.
  349. *
  350. * The \a newPath object must not exist before the rename call.
  351. *
  352. * The file to be renamed must not be open. The directory entry may be
  353. * moved and file system corruption could occur if the file is accessed by
  354. * a file object that was opened before the rename() call.
  355. *
  356. * \return true for success or false for failure.
  357. */
  358. #endif // ENABLE_ARDUINO_STRING
  359. private:
  360. /** FsBaseFile allowed access to private members. */
  361. friend class FsBaseFile;
  362. static FsVolume* m_cwv;
  363. FsVolume(const FsVolume& from);
  364. FsVolume& operator=(const FsVolume& from);
  365. newalign_t m_volMem[FS_ALIGN_DIM(ExFatVolume, FatVolume)];
  366. FatVolume* m_fVol;
  367. ExFatVolume* m_xVol;
  368. BlockDevice* m_blockDev;
  369. };
  370. #endif // FsVolume_h