FsVolume.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /**
  2. * Copyright (c) 2011-2022 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() {}
  42. ~FsVolume() {end();}
  43. /** Get file's user settable attributes.
  44. * \param[in] path path to file.
  45. * \return user settable file attributes for success else -1.
  46. */
  47. int attrib(const char* path) {
  48. return m_fVol ? m_fVol->attrib(path) :
  49. m_xVol ? m_xVol->attrib(path) : -1;
  50. }
  51. /** Set file's user settable attributes.
  52. * \param[in] path path to file.
  53. * \param[in] bits bit-wise or of selected attributes: FS_ATTRIB_READ_ONLY,
  54. * FS_ATTRIB_HIDDEN, FS_ATTRIB_SYSTEM, FS_ATTRIB_ARCHIVE.
  55. *
  56. * \return true for success or false for failure.
  57. */
  58. bool attrib(const char* path, uint8_t bits) {
  59. return m_fVol ? m_fVol->attrib(path, bits) :
  60. m_xVol ? m_xVol->attrib(path, bits) : false;
  61. }
  62. /**
  63. * Initialize an FatVolume object.
  64. * \param[in] blockDev Device block driver.
  65. * \param[in] setCwv Set current working volume if true.
  66. * \param[in] part partition to initialize.
  67. * \param[in] volStart Start sector of volume if part is zero.
  68. * \return true for success or false for failure.
  69. */
  70. bool begin(FsBlockDevice* blockDev, bool setCwv = true, uint8_t
  71. part = 1, uint32_t volStart = 0);
  72. #ifndef DOXYGEN_SHOULD_SKIP_THIS
  73. uint32_t __attribute__((error("use sectorsPerCluster()"))) blocksPerCluster();
  74. #endif // DOXYGEN_SHOULD_SKIP_THIS
  75. /** \return the number of bytes in a cluster. */
  76. uint32_t bytesPerCluster() const {
  77. return m_fVol ? m_fVol->bytesPerCluster() :
  78. m_xVol ? m_xVol->bytesPerCluster() : 0;
  79. }
  80. /**
  81. * Set volume working directory to root.
  82. * \return true for success or false for failure.
  83. */
  84. bool chdir() {
  85. return m_fVol ? m_fVol->chdir() :
  86. m_xVol ? m_xVol->chdir() : false;
  87. }
  88. /**
  89. * Set volume working directory.
  90. * \param[in] path Path for volume working directory.
  91. * \return true for success or false for failure.
  92. */
  93. bool chdir(const char* path) {
  94. return m_fVol ? m_fVol->chdir(path) :
  95. m_xVol ? m_xVol->chdir(path) : false;
  96. }
  97. /** Change global working volume to this volume. */
  98. void chvol() {m_cwv = this;}
  99. /** \return The total number of clusters in the volume. */
  100. uint32_t clusterCount() const {
  101. return m_fVol ? m_fVol->clusterCount() :
  102. m_xVol ? m_xVol->clusterCount() : 0;
  103. }
  104. /** \return The logical sector number for the start of file data. */
  105. uint32_t dataStartSector() const {
  106. return m_fVol ? m_fVol->dataStartSector() :
  107. m_xVol ? m_xVol->clusterHeapStartSector() : 0;
  108. }
  109. /** End access to volume
  110. * \return pointer to sector size buffer for format.
  111. */
  112. uint8_t* end() {
  113. m_fVol = nullptr;
  114. m_xVol = nullptr;
  115. static_assert(sizeof(m_volMem) >= 512, "m_volMem too small");
  116. return reinterpret_cast<uint8_t*>(m_volMem);
  117. }
  118. /** Test for the existence of a file in a directory
  119. *
  120. * \param[in] path Path of the file to be tested for.
  121. *
  122. * \return true if the file exists else false.
  123. */
  124. bool exists(const char* path) {
  125. return m_fVol ? m_fVol->exists(path) :
  126. m_xVol ? m_xVol->exists(path) : false;
  127. }
  128. /** \return The logical sector number for the start of the first FAT. */
  129. uint32_t fatStartSector() const {
  130. return m_fVol ? m_fVol->fatStartSector() :
  131. m_xVol ? m_xVol->fatStartSector() : 0;
  132. }
  133. /** \return Partition type, FAT_TYPE_EXFAT, FAT_TYPE_FAT32,
  134. * FAT_TYPE_FAT16, or zero for error.
  135. */
  136. uint8_t fatType() const {
  137. return m_fVol ? m_fVol->fatType() :
  138. m_xVol ? m_xVol->fatType() : 0;
  139. }
  140. /** \return free cluster count or -1 if an error occurs. */
  141. int32_t freeClusterCount() const {
  142. return m_fVol ? m_fVol->freeClusterCount() :
  143. m_xVol ? m_xVol->freeClusterCount() : -1;
  144. }
  145. /**
  146. * Check for device busy.
  147. *
  148. * \return true if busy else false.
  149. */
  150. bool isBusy() {
  151. return m_fVol ? m_fVol->isBusy() :
  152. m_xVol ? m_xVol->isBusy() : false;
  153. }
  154. /** List directory contents.
  155. *
  156. * \param[in] pr Print object.
  157. *
  158. * \return true for success or false for failure.
  159. */
  160. bool ls(print_t* pr) {
  161. return m_fVol ? m_fVol->ls(pr) :
  162. m_xVol ? m_xVol->ls(pr) : false;
  163. }
  164. /** List directory contents.
  165. *
  166. * \param[in] pr Print object.
  167. * \param[in] flags The inclusive OR of
  168. *
  169. * LS_DATE - %Print file modification date
  170. *
  171. * LS_SIZE - %Print file size.
  172. *
  173. * LS_R - Recursive list of subdirectories.
  174. *
  175. * \return true for success or false for failure.
  176. */
  177. bool ls(print_t* pr, uint8_t flags) {
  178. return m_fVol ? m_fVol->ls(pr, flags) :
  179. m_xVol ? m_xVol->ls(pr, flags) : false;
  180. }
  181. /** List the directory contents of a directory.
  182. *
  183. * \param[in] pr Print stream for list.
  184. *
  185. * \param[in] path directory to list.
  186. *
  187. * \param[in] flags The inclusive OR of
  188. *
  189. * LS_DATE - %Print file modification date
  190. *
  191. * LS_SIZE - %Print file size.
  192. *
  193. * LS_R - Recursive list of subdirectories.
  194. *
  195. * \return true for success or false for failure.
  196. */
  197. bool ls(print_t* pr, const char* path, uint8_t flags);
  198. /** Make a subdirectory in the volume root directory.
  199. *
  200. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  201. *
  202. * \param[in] pFlag Create missing parent directories if true.
  203. *
  204. * \return true for success or false for failure.
  205. */
  206. bool mkdir(const char *path, bool pFlag = true) {
  207. return m_fVol ? m_fVol->mkdir(path, pFlag) :
  208. m_xVol ? m_xVol->mkdir(path, pFlag) : false;
  209. }
  210. /** open a file
  211. *
  212. * \param[in] path location of file to be opened.
  213. * \param[in] oflag open flags.
  214. * \return a FsBaseFile object.
  215. */
  216. FsFile open(const char* path, oflag_t oflag = O_RDONLY);
  217. /** Remove a file from the volume root directory.
  218. *
  219. * \param[in] path A path with a valid 8.3 DOS name for the file.
  220. *
  221. * \return true for success or false for failure.
  222. */
  223. bool remove(const char *path) {
  224. return m_fVol ? m_fVol->remove(path) :
  225. m_xVol ? m_xVol->remove(path) : false;
  226. }
  227. /** Rename a file or subdirectory.
  228. *
  229. * \param[in] oldPath Path name to the file or subdirectory to be renamed.
  230. *
  231. * \param[in] newPath New path name of the file or subdirectory.
  232. *
  233. * The \a newPath object must not exist before the rename call.
  234. *
  235. * The file to be renamed must not be open. The directory entry may be
  236. * moved and file system corruption could occur if the file is accessed by
  237. * a file object that was opened before the rename() call.
  238. *
  239. * \return true for success or false for failure.
  240. */
  241. bool rename(const char *oldPath, const char *newPath) {
  242. return m_fVol ? m_fVol->rename(oldPath, newPath) :
  243. m_xVol ? m_xVol->rename(oldPath, newPath) : false;
  244. }
  245. /** Remove a subdirectory from the volume's root directory.
  246. *
  247. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  248. *
  249. * The subdirectory file will be removed only if it is empty.
  250. *
  251. * \return true for success or false for failure.
  252. */
  253. bool rmdir(const char *path) {
  254. return m_fVol ? m_fVol->rmdir(path) :
  255. m_xVol ? m_xVol->rmdir(path) : false;
  256. }
  257. /** \return The volume's cluster size in sectors. */
  258. uint32_t sectorsPerCluster() const {
  259. return m_fVol ? m_fVol->sectorsPerCluster() :
  260. m_xVol ? m_xVol->sectorsPerCluster() : 0;
  261. }
  262. #if ENABLE_ARDUINO_SERIAL
  263. /** List directory contents.
  264. * \return true for success or false for failure.
  265. */
  266. bool ls() {
  267. return ls(&Serial);
  268. }
  269. /** List directory contents.
  270. *
  271. * \param[in] flags The inclusive OR of
  272. *
  273. * LS_DATE - %Print file modification date
  274. *
  275. * LS_SIZE - %Print file size.
  276. *
  277. * LS_R - Recursive list of subdirectories.
  278. *
  279. * \return true for success or false for failure.
  280. */
  281. bool ls(uint8_t flags) {
  282. return ls(&Serial, flags);
  283. }
  284. /** List the directory contents of a directory to Serial.
  285. *
  286. * \param[in] path directory to list.
  287. *
  288. * \param[in] flags The inclusive OR of
  289. *
  290. * LS_DATE - %Print file modification date
  291. *
  292. * LS_SIZE - %Print file size.
  293. *
  294. * LS_R - Recursive list of subdirectories.
  295. *
  296. * \return true for success or false for failure.
  297. *
  298. * \return true for success or false for failure.
  299. */
  300. bool ls(const char* path, uint8_t flags = 0) {
  301. return ls(&Serial, path, flags);
  302. }
  303. #endif // ENABLE_ARDUINO_SERIAL
  304. #if ENABLE_ARDUINO_STRING
  305. /**
  306. * Set volume working directory.
  307. * \param[in] path Path for volume working directory.
  308. * \return true for success or false for failure.
  309. */
  310. bool chdir(const String& path) {
  311. return chdir(path.c_str());
  312. }
  313. /** Test for the existence of a file in a directory
  314. *
  315. * \param[in] path Path of the file to be tested for.
  316. *
  317. * \return true if the file exists else false.
  318. */
  319. bool exists(const String &path) {
  320. return exists(path.c_str());
  321. }
  322. /** Make a subdirectory in the volume root directory.
  323. *
  324. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  325. *
  326. * \param[in] pFlag Create missing parent directories if true.
  327. *
  328. * \return true for success or false for failure.
  329. */
  330. bool mkdir(const String &path, bool pFlag = true) {
  331. return mkdir(path.c_str(), pFlag);
  332. }
  333. /** open a file
  334. *
  335. * \param[in] path location of file to be opened.
  336. * \param[in] oflag open flags.
  337. * \return a FsBaseFile object.
  338. */
  339. FsFile open(const String &path, oflag_t oflag = O_RDONLY);
  340. /** Remove a file from the volume root directory.
  341. *
  342. * \param[in] path A path with a valid 8.3 DOS name for the file.
  343. *
  344. * \return true for success or false for failure.
  345. */
  346. bool remove(const String &path) {
  347. return remove(path.c_str());
  348. }
  349. /** Rename a file or subdirectory.
  350. *
  351. * \param[in] oldPath Path name to the file or subdirectory to be renamed.
  352. *
  353. * \param[in] newPath New path name of the file or subdirectory.
  354. *
  355. * The \a newPath object must not exist before the rename call.
  356. *
  357. * The file to be renamed must not be open. The directory entry may be
  358. * moved and file system corruption could occur if the file is accessed by
  359. * a file object that was opened before the rename() call.
  360. *
  361. * \return true for success or false for failure.
  362. */
  363. bool rename(const String& oldPath, const String& newPath) {
  364. return rename(oldPath.c_str(), newPath.c_str());
  365. }
  366. /** Remove a subdirectory from the volume's root directory.
  367. *
  368. * \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
  369. *
  370. * The subdirectory file will be removed only if it is empty.
  371. *
  372. * \return true for success or false for failure.
  373. */
  374. bool rmdir(const String &path) {
  375. return rmdir(path.c_str());
  376. }
  377. /** Rename a file or subdirectory.
  378. *
  379. * \param[in] oldPath Path name to the file or subdirectory to be renamed.
  380. *
  381. * \param[in] newPath New path name of the file or subdirectory.
  382. *
  383. * The \a newPath object must not exist before the rename call.
  384. *
  385. * The file to be renamed must not be open. The directory entry may be
  386. * moved and file system corruption could occur if the file is accessed by
  387. * a file object that was opened before the rename() call.
  388. *
  389. * \return true for success or false for failure.
  390. */
  391. #endif // ENABLE_ARDUINO_STRING
  392. protected:
  393. newalign_t m_volMem[FS_ALIGN_DIM(ExFatVolume, FatVolume)];
  394. private:
  395. /** FsBaseFile allowed access to private members. */
  396. friend class FsBaseFile;
  397. static FsVolume* cwv() {return m_cwv;}
  398. FsVolume(const FsVolume& from);
  399. FsVolume& operator=(const FsVolume& from);
  400. static FsVolume* m_cwv;
  401. FatVolume* m_fVol = nullptr;
  402. ExFatVolume* m_xVol = nullptr;
  403. FsBlockDevice* m_blockDev;
  404. };
  405. #endif // FsVolume_h