lfs_vfs.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  1. /****************************************************************************
  2. * fs/littlefs/lfs_vfs.c
  3. *
  4. * This file is a part of NuttX:
  5. *
  6. * Copyright (C) 2019 Gregory Nutt. All rights reserved.
  7. *
  8. * Ported by:
  9. *
  10. * Copyright (C) 2019 Pinecone Inc. All rights reserved.
  11. * Author: lihaichen <li8303@163.com>
  12. *
  13. * This port derives from ARM mbed logic which has a compatible 3-clause
  14. * BSD license:
  15. *
  16. * Copyright (c) 2017, Arm Limited. All rights reserved.
  17. *
  18. * Redistribution and use in source and binary forms, with or without
  19. * modification, are permitted provided that the following conditions
  20. * are met:
  21. *
  22. * 1. Redistributions of source code must retain the above copyright
  23. * notice, this list of conditions and the following disclaimer.
  24. * 2. Redistributions in binary form must reproduce the above copyright
  25. * notice, this list of conditions and the following disclaimer in
  26. * the documentation and/or other materials provided with the
  27. * distribution.
  28. * 3. Neither the names ARM, NuttX nor the names of its contributors may be
  29. * used to endorse or promote products derived from this software
  30. * without specific prior written permission.
  31. *
  32. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  33. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  34. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  35. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  36. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  37. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  38. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  39. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  40. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  41. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  42. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  43. * POSSIBILITY OF SUCH DAMAGE.
  44. *
  45. ****************************************************************************/
  46. /****************************************************************************
  47. * Included Files
  48. ****************************************************************************/
  49. #include <nuttx/config.h>
  50. #include <errno.h>
  51. #include <fcntl.h>
  52. #include <string.h>
  53. #include <nuttx/fs/dirent.h>
  54. #include <nuttx/fs/fs.h>
  55. #include <nuttx/mtd/mtd.h>
  56. #include <nuttx/semaphore.h>
  57. #include <sys/stat.h>
  58. #include <sys/statfs.h>
  59. #include "lfs.h"
  60. #include "lfs_util.h"
  61. /****************************************************************************
  62. * Private Types
  63. ****************************************************************************/
  64. /* This structure represents the overall mountpoint state. An instance of this
  65. * structure is retained as inode private data on each mountpoint that is
  66. * mounted with a littlefs filesystem.
  67. */
  68. struct littlefs_mountpt_s
  69. {
  70. sem_t sem;
  71. FAR struct inode *drv;
  72. struct mtd_geometry_s geo;
  73. struct lfs_config_s cfg;
  74. lfs_t lfs;
  75. };
  76. /****************************************************************************
  77. * Private Function Prototypes
  78. ****************************************************************************/
  79. static void littlefs_semgive(FAR struct littlefs_mountpt_s *fs);
  80. static void littlefs_semtake(FAR struct littlefs_mountpt_s *fs);
  81. static int littlefs_open(FAR struct file *filep, FAR const char *relpath,
  82. int oflags, mode_t mode);
  83. static int littlefs_close(FAR struct file *filep);
  84. static ssize_t littlefs_read(FAR struct file *filep, FAR char *buffer,
  85. size_t buflen);
  86. static ssize_t littlefs_write(FAR struct file *filep, FAR const char *buffer,
  87. size_t buflen);
  88. static off_t littlefs_seek(FAR struct file *filep, off_t offset,
  89. int whence);
  90. static int littlefs_ioctl(FAR struct file *filep, int cmd,
  91. unsigned long arg);
  92. static int littlefs_sync(FAR struct file *filep);
  93. static int littlefs_dup(FAR const struct file *oldp,
  94. FAR struct file *newp);
  95. static int littlefs_fstat(FAR const struct file *filep,
  96. FAR struct stat *buf);
  97. static int littlefs_truncate(FAR struct file *filep,
  98. off_t length);
  99. static int littlefs_opendir(FAR struct inode *mountpt,
  100. FAR const char *relpath,
  101. FAR struct fs_dirent_s *dir);
  102. static int littlefs_closedir(FAR struct inode *mountpt,
  103. FAR struct fs_dirent_s *dir);
  104. static int littlefs_readdir(FAR struct inode *mountpt,
  105. FAR struct fs_dirent_s *dir);
  106. static int littlefs_rewinddir(FAR struct inode *mountpt,
  107. FAR struct fs_dirent_s *dir);
  108. static int littlefs_bind(FAR struct inode *driver,
  109. FAR const void *data, FAR void **handle);
  110. static int littlefs_unbind(FAR void *handle, FAR struct inode **driver,
  111. unsigned int flags);
  112. static int littlefs_statfs(FAR struct inode *mountpt,
  113. FAR struct statfs *buf);
  114. static int littlefs_unlink(FAR struct inode *mountpt,
  115. FAR const char *relpath);
  116. static int littlefs_mkdir(FAR struct inode *mountpt,
  117. FAR const char *relpath, mode_t mode);
  118. static int littlefs_rmdir(FAR struct inode *mountpt,
  119. FAR const char *relpath);
  120. static int littlefs_rename(FAR struct inode *mountpt,
  121. FAR const char *oldrelpath,
  122. FAR const char *newrelpath);
  123. static int littlefs_stat(FAR struct inode *mountpt,
  124. FAR const char *relpath, FAR struct stat *buf);
  125. /****************************************************************************
  126. * Public Data
  127. ****************************************************************************/
  128. /* See fs_mount.c -- this structure is explicitly extern'ed there.
  129. * We use the old-fashioned kind of initializers so that this will compile
  130. * with any compiler.
  131. */
  132. const struct mountpt_operations littlefs_operations =
  133. {
  134. littlefs_open, /* open */
  135. littlefs_close, /* close */
  136. littlefs_read, /* read */
  137. littlefs_write, /* write */
  138. littlefs_seek, /* seek */
  139. littlefs_ioctl, /* ioctl */
  140. littlefs_sync, /* sync */
  141. littlefs_dup, /* dup */
  142. littlefs_fstat, /* fstat */
  143. littlefs_truncate, /* truncate */
  144. littlefs_opendir, /* opendir */
  145. littlefs_closedir, /* closedir */
  146. littlefs_readdir, /* readdir */
  147. littlefs_rewinddir, /* rewinddir */
  148. littlefs_bind, /* bind */
  149. littlefs_unbind, /* unbind */
  150. littlefs_statfs, /* statfs */
  151. littlefs_unlink, /* unlink */
  152. littlefs_mkdir, /* mkdir */
  153. littlefs_rmdir, /* rmdir */
  154. littlefs_rename, /* rename */
  155. littlefs_stat /* stat */
  156. };
  157. /****************************************************************************
  158. * Private Functions
  159. ****************************************************************************/
  160. /****************************************************************************
  161. * Name: littlefs_semtake
  162. ****************************************************************************/
  163. static void littlefs_semtake(FAR struct littlefs_mountpt_s *fs)
  164. {
  165. int ret;
  166. do
  167. {
  168. /* Take the semaphore (perhaps waiting) */
  169. ret = nxsem_wait(&fs->sem);
  170. /* The only case that an error should occur here is if the wait was
  171. * awakened by a signal.
  172. */
  173. DEBUGASSERT(ret == OK || ret == -EINTR);
  174. }
  175. while (ret == -EINTR);
  176. }
  177. /****************************************************************************
  178. * Name: littlefs_semgive
  179. ****************************************************************************/
  180. static void littlefs_semgive(FAR struct littlefs_mountpt_s *fs)
  181. {
  182. nxsem_post(&fs->sem);
  183. }
  184. /****************************************************************************
  185. * Name: littlefs_convert_oflags
  186. ****************************************************************************/
  187. static int littlefs_convert_oflags(int oflags)
  188. {
  189. int ret = 0;
  190. if ((oflags & O_RDONLY) != 0)
  191. {
  192. ret |= LFS_O_RDONLY;
  193. }
  194. if ((oflags & O_WRONLY) != 0)
  195. {
  196. ret |= LFS_O_WRONLY;
  197. }
  198. if ((oflags & O_CREAT) != 0)
  199. {
  200. ret |= LFS_O_CREAT;
  201. }
  202. if ((oflags & O_EXCL) != 0)
  203. {
  204. ret |= LFS_O_EXCL;
  205. }
  206. if ((oflags & O_APPEND) != 0)
  207. {
  208. ret |= LFS_O_APPEND;
  209. }
  210. if ((oflags & O_TRUNC) != 0)
  211. {
  212. ret |= LFS_O_TRUNC;
  213. }
  214. return ret;
  215. }
  216. /****************************************************************************
  217. * Name: littlefs_open
  218. ****************************************************************************/
  219. static int littlefs_open(FAR struct file *filep, FAR const char *relpath,
  220. int oflags, mode_t mode)
  221. {
  222. FAR struct littlefs_mountpt_s *fs;
  223. FAR struct lfs_file_s *priv;
  224. FAR struct inode *inode;
  225. int ret;
  226. /* Get the mountpoint inode reference from the file structure and the
  227. * mountpoint private data from the inode structure
  228. */
  229. inode = filep->f_inode;
  230. fs = inode->i_private;
  231. /* Allocate memory for the open file */
  232. priv = kmm_malloc(sizeof(*priv));
  233. if (priv == NULL)
  234. {
  235. return -ENOMEM;
  236. }
  237. /* Take the semaphore */
  238. littlefs_semtake(fs);
  239. /* Try to open the file */
  240. oflags = littlefs_convert_oflags(oflags);
  241. ret = lfs_file_open(&fs->lfs, priv, relpath, oflags);
  242. if (ret < 0)
  243. {
  244. /* Error opening file */
  245. goto errout;
  246. }
  247. /* In append mode, we need to set the file pointer to the end of the
  248. * file.
  249. */
  250. if (oflags & LFS_O_APPEND)
  251. {
  252. ret = lfs_file_seek(&fs->lfs, priv, 0, LFS_SEEK_END);
  253. if (ret >= 0)
  254. {
  255. filep->f_pos = ret;
  256. }
  257. else
  258. {
  259. goto errout_with_file;
  260. }
  261. }
  262. littlefs_semgive(fs);
  263. /* Attach the private date to the struct file instance */
  264. filep->f_priv = priv;
  265. return OK;
  266. errout_with_file:
  267. lfs_file_close(&fs->lfs, priv);
  268. errout:
  269. littlefs_semgive(fs);
  270. kmm_free(priv);
  271. return ret;
  272. }
  273. /****************************************************************************
  274. * Name: littlefs_close
  275. ****************************************************************************/
  276. static int littlefs_close(FAR struct file *filep)
  277. {
  278. FAR struct littlefs_mountpt_s *fs;
  279. FAR struct lfs_file_s *priv;
  280. FAR struct inode *inode;
  281. /* Recover our private data from the struct file instance */
  282. priv = filep->f_priv;
  283. inode = filep->f_inode;
  284. fs = inode->i_private;
  285. /* Close the file */
  286. littlefs_semtake(fs);
  287. lfs_file_close(&fs->lfs, priv);
  288. littlefs_semgive(fs);
  289. /* Now free the pointer */
  290. kmm_free(priv);
  291. return OK;
  292. }
  293. /****************************************************************************
  294. * Name: littlefs_read
  295. ****************************************************************************/
  296. static ssize_t littlefs_read(FAR struct file *filep, FAR char *buffer,
  297. size_t buflen)
  298. {
  299. FAR struct littlefs_mountpt_s *fs;
  300. FAR struct lfs_file_s *priv;
  301. FAR struct inode *inode;
  302. ssize_t ret;
  303. /* Recover our private data from the struct file instance */
  304. priv = filep->f_priv;
  305. inode = filep->f_inode;
  306. fs = inode->i_private;
  307. /* Call LFS to perform the read */
  308. littlefs_semtake(fs);
  309. ret = lfs_file_read(&fs->lfs, priv, buffer, buflen);
  310. if (ret > 0)
  311. {
  312. filep->f_pos += ret;
  313. }
  314. littlefs_semgive(fs);
  315. return ret;
  316. }
  317. /****************************************************************************
  318. * Name: littlefs_write
  319. ****************************************************************************/
  320. static ssize_t littlefs_write(FAR struct file *filep, const char *buffer,
  321. size_t buflen)
  322. {
  323. FAR struct littlefs_mountpt_s *fs;
  324. FAR struct lfs_file_s *priv;
  325. FAR struct inode *inode;
  326. ssize_t ret;
  327. /* Recover our private data from the struct file instance */
  328. priv = filep->f_priv;
  329. inode = filep->f_inode;
  330. fs = inode->i_private;
  331. /* Call LFS to perform the write */
  332. littlefs_semtake(fs);
  333. ret = lfs_file_write(&fs->lfs, priv, buffer, buflen);
  334. if (ret > 0)
  335. {
  336. filep->f_pos += ret;
  337. }
  338. littlefs_semgive(fs);
  339. return ret;
  340. }
  341. /****************************************************************************
  342. * Name: littlefs_seek
  343. ****************************************************************************/
  344. static off_t littlefs_seek(FAR struct file *filep, off_t offset, int whence)
  345. {
  346. FAR struct littlefs_mountpt_s *fs;
  347. FAR struct lfs_file_s *priv;
  348. FAR struct inode *inode;
  349. off_t ret;
  350. /* Recover our private data from the struct file instance */
  351. priv = filep->f_priv;
  352. inode = filep->f_inode;
  353. fs = inode->i_private;
  354. /* Call LFS to perform the seek */
  355. littlefs_semtake(fs);
  356. ret = lfs_file_seek(&fs->lfs, priv, offset, whence);
  357. if (ret >= 0)
  358. {
  359. filep->f_pos = ret;
  360. }
  361. littlefs_semgive(fs);
  362. return ret;
  363. }
  364. /****************************************************************************
  365. * Name: littlefs_ioctl
  366. ****************************************************************************/
  367. static int littlefs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  368. {
  369. FAR struct littlefs_mountpt_s *fs;
  370. FAR struct inode *inode;
  371. FAR struct inode *drv;
  372. /* Recover our private data from the struct file instance */
  373. inode = filep->f_inode;
  374. fs = inode->i_private;
  375. drv = fs->drv;
  376. if (INODE_IS_MTD(drv))
  377. {
  378. return MTD_IOCTL(drv->u.i_mtd, cmd, arg);
  379. }
  380. else
  381. {
  382. return drv->u.i_bops->ioctl(drv, cmd, arg);
  383. }
  384. }
  385. /****************************************************************************
  386. * Name: littlefs_sync
  387. *
  388. * Description: Synchronize the file state on disk to match internal, in-
  389. * memory state.
  390. *
  391. ****************************************************************************/
  392. static int littlefs_sync(FAR struct file *filep)
  393. {
  394. FAR struct littlefs_mountpt_s *fs;
  395. FAR struct lfs_file_s *priv;
  396. FAR struct inode *inode;
  397. int ret;
  398. /* Recover our private data from the struct file instance */
  399. priv = filep->f_priv;
  400. inode = filep->f_inode;
  401. fs = inode->i_private;
  402. littlefs_semtake(fs);
  403. ret = lfs_file_sync(&fs->lfs, priv);
  404. littlefs_semgive(fs);
  405. return ret;
  406. }
  407. /****************************************************************************
  408. * Name: littlefs_dup
  409. *
  410. * Description: Duplicate open file data in the new file structure.
  411. *
  412. ****************************************************************************/
  413. static int littlefs_dup(FAR const struct file *oldp, FAR struct file *newp)
  414. {
  415. return -ENOSYS;
  416. }
  417. /****************************************************************************
  418. * Name: littlefs_fstat
  419. *
  420. * Description:
  421. * Obtain information about an open file associated with the file
  422. * descriptor 'fd', and will write it to the area pointed to by 'buf'.
  423. *
  424. ****************************************************************************/
  425. static int littlefs_fstat(FAR const struct file *filep, FAR struct stat *buf)
  426. {
  427. FAR struct littlefs_mountpt_s *fs;
  428. FAR struct lfs_file_s *priv;
  429. FAR struct inode *inode;
  430. memset(buf, 0, sizeof(*buf));
  431. /* Recover our private data from the struct file instance */
  432. priv = filep->f_priv;
  433. inode = filep->f_inode;
  434. fs = inode->i_private;
  435. /* Call LFS to get file size */
  436. littlefs_semtake(fs);
  437. buf->st_size = lfs_file_size(&fs->lfs, priv);
  438. littlefs_semgive(fs);
  439. if (buf->st_size < 0)
  440. {
  441. return buf->st_size;
  442. }
  443. buf->st_mode = S_IRWXO | S_IRWXG | S_IRWXU | S_IFREG;
  444. buf->st_blksize = fs->cfg.block_size;
  445. buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / buf->st_blksize;
  446. return OK;
  447. }
  448. /****************************************************************************
  449. * Name: littlefs_truncate
  450. *
  451. * Description:
  452. * Set the length of the open, regular file associated with the file
  453. * structure 'filep' to 'length'.
  454. *
  455. ****************************************************************************/
  456. static int littlefs_truncate(FAR struct file *filep, off_t length)
  457. {
  458. FAR struct littlefs_mountpt_s *fs;
  459. FAR struct lfs_file_s *priv;
  460. FAR struct inode *inode;
  461. int ret;
  462. /* Recover our private data from the struct file instance */
  463. priv = filep->f_priv;
  464. inode = filep->f_inode;
  465. fs = inode->i_private;
  466. /* Call LFS to perform the truncate */
  467. littlefs_semtake(fs);
  468. ret = lfs_file_truncate(&fs->lfs, priv, length);
  469. littlefs_semgive(fs);
  470. return ret;
  471. }
  472. /****************************************************************************
  473. * Name: littlefs_opendir
  474. *
  475. * Description: Open a directory for read access
  476. *
  477. ****************************************************************************/
  478. static int littlefs_opendir(FAR struct inode *mountpt,
  479. FAR const char *relpath,
  480. FAR struct fs_dirent_s *dir)
  481. {
  482. FAR struct littlefs_mountpt_s *fs;
  483. FAR struct lfs_dir_s *priv;
  484. int ret;
  485. /* Recover our private data from the inode instance */
  486. fs = mountpt->i_private;
  487. /* Allocate memory for the open directory */
  488. priv = kmm_malloc(sizeof(*priv));
  489. if (priv == NULL)
  490. {
  491. return -ENOMEM;
  492. }
  493. /* Take the semaphore */
  494. littlefs_semtake(fs);
  495. /* Call the LFS's opendir function */
  496. ret = lfs_dir_open(&fs->lfs, priv, relpath);
  497. if (ret < 0)
  498. {
  499. goto errout;
  500. }
  501. dir->fd_position = lfs_dir_tell(&fs->lfs, priv);
  502. littlefs_semgive(fs);
  503. dir->u.littlefs = priv;
  504. return OK;
  505. errout:
  506. littlefs_semgive(fs);
  507. kmm_free(priv);
  508. return ret;
  509. }
  510. /****************************************************************************
  511. * Name: littlefs_closedir
  512. *
  513. * Description: Close a directory
  514. *
  515. ****************************************************************************/
  516. static int littlefs_closedir(FAR struct inode *mountpt,
  517. FAR struct fs_dirent_s *dir)
  518. {
  519. struct littlefs_mountpt_s *fs;
  520. FAR struct lfs_dir_s *priv;
  521. /* Recover our private data from the inode instance */
  522. priv = dir->u.littlefs;
  523. fs = mountpt->i_private;
  524. /* Call the LFS's closedir function */
  525. littlefs_semtake(fs);
  526. lfs_dir_close(&fs->lfs, priv);
  527. littlefs_semgive(fs);
  528. kmm_free(priv);
  529. return OK;
  530. }
  531. /****************************************************************************
  532. * Name: littlefs_readdir
  533. *
  534. * Description: Read the next directory entry
  535. *
  536. ****************************************************************************/
  537. static int littlefs_readdir(FAR struct inode *mountpt,
  538. FAR struct fs_dirent_s *dir)
  539. {
  540. FAR struct littlefs_mountpt_s *fs;
  541. FAR struct lfs_dir_s *priv;
  542. struct lfs_info_s info;
  543. int ret;
  544. /* Recover our private data from the inode instance */
  545. priv = dir->u.littlefs;
  546. fs = mountpt->i_private;
  547. /* Call the LFS's readdir function */
  548. littlefs_semtake(fs);
  549. ret = lfs_dir_read(&fs->lfs, priv, &info);
  550. if (ret > 0)
  551. {
  552. dir->fd_position = lfs_dir_tell(&fs->lfs, priv);
  553. if (info.type == LFS_TYPE_REG)
  554. {
  555. dir->fd_dir.d_type = DTYPE_FILE;
  556. }
  557. else
  558. {
  559. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  560. }
  561. strcpy(dir->fd_dir.d_name, info.name);
  562. }
  563. else if (ret == 0)
  564. {
  565. ret = -ENOENT;
  566. }
  567. littlefs_semgive(fs);
  568. return ret;
  569. }
  570. /****************************************************************************
  571. * Name: littlefs_rewindir
  572. *
  573. * Description: Reset directory read to the first entry
  574. *
  575. ****************************************************************************/
  576. static int littlefs_rewinddir(FAR struct inode *mountpt,
  577. FAR struct fs_dirent_s *dir)
  578. {
  579. struct littlefs_mountpt_s *fs;
  580. FAR struct lfs_dir_s *priv;
  581. int ret;
  582. /* Recover our private data from the inode instance */
  583. priv = dir->u.littlefs;
  584. fs = mountpt->i_private;
  585. /* Call the LFS's rewinddir function */
  586. littlefs_semtake(fs);
  587. ret = lfs_dir_rewind(&fs->lfs, priv);
  588. if (ret >= 0)
  589. {
  590. dir->fd_position = lfs_dir_tell(&fs->lfs, priv);
  591. }
  592. littlefs_semgive(fs);
  593. return ret;
  594. }
  595. /****************************************************************************
  596. * Name: littlefs_bind
  597. *
  598. * Description: This implements a portion of the mount operation. This
  599. * function allocates and initializes the mountpoint private data and
  600. * binds the driver inode to the filesystem private data. The final
  601. * binding of the private data (containing the driver) to the
  602. * mountpoint is performed by mount().
  603. *
  604. ****************************************************************************/
  605. static int littlefs_read_block(FAR const struct lfs_config_s *c,
  606. lfs_block_t block, lfs_off_t off,
  607. FAR void *buffer, lfs_size_t size)
  608. {
  609. FAR struct littlefs_mountpt_s *fs = c->context;
  610. FAR struct mtd_geometry_s *geo = &fs->geo;
  611. FAR struct inode *drv = fs->drv;
  612. int ret;
  613. block = (block * c->block_size + off) / geo->blocksize;
  614. size = size / geo->blocksize;
  615. if (INODE_IS_MTD(drv))
  616. {
  617. ret = MTD_BREAD(drv->u.i_mtd, block, size, buffer);
  618. }
  619. else
  620. {
  621. ret = drv->u.i_bops->read(drv, buffer, block, size);
  622. }
  623. return ret >= 0 ? OK : ret;
  624. }
  625. /****************************************************************************
  626. * Name: littlefs_write_block
  627. ****************************************************************************/
  628. static int littlefs_write_block(FAR const struct lfs_config_s *c,
  629. lfs_block_t block, lfs_off_t off,
  630. FAR const void *buffer, lfs_size_t size)
  631. {
  632. FAR struct littlefs_mountpt_s *fs = c->context;
  633. FAR struct mtd_geometry_s *geo = &fs->geo;
  634. FAR struct inode *drv = fs->drv;
  635. int ret;
  636. block = (block * c->block_size + off) / geo->blocksize;
  637. size = size / geo->blocksize;
  638. if (INODE_IS_MTD(drv))
  639. {
  640. ret = MTD_BWRITE(drv->u.i_mtd, block, size, buffer);
  641. }
  642. else
  643. {
  644. ret = drv->u.i_bops->write(drv, buffer, block, size);
  645. }
  646. return ret >= 0 ? OK : ret;
  647. }
  648. /****************************************************************************
  649. * Name: littlefs_erase_block
  650. ****************************************************************************/
  651. static int littlefs_erase_block(FAR const struct lfs_config_s *c,
  652. lfs_block_t block)
  653. {
  654. FAR struct littlefs_mountpt_s *fs = c->context;
  655. FAR struct inode *drv = fs->drv;
  656. int ret = OK;
  657. if (INODE_IS_MTD(drv))
  658. {
  659. FAR struct mtd_geometry_s *geo = &fs->geo;
  660. size_t size = c->block_size / geo->erasesize;
  661. block = block * c->block_size / geo->erasesize;
  662. ret = MTD_ERASE(drv->u.i_mtd, block, size);
  663. }
  664. return ret >= 0 ? OK : ret;
  665. }
  666. /****************************************************************************
  667. * Name: littlefs_sync_block
  668. ****************************************************************************/
  669. static int littlefs_sync_block(FAR const struct lfs_config_s *c)
  670. {
  671. FAR struct littlefs_mountpt_s *fs = c->context;
  672. FAR struct inode *drv = fs->drv;
  673. int ret;
  674. if (INODE_IS_MTD(drv))
  675. {
  676. ret = MTD_IOCTL(drv->u.i_mtd, BIOC_FLUSH, 0);
  677. }
  678. else
  679. {
  680. ret = drv->u.i_bops->ioctl(drv, BIOC_FLUSH, 0);
  681. }
  682. return ret == -ENOTTY ? OK : ret;
  683. }
  684. /****************************************************************************
  685. * Name: littlefs_bind
  686. ****************************************************************************/
  687. static int littlefs_bind(FAR struct inode *driver, FAR const void *data,
  688. FAR void **handle)
  689. {
  690. FAR struct littlefs_mountpt_s *fs;
  691. int ret;
  692. /* Open the block driver */
  693. if (INODE_IS_BLOCK(driver) && driver->u.i_bops->open)
  694. {
  695. ret = driver->u.i_bops->open(driver);
  696. if (ret < 0)
  697. {
  698. return ret;
  699. }
  700. }
  701. /* Create an instance of the mountpt state structure */
  702. fs = kmm_zalloc(sizeof(*fs));
  703. if (!fs)
  704. {
  705. ret = -ENOMEM;
  706. goto errout_with_block;
  707. }
  708. /* Initialize the allocated mountpt state structure. The filesystem is
  709. * responsible for one reference on the driver inode and does not
  710. * have to addref() here (but does have to release in unbind().
  711. */
  712. fs->drv = driver; /* Save the driver reference */
  713. nxsem_init(&fs->sem, 0, 0); /* Initialize the access control semaphore */
  714. if (INODE_IS_MTD(driver))
  715. {
  716. /* Get MTD geometry directly */
  717. ret = MTD_IOCTL(driver->u.i_mtd, MTDIOC_GEOMETRY,
  718. (unsigned long)&fs->geo);
  719. }
  720. else
  721. {
  722. /* Try to get FLT MTD geometry first */
  723. ret = driver->u.i_bops->ioctl(driver, MTDIOC_GEOMETRY,
  724. (unsigned long)&fs->geo);
  725. if (ret < 0)
  726. {
  727. struct geometry geometry;
  728. /* Not FLT MTD device, get normal block geometry */
  729. ret = driver->u.i_bops->geometry(driver, &geometry);
  730. if (ret >= 0)
  731. {
  732. /* And convert to MTD geometry */
  733. fs->geo.blocksize = geometry.geo_sectorsize;
  734. fs->geo.erasesize = geometry.geo_sectorsize;
  735. fs->geo.neraseblocks = geometry.geo_nsectors;
  736. }
  737. }
  738. }
  739. if (ret < 0)
  740. {
  741. goto errout_with_fs;
  742. }
  743. /* Initialize lfs_config structure */
  744. fs->cfg.context = fs;
  745. fs->cfg.read = littlefs_read_block;
  746. fs->cfg.prog = littlefs_write_block;
  747. fs->cfg.erase = littlefs_erase_block;
  748. fs->cfg.sync = littlefs_sync_block;
  749. fs->cfg.read_size = fs->geo.blocksize;
  750. fs->cfg.prog_size = fs->geo.blocksize;
  751. fs->cfg.block_size = fs->geo.erasesize;
  752. fs->cfg.block_count = fs->geo.neraseblocks;
  753. fs->cfg.lookahead = 4 * ((fs->cfg.block_count + 31) / 32);
  754. if (fs->cfg.lookahead > fs->cfg.read_size)
  755. {
  756. fs->cfg.lookahead = fs->cfg.read_size;
  757. }
  758. /* Then get information about the littlefs filesystem on the devices
  759. * managed by this driver.
  760. */
  761. /* Force format the device if -o forceformat */
  762. if (data && strcmp(data, "forceformat") == 0)
  763. {
  764. ret = lfs_format(&fs->lfs, &fs->cfg);
  765. if (ret < 0)
  766. {
  767. goto errout_with_fs;
  768. }
  769. }
  770. ret = lfs_mount(&fs->lfs, &fs->cfg);
  771. if (ret < 0)
  772. {
  773. /* Auto format the device if -o autoformat */
  774. if (ret != LFS_ERR_CORRUPT ||
  775. !data || strcmp(data, "autoformat"))
  776. {
  777. goto errout_with_fs;
  778. }
  779. ret = lfs_format(&fs->lfs, &fs->cfg);
  780. if (ret < 0)
  781. {
  782. goto errout_with_fs;
  783. }
  784. /* Try to mount the device again */
  785. ret = lfs_mount(&fs->lfs, &fs->cfg);
  786. if (ret < 0)
  787. {
  788. goto errout_with_fs;
  789. }
  790. }
  791. *handle = fs;
  792. littlefs_semgive(fs);
  793. return OK;
  794. errout_with_fs:
  795. nxsem_destroy(&fs->sem);
  796. kmm_free(fs);
  797. errout_with_block:
  798. if (INODE_IS_BLOCK(driver) && driver->u.i_bops->close)
  799. {
  800. driver->u.i_bops->close(driver);
  801. }
  802. return ret;
  803. }
  804. /****************************************************************************
  805. * Name: littlefs_unbind
  806. *
  807. * Description: This implements the filesystem portion of the umount
  808. * operation.
  809. *
  810. ****************************************************************************/
  811. static int littlefs_unbind(FAR void *handle, FAR struct inode **driver,
  812. unsigned int flags)
  813. {
  814. FAR struct littlefs_mountpt_s *fs = handle;
  815. FAR struct inode *drv = fs->drv;
  816. int ret;
  817. /* Unmount */
  818. littlefs_semtake(fs);
  819. ret = lfs_unmount(&fs->lfs);
  820. littlefs_semgive(fs);
  821. if (ret >= 0)
  822. {
  823. /* Close the block driver */
  824. if (INODE_IS_BLOCK(drv) && drv->u.i_bops->close)
  825. {
  826. drv->u.i_bops->close(drv);
  827. }
  828. /* We hold a reference to the driver but should not but
  829. * mucking with inodes in this context. So, we will just return
  830. * our contained reference to the driver inode and let the
  831. * umount logic dispose of it.
  832. */
  833. if (driver)
  834. {
  835. *driver = drv;
  836. }
  837. /* Release the mountpoint private data */
  838. nxsem_destroy(&fs->sem);
  839. kmm_free(fs);
  840. }
  841. return ret;
  842. }
  843. /****************************************************************************
  844. * Name: littlefs_used_block
  845. ****************************************************************************/
  846. static int littlefs_used_block(void *arg, lfs_block_t block)
  847. {
  848. FAR struct statfs *buf = arg;
  849. buf->f_bfree--;
  850. buf->f_bavail--;
  851. return 0;
  852. }
  853. /****************************************************************************
  854. * Name: littlefs_statfs
  855. *
  856. * Description: Return filesystem statistics
  857. *
  858. ****************************************************************************/
  859. static int littlefs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
  860. {
  861. FAR struct littlefs_mountpt_s *fs;
  862. int ret;
  863. /* Get the mountpoint private data from the inode structure */
  864. fs = mountpt->i_private;
  865. /* Return something for the file system description */
  866. memset(buf, 0, sizeof(*buf));
  867. buf->f_type = LITTLEFS_SUPER_MAGIC;
  868. buf->f_namelen = LFS_NAME_MAX;
  869. buf->f_bsize = fs->cfg.block_size;
  870. buf->f_blocks = fs->cfg.block_count;
  871. buf->f_bfree = fs->cfg.block_count;
  872. buf->f_bavail = fs->cfg.block_count;
  873. littlefs_semtake(fs);
  874. ret = lfs_traverse(&fs->lfs, littlefs_used_block, buf);
  875. littlefs_semgive(fs);
  876. return ret;
  877. }
  878. /****************************************************************************
  879. * Name: littlefs_unlink
  880. *
  881. * Description: Remove a file
  882. *
  883. ****************************************************************************/
  884. static int littlefs_unlink(FAR struct inode *mountpt,
  885. FAR const char *relpath)
  886. {
  887. FAR struct littlefs_mountpt_s *fs;
  888. int ret;
  889. /* Get the mountpoint private data from the inode structure */
  890. fs = mountpt->i_private;
  891. /* Call the LFS to perform the unlink */
  892. littlefs_semtake(fs);
  893. ret = lfs_remove(&fs->lfs, relpath);
  894. littlefs_semgive(fs);
  895. return ret;
  896. }
  897. /****************************************************************************
  898. * Name: littlefs_mkdir
  899. *
  900. * Description: Create a directory
  901. *
  902. ****************************************************************************/
  903. static int littlefs_mkdir(FAR struct inode *mountpt, FAR const char *relpath,
  904. mode_t mode)
  905. {
  906. FAR struct littlefs_mountpt_s *fs;
  907. int ret;
  908. /* Get the mountpoint private data from the inode structure */
  909. fs = mountpt->i_private;
  910. /* Call LFS to do the mkdir */
  911. littlefs_semtake(fs);
  912. ret = lfs_mkdir(&fs->lfs, relpath);
  913. littlefs_semgive(fs);
  914. return ret;
  915. }
  916. /****************************************************************************
  917. * Name: littlefs_rmdir
  918. *
  919. * Description: Remove a directory
  920. *
  921. ****************************************************************************/
  922. static int littlefs_rmdir(FAR struct inode *mountpt, FAR const char *relpath)
  923. {
  924. return littlefs_unlink(mountpt, relpath);
  925. }
  926. /****************************************************************************
  927. * Name: littlefs_rename
  928. *
  929. * Description: Rename a file or directory
  930. *
  931. ****************************************************************************/
  932. static int littlefs_rename(FAR struct inode *mountpt,
  933. FAR const char *oldrelpath,
  934. FAR const char *newrelpath)
  935. {
  936. FAR struct littlefs_mountpt_s *fs;
  937. int ret;
  938. /* Get the mountpoint private data from the inode structure */
  939. fs = mountpt->i_private;
  940. /* Call LFS to do the rename */
  941. littlefs_semtake(fs);
  942. ret = lfs_rename(&fs->lfs, oldrelpath, newrelpath);
  943. littlefs_semgive(fs);
  944. return ret;
  945. }
  946. /****************************************************************************
  947. * Name: littlefs_stat
  948. *
  949. * Description: Return information about a file or directory
  950. *
  951. ****************************************************************************/
  952. static int littlefs_stat(FAR struct inode *mountpt, FAR const char *relpath,
  953. FAR struct stat *buf)
  954. {
  955. FAR struct littlefs_mountpt_s *fs;
  956. struct lfs_info_s info;
  957. int ret;
  958. memset(buf, 0, sizeof(*buf));
  959. /* Get the mountpoint private data from the inode structure */
  960. fs = mountpt->i_private;
  961. /* Call the LFS to do the stat operation */
  962. littlefs_semtake(fs);
  963. ret = lfs_stat(&fs->lfs, relpath, &info);
  964. littlefs_semgive(fs);
  965. if (ret >= 0)
  966. {
  967. /* Convert info to stat */
  968. buf->st_mode = S_IRWXO | S_IRWXG | S_IRWXU;
  969. if (info.type == LFS_TYPE_REG)
  970. {
  971. buf->st_mode |= S_IFREG;
  972. }
  973. else
  974. {
  975. buf->st_mode |= S_IFDIR;
  976. }
  977. buf->st_size = info.size;
  978. buf->st_blksize = fs->cfg.block_size;
  979. buf->st_blocks = (buf->st_size + buf->st_blksize - 1) /
  980. buf->st_blksize;
  981. }
  982. return ret;
  983. }