fs_romfs.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. /****************************************************************************
  2. * fs/romfs/fs_romfs.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <sys/types.h>
  25. #include <sys/statfs.h>
  26. #include <sys/stat.h>
  27. #include <stdint.h>
  28. #include <stdbool.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #include <fcntl.h>
  33. #include <limits.h>
  34. #include <assert.h>
  35. #include <errno.h>
  36. #include <debug.h>
  37. #include <nuttx/kmalloc.h>
  38. #include <nuttx/fs/fs.h>
  39. #include <nuttx/fs/ioctl.h>
  40. #include <nuttx/fs/dirent.h>
  41. #include <nuttx/mtd/mtd.h>
  42. #include "fs_romfs.h"
  43. /****************************************************************************
  44. * Private Function Prototypes
  45. ****************************************************************************/
  46. static int romfs_open(FAR struct file *filep, FAR const char *relpath,
  47. int oflags, mode_t mode);
  48. static int romfs_close(FAR struct file *filep);
  49. static ssize_t romfs_read(FAR struct file *filep, FAR char *buffer,
  50. size_t buflen);
  51. static off_t romfs_seek(FAR struct file *filep, off_t offset, int whence);
  52. static int romfs_ioctl(FAR struct file *filep, int cmd,
  53. unsigned long arg);
  54. static int romfs_dup(FAR const struct file *oldp,
  55. FAR struct file *newp);
  56. static int romfs_fstat(FAR const struct file *filep,
  57. FAR struct stat *buf);
  58. static int romfs_opendir(FAR struct inode *mountpt,
  59. FAR const char *relpath,
  60. FAR struct fs_dirent_s *dir);
  61. static int romfs_readdir(FAR struct inode *mountpt,
  62. FAR struct fs_dirent_s *dir);
  63. static int romfs_rewinddir(FAR struct inode *mountpt,
  64. FAR struct fs_dirent_s *dir);
  65. static int romfs_bind(FAR struct inode *blkdriver, FAR const void *data,
  66. FAR void **handle);
  67. static int romfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
  68. unsigned int flags);
  69. static int romfs_statfs(FAR struct inode *mountpt,
  70. FAR struct statfs *buf);
  71. static int romfs_stat_common(uint8_t type, uint32_t size,
  72. uint16_t sectorsize, FAR struct stat *buf);
  73. static int romfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
  74. FAR struct stat *buf);
  75. /****************************************************************************
  76. * Public Data
  77. ****************************************************************************/
  78. /* See fs_mount.c -- this structure is explicitly externed there.
  79. * We use the old-fashioned kind of initializers so that this will compile
  80. * with any compiler.
  81. */
  82. const struct mountpt_operations romfs_operations =
  83. {
  84. romfs_open, /* open */
  85. romfs_close, /* close */
  86. romfs_read, /* read */
  87. NULL, /* write */
  88. romfs_seek, /* seek */
  89. romfs_ioctl, /* ioctl */
  90. NULL, /* sync */
  91. romfs_dup, /* dup */
  92. romfs_fstat, /* fstat */
  93. NULL, /* truncate */
  94. romfs_opendir, /* opendir */
  95. NULL, /* closedir */
  96. romfs_readdir, /* readdir */
  97. romfs_rewinddir, /* rewinddir */
  98. romfs_bind, /* bind */
  99. romfs_unbind, /* unbind */
  100. romfs_statfs, /* statfs */
  101. NULL, /* unlink */
  102. NULL, /* mkdir */
  103. NULL, /* rmdir */
  104. NULL, /* rename */
  105. romfs_stat /* stat */
  106. };
  107. /****************************************************************************
  108. * Private Functions
  109. ****************************************************************************/
  110. /****************************************************************************
  111. * Name: romfs_open
  112. ****************************************************************************/
  113. static int romfs_open(FAR struct file *filep, FAR const char *relpath,
  114. int oflags, mode_t mode)
  115. {
  116. struct romfs_dirinfo_s dirinfo;
  117. FAR struct romfs_mountpt_s *rm;
  118. FAR struct romfs_file_s *rf;
  119. int ret;
  120. finfo("Open '%s'\n", relpath);
  121. /* Sanity checks */
  122. DEBUGASSERT(filep->f_priv == NULL && filep->f_inode != NULL);
  123. /* Get mountpoint private data from the inode reference from the file
  124. * structure
  125. */
  126. rm = (FAR struct romfs_mountpt_s *)filep->f_inode->i_private;
  127. DEBUGASSERT(rm != NULL);
  128. /* Check if the mount is still healthy */
  129. ret = romfs_semtake(rm);
  130. if (ret < 0)
  131. {
  132. return ret;
  133. }
  134. ret = romfs_checkmount(rm);
  135. if (ret != OK)
  136. {
  137. ferr("ERROR: romfs_checkmount failed: %d\n", ret);
  138. goto errout_with_semaphore;
  139. }
  140. /* ROMFS is read-only. Any attempt to open with any kind of write
  141. * access is not permitted.
  142. */
  143. if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)
  144. {
  145. ferr("ERROR: Only O_RDONLY supported\n");
  146. ret = -EACCES;
  147. goto errout_with_semaphore;
  148. }
  149. /* Initialize the directory info structure */
  150. memset(&dirinfo, 0, sizeof(struct romfs_dirinfo_s));
  151. /* Locate the directory entry for this path */
  152. ret = romfs_finddirentry(rm, &dirinfo, relpath);
  153. if (ret < 0)
  154. {
  155. ferr("ERROR: Failed to find directory directory entry for '%s': %d\n",
  156. relpath, ret);
  157. goto errout_with_semaphore;
  158. }
  159. /* The full path exists -- but is the final component a file
  160. * or a directory? Or some other Unix file type that is not
  161. * appropriate in this context.
  162. *
  163. * REVISIT: This logic should follow hard/soft link file
  164. * types. At present, it returns the ENXIO.
  165. */
  166. if (IS_DIRECTORY(dirinfo.rd_next))
  167. {
  168. /* It is a directory */
  169. ret = -EISDIR;
  170. ferr("ERROR: '%s' is a directory\n", relpath);
  171. goto errout_with_semaphore;
  172. }
  173. else if (!IS_FILE(dirinfo.rd_next))
  174. {
  175. /* ENXIO indicates "The named file is a character special or
  176. * block special file, and the device associated with this
  177. * special file does not exist."
  178. *
  179. * Here we also return ENXIO if the file is not a directory
  180. * or a regular file.
  181. */
  182. ret = -ENXIO;
  183. ferr("ERROR: '%s' is a special file\n", relpath);
  184. goto errout_with_semaphore;
  185. }
  186. #ifdef CONFIG_FILE_MODE
  187. # warning "Missing check for privileges based on inode->i_mode"
  188. #endif
  189. /* Create an instance of the file private data to describe the opened
  190. * file.
  191. */
  192. rf = (FAR struct romfs_file_s *)kmm_zalloc(sizeof(struct romfs_file_s));
  193. if (!rf)
  194. {
  195. ferr("ERROR: Failed to allocate private data\n");
  196. ret = -ENOMEM;
  197. goto errout_with_semaphore;
  198. }
  199. /* Initialize the file private data (only need to initialize
  200. * non-zero elements)
  201. */
  202. rf->rf_size = dirinfo.rd_size;
  203. rf->rf_type = (uint8_t)(dirinfo.rd_next & RFNEXT_ALLMODEMASK);
  204. /* Get the start of the file data */
  205. ret = romfs_datastart(rm, dirinfo.rd_dir.fr_curroffset,
  206. &rf->rf_startoffset);
  207. if (ret < 0)
  208. {
  209. ferr("ERROR: Failed to locate start of file data: %d\n", ret);
  210. kmm_free(rf);
  211. goto errout_with_semaphore;
  212. }
  213. /* Configure buffering to support access to this file */
  214. ret = romfs_fileconfigure(rm, rf);
  215. if (ret < 0)
  216. {
  217. ferr("ERROR: Failed configure buffering: %d\n", ret);
  218. kmm_free(rf);
  219. goto errout_with_semaphore;
  220. }
  221. /* Attach the private date to the struct file instance */
  222. filep->f_priv = rf;
  223. /* Then insert the new instance into the mountpoint structure.
  224. * It needs to be there (1) to handle error conditions that effect
  225. * all files, and (2) to inform the umount logic that we are busy
  226. * (but a simple reference count could have done that).
  227. */
  228. rf->rf_next = rm->rm_head;
  229. rm->rm_head = rf->rf_next;
  230. romfs_semgive(rm);
  231. return OK;
  232. /* Error exits */
  233. errout_with_semaphore:
  234. romfs_semgive(rm);
  235. return ret;
  236. }
  237. /****************************************************************************
  238. * Name: romfs_close
  239. ****************************************************************************/
  240. static int romfs_close(FAR struct file *filep)
  241. {
  242. FAR struct romfs_mountpt_s *rm;
  243. FAR struct romfs_file_s *rf;
  244. int ret = OK;
  245. finfo("Closing\n");
  246. /* Sanity checks */
  247. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  248. /* Recover our private data from the struct file instance */
  249. rf = filep->f_priv;
  250. rm = filep->f_inode->i_private;
  251. DEBUGASSERT(rm != NULL);
  252. /* Do not check if the mount is healthy. We must support closing of
  253. * the file even when there is healthy mount.
  254. */
  255. /* Deallocate the memory structures created when the open method
  256. * was called.
  257. *
  258. * Free the sector buffer that was used to manage partial sector
  259. * accesses.
  260. */
  261. if (!rm->rm_xipbase && rf->rf_buffer)
  262. {
  263. kmm_free(rf->rf_buffer);
  264. }
  265. /* Then free the file structure itself. */
  266. kmm_free(rf);
  267. filep->f_priv = NULL;
  268. return ret;
  269. }
  270. /****************************************************************************
  271. * Name: romfs_read
  272. ****************************************************************************/
  273. static ssize_t romfs_read(FAR struct file *filep, FAR char *buffer,
  274. size_t buflen)
  275. {
  276. FAR struct romfs_mountpt_s *rm;
  277. FAR struct romfs_file_s *rf;
  278. unsigned int bytesread;
  279. unsigned int readsize;
  280. unsigned int nsectors;
  281. uint32_t offset;
  282. size_t bytesleft;
  283. off_t sector;
  284. FAR uint8_t *userbuffer = (FAR uint8_t *)buffer;
  285. int sectorndx;
  286. int ret;
  287. finfo("Read %zu bytes from offset %jd\n", buflen, (intmax_t)filep->f_pos);
  288. /* Sanity checks */
  289. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  290. /* Recover our private data from the struct file instance */
  291. rf = filep->f_priv;
  292. rm = filep->f_inode->i_private;
  293. DEBUGASSERT(rm != NULL);
  294. /* Make sure that the mount is still healthy */
  295. ret = romfs_semtake(rm);
  296. if (ret < 0)
  297. {
  298. return (ssize_t)ret;
  299. }
  300. ret = romfs_checkmount(rm);
  301. if (ret != OK)
  302. {
  303. ferr("ERROR: romfs_checkmount failed: %d\n", ret);
  304. goto errout_with_semaphore;
  305. }
  306. /* Get the number of bytes left in the file */
  307. bytesleft = rf->rf_size - filep->f_pos;
  308. /* Truncate read count so that it does not exceed the number
  309. * of bytes left in the file.
  310. */
  311. if (buflen > bytesleft)
  312. {
  313. buflen = bytesleft;
  314. }
  315. /* Loop until either (1) all data has been transferred, or (2) an
  316. * error occurs.
  317. */
  318. readsize = 0;
  319. while (buflen > 0)
  320. {
  321. /* Get the first sector and index to read from. */
  322. offset = rf->rf_startoffset + filep->f_pos;
  323. sector = SEC_NSECTORS(rm, offset);
  324. sectorndx = offset & SEC_NDXMASK(rm);
  325. /* Check if the user has provided a buffer large enough to
  326. * hold one or more complete sectors -AND- the read is
  327. * aligned to a sector boundary.
  328. */
  329. nsectors = SEC_NSECTORS(rm, buflen);
  330. if (nsectors > 0 && sectorndx == 0)
  331. {
  332. /* Read maximum contiguous sectors directly to the user's
  333. * buffer without using our tiny read buffer.
  334. */
  335. /* Read all of the sectors directly into user memory */
  336. finfo("Read %d sectors starting with %jd\n", nsectors,
  337. (intmax_t)sector);
  338. ret = romfs_hwread(rm, userbuffer, sector, nsectors);
  339. if (ret < 0)
  340. {
  341. ferr("ERROR: romfs_hwread failed: %d\n", ret);
  342. goto errout_with_semaphore;
  343. }
  344. bytesread = nsectors * rm->rm_hwsectorsize;
  345. }
  346. else
  347. {
  348. /* We are reading a partial sector. First, read the whole sector
  349. * into the file data buffer. This is a caching buffer so if
  350. * it is already there then all is well.
  351. */
  352. finfo("Read sector %jd\n", (intmax_t)sector);
  353. ret = romfs_filecacheread(rm, rf, sector);
  354. if (ret < 0)
  355. {
  356. ferr("ERROR: romfs_filecacheread failed: %d\n", ret);
  357. goto errout_with_semaphore;
  358. }
  359. /* Copy the partial sector into the user buffer */
  360. bytesread = rm->rm_hwsectorsize - sectorndx;
  361. if (bytesread > buflen)
  362. {
  363. /* We will not read to the end of the buffer */
  364. bytesread = buflen;
  365. }
  366. finfo("Return %d bytes from sector offset %d\n",
  367. bytesread, sectorndx);
  368. memcpy(userbuffer, &rf->rf_buffer[sectorndx], bytesread);
  369. }
  370. /* Set up for the next sector read */
  371. userbuffer += bytesread;
  372. filep->f_pos += bytesread;
  373. readsize += bytesread;
  374. buflen -= bytesread;
  375. }
  376. romfs_semgive(rm);
  377. return readsize;
  378. errout_with_semaphore:
  379. romfs_semgive(rm);
  380. return ret;
  381. }
  382. /****************************************************************************
  383. * Name: romfs_seek
  384. ****************************************************************************/
  385. static off_t romfs_seek(FAR struct file *filep, off_t offset, int whence)
  386. {
  387. FAR struct romfs_mountpt_s *rm;
  388. FAR struct romfs_file_s *rf;
  389. off_t position;
  390. int ret;
  391. finfo("Seek to offset: %jd whence: %d\n", (intmax_t)offset, whence);
  392. /* Sanity checks */
  393. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  394. /* Recover our private data from the struct file instance */
  395. rf = filep->f_priv;
  396. rm = filep->f_inode->i_private;
  397. DEBUGASSERT(rm != NULL);
  398. /* Map the offset according to the whence option */
  399. switch (whence)
  400. {
  401. case SEEK_SET: /* The offset is set to offset bytes. */
  402. position = offset;
  403. break;
  404. case SEEK_CUR: /* The offset is set to its current location plus
  405. * offset bytes. */
  406. position = offset + filep->f_pos;
  407. break;
  408. case SEEK_END: /* The offset is set to the size of the file plus
  409. * offset bytes. */
  410. position = offset + rf->rf_size;
  411. break;
  412. default:
  413. ferr("ERROR: Whence is invalid: %d\n", whence);
  414. return -EINVAL;
  415. }
  416. /* Make sure that the mount is still healthy */
  417. ret = romfs_semtake(rm);
  418. if (ret < 0)
  419. {
  420. return (off_t)ret;
  421. }
  422. ret = romfs_checkmount(rm);
  423. if (ret != OK)
  424. {
  425. ferr("ERROR: romfs_checkmount failed: %d\n", ret);
  426. goto errout_with_semaphore;
  427. }
  428. /* Limit positions to the end of the file. */
  429. if (position > rf->rf_size)
  430. {
  431. /* Otherwise, the position is limited to the file size */
  432. position = rf->rf_size;
  433. }
  434. /* Set file position and return success */
  435. filep->f_pos = position;
  436. finfo("New file position: %jd\n", (intmax_t)filep->f_pos);
  437. romfs_semgive(rm);
  438. return OK;
  439. errout_with_semaphore:
  440. romfs_semgive(rm);
  441. return ret;
  442. }
  443. /****************************************************************************
  444. * Name: romfs_ioctl
  445. ****************************************************************************/
  446. static int romfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  447. {
  448. FAR struct romfs_mountpt_s *rm;
  449. FAR struct romfs_file_s *rf;
  450. FAR void **ppv = (FAR void**)arg;
  451. finfo("cmd: %d arg: %08lx\n", cmd, arg);
  452. /* Sanity checks */
  453. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  454. /* Recover our private data from the struct file instance */
  455. rf = filep->f_priv;
  456. rm = filep->f_inode->i_private;
  457. DEBUGASSERT(rm != NULL);
  458. /* Only one ioctl command is supported */
  459. if (cmd == FIOC_MMAP && rm->rm_xipbase && ppv)
  460. {
  461. /* Return the address on the media corresponding to the start of
  462. * the file.
  463. */
  464. *ppv = (FAR void *)(rm->rm_xipbase + rf->rf_startoffset);
  465. return OK;
  466. }
  467. ferr("ERROR: Invalid cmd: %d \n", cmd);
  468. return -ENOTTY;
  469. }
  470. /****************************************************************************
  471. * Name: romfs_dup
  472. ****************************************************************************/
  473. static int romfs_dup(FAR const struct file *oldp, FAR struct file *newp)
  474. {
  475. FAR struct romfs_mountpt_s *rm;
  476. FAR struct romfs_file_s *oldrf;
  477. FAR struct romfs_file_s *newrf;
  478. int ret;
  479. finfo("Dup %p->%p\n", oldp, newp);
  480. /* Sanity checks */
  481. DEBUGASSERT(oldp->f_priv != NULL &&
  482. newp->f_priv == NULL &&
  483. newp->f_inode != NULL);
  484. /* Get mountpoint private data from the inode reference from the file
  485. * structure
  486. */
  487. rm = (FAR struct romfs_mountpt_s *)newp->f_inode->i_private;
  488. DEBUGASSERT(rm != NULL);
  489. /* Check if the mount is still healthy */
  490. ret = romfs_semtake(rm);
  491. if (ret < 0)
  492. {
  493. return ret;
  494. }
  495. ret = romfs_checkmount(rm);
  496. if (ret != OK)
  497. {
  498. ferr("ERROR: romfs_checkmount failed: %d\n", ret);
  499. goto errout_with_semaphore;
  500. }
  501. /* Recover the old private data from the old struct file instance */
  502. oldrf = oldp->f_priv;
  503. /* Create an new instance of the file private data to describe the new
  504. * dup'ed file.
  505. */
  506. newrf = (FAR struct romfs_file_s *)kmm_malloc(sizeof(struct romfs_file_s));
  507. if (!newrf)
  508. {
  509. ferr("ERROR: Failed to allocate private data\n");
  510. ret = -ENOMEM;
  511. goto errout_with_semaphore;
  512. }
  513. /* Copy all file private data (except for the buffer) */
  514. newrf->rf_startoffset = oldrf->rf_startoffset;
  515. newrf->rf_size = oldrf->rf_size;
  516. /* Configure buffering to support access to this file */
  517. ret = romfs_fileconfigure(rm, newrf);
  518. if (ret < 0)
  519. {
  520. kmm_free(newrf);
  521. ferr("ERROR: Failed configure buffering: %d\n", ret);
  522. goto errout_with_semaphore;
  523. }
  524. /* Attach the new private date to the new struct file instance */
  525. newp->f_priv = newrf;
  526. /* Then insert the new instance into the mountpoint structure.
  527. * It needs to be there (1) to handle error conditions that effect
  528. * all files, and (2) to inform the umount logic that we are busy
  529. * (but a simple reference count could have done that).
  530. */
  531. newrf->rf_next = rm->rm_head;
  532. rm->rm_head = newrf->rf_next;
  533. romfs_semgive(rm);
  534. return OK;
  535. /* Error exits */
  536. errout_with_semaphore:
  537. romfs_semgive(rm);
  538. return ret;
  539. }
  540. /****************************************************************************
  541. * Name: romfs_fstat
  542. *
  543. * Description:
  544. * Obtain information about an open file associated with the file
  545. * descriptor 'fd', and will write it to the area pointed to by 'buf'.
  546. *
  547. ****************************************************************************/
  548. static int romfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
  549. {
  550. FAR struct romfs_mountpt_s *rm;
  551. FAR struct romfs_file_s *rf;
  552. int ret;
  553. finfo("fstat\n");
  554. /* Sanity checks */
  555. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  556. /* Get mountpoint private data from the inode reference from the file
  557. * structure
  558. */
  559. rf = filep->f_priv;
  560. rm = (FAR struct romfs_mountpt_s *)filep->f_inode->i_private;
  561. DEBUGASSERT(rm != NULL);
  562. /* Check if the mount is still healthy */
  563. ret = romfs_semtake(rm);
  564. if (ret < 0)
  565. {
  566. return ret;
  567. }
  568. ret = romfs_checkmount(rm);
  569. if (ret >= 0)
  570. {
  571. /* Return information about the directory entry */
  572. ret = romfs_stat_common(rf->rf_type, rf->rf_size,
  573. rm->rm_hwsectorsize, buf);
  574. }
  575. romfs_semgive(rm);
  576. return ret;
  577. }
  578. /****************************************************************************
  579. * Name: romfs_opendir
  580. *
  581. * Description:
  582. * Open a directory for read access
  583. *
  584. ****************************************************************************/
  585. static int romfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
  586. FAR struct fs_dirent_s *dir)
  587. {
  588. FAR struct romfs_mountpt_s *rm;
  589. FAR struct romfs_dirinfo_s dirinfo;
  590. int ret;
  591. finfo("relpath: '%s'\n", relpath);
  592. /* Sanity checks */
  593. DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
  594. /* Recover our private data from the inode instance */
  595. rm = mountpt->i_private;
  596. /* Make sure that the mount is still healthy */
  597. ret = romfs_semtake(rm);
  598. if (ret < 0)
  599. {
  600. return ret;
  601. }
  602. ret = romfs_checkmount(rm);
  603. if (ret != OK)
  604. {
  605. ferr("ERROR: romfs_checkmount failed: %d\n", ret);
  606. goto errout_with_semaphore;
  607. }
  608. /* Find the requested directory */
  609. ret = romfs_finddirentry(rm, &dirinfo, relpath);
  610. if (ret < 0)
  611. {
  612. ferr("ERROR: Failed to find directory '%s': %d\n", relpath, ret);
  613. goto errout_with_semaphore;
  614. }
  615. /* Verify that it is some kind of directory */
  616. if (!IS_DIRECTORY(dirinfo.rd_next))
  617. {
  618. /* The entry is not a directory */
  619. ferr("ERROR: '%s' is not a directory\n", relpath);
  620. ret = -ENOTDIR;
  621. goto errout_with_semaphore;
  622. }
  623. /* The entry is a directory */
  624. memcpy(&dir->u.romfs, &dirinfo.rd_dir, sizeof(struct fs_romfsdir_s));
  625. romfs_semgive(rm);
  626. return OK;
  627. errout_with_semaphore:
  628. romfs_semgive(rm);
  629. return ret;
  630. }
  631. /****************************************************************************
  632. * Name: romfs_readdir
  633. *
  634. * Description: Read the next directory entry
  635. *
  636. ****************************************************************************/
  637. static int romfs_readdir(FAR struct inode *mountpt,
  638. FAR struct fs_dirent_s *dir)
  639. {
  640. FAR struct romfs_mountpt_s *rm;
  641. uint32_t linkoffset;
  642. uint32_t next;
  643. uint32_t info;
  644. uint32_t size;
  645. int ret;
  646. finfo("Entry\n");
  647. /* Sanity checks */
  648. DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
  649. /* Recover our private data from the inode instance */
  650. rm = mountpt->i_private;
  651. /* Make sure that the mount is still healthy */
  652. ret = romfs_semtake(rm);
  653. if (ret < 0)
  654. {
  655. return ret;
  656. }
  657. ret = romfs_checkmount(rm);
  658. if (ret != OK)
  659. {
  660. ferr("ERROR: omfs_checkmount failed: %d\n", ret);
  661. goto errout_with_semaphore;
  662. }
  663. /* Loop, skipping over unsupported items in the file system */
  664. for (; ; )
  665. {
  666. /* Have we reached the end of the directory */
  667. if (!dir->u.romfs.fr_curroffset)
  668. {
  669. /* We signal the end of the directory by returning the
  670. * special error -ENOENT
  671. */
  672. finfo("End of directory\n");
  673. ret = -ENOENT;
  674. goto errout_with_semaphore;
  675. }
  676. /* Parse the directory entry */
  677. ret = romfs_parsedirentry(rm, dir->u.romfs.fr_curroffset, &linkoffset,
  678. &next, &info, &size);
  679. if (ret < 0)
  680. {
  681. ferr("ERROR: romfs_parsedirentry failed: %d\n", ret);
  682. goto errout_with_semaphore;
  683. }
  684. /* Save the filename */
  685. ret = romfs_parsefilename(rm, dir->u.romfs.fr_curroffset,
  686. dir->fd_dir.d_name);
  687. if (ret < 0)
  688. {
  689. ferr("ERROR: romfs_parsefilename failed: %d\n", ret);
  690. goto errout_with_semaphore;
  691. }
  692. /* Set up the next directory entry offset */
  693. dir->u.romfs.fr_curroffset = next & RFNEXT_OFFSETMASK;
  694. /* Check the file type */
  695. if (IS_DIRECTORY(next))
  696. {
  697. dir->fd_dir.d_type = DTYPE_DIRECTORY;
  698. break;
  699. }
  700. else if (IS_FILE(next))
  701. {
  702. dir->fd_dir.d_type = DTYPE_FILE;
  703. break;
  704. }
  705. else if (IS_SOFTLINK(next))
  706. {
  707. dir->fd_dir.d_type = DTYPE_LINK;
  708. break;
  709. }
  710. }
  711. errout_with_semaphore:
  712. romfs_semgive(rm);
  713. return ret;
  714. }
  715. /****************************************************************************
  716. * Name: romfs_rewindir
  717. *
  718. * Description: Reset directory read to the first entry
  719. *
  720. ****************************************************************************/
  721. static int romfs_rewinddir(FAR struct inode *mountpt,
  722. FAR struct fs_dirent_s *dir)
  723. {
  724. FAR struct romfs_mountpt_s *rm;
  725. int ret;
  726. finfo("Entry\n");
  727. /* Sanity checks */
  728. DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
  729. /* Recover our private data from the inode instance */
  730. rm = mountpt->i_private;
  731. /* Make sure that the mount is still healthy */
  732. ret = romfs_semtake(rm);
  733. if (ret < 0)
  734. {
  735. return ret;
  736. }
  737. ret = romfs_checkmount(rm);
  738. if (ret == OK)
  739. {
  740. dir->u.romfs.fr_curroffset = dir->u.romfs.fr_firstoffset;
  741. }
  742. romfs_semgive(rm);
  743. return ret;
  744. }
  745. /****************************************************************************
  746. * Name: romfs_bind
  747. *
  748. * Description: This implements a portion of the mount operation. This
  749. * function allocates and initializes the mountpoint private data and
  750. * binds the blockdriver inode to the filesystem private data. The final
  751. * binding of the private data (containing the blockdriver) to the
  752. * mountpoint is performed by mount().
  753. *
  754. ****************************************************************************/
  755. static int romfs_bind(FAR struct inode *blkdriver, FAR const void *data,
  756. FAR void **handle)
  757. {
  758. struct romfs_mountpt_s *rm;
  759. int ret;
  760. finfo("Entry\n");
  761. /* Open the block driver */
  762. if (blkdriver == NULL)
  763. {
  764. ferr("ERROR: No block driver/ops\n");
  765. return -ENODEV;
  766. }
  767. if (INODE_IS_BLOCK(blkdriver) &&
  768. blkdriver->u.i_bops->open != NULL &&
  769. blkdriver->u.i_bops->open(blkdriver) != OK)
  770. {
  771. ferr("ERROR: No open method\n");
  772. return -ENODEV;
  773. }
  774. /* Create an instance of the mountpt state structure */
  775. rm = (FAR struct romfs_mountpt_s *)
  776. kmm_zalloc(sizeof(struct romfs_mountpt_s));
  777. if (!rm)
  778. {
  779. ferr("ERROR: Failed to allocate mountpoint structure\n");
  780. return -ENOMEM;
  781. }
  782. /* Initialize the allocated mountpt state structure. The filesystem is
  783. * responsible for one reference ont the blkdriver inode and does not
  784. * have to addref() here (but does have to release in ubind().
  785. */
  786. nxsem_init(&rm->rm_sem, 0, 0); /* Initialize the semaphore that controls access */
  787. rm->rm_blkdriver = blkdriver; /* Save the block driver reference */
  788. /* Get the hardware configuration and setup buffering appropriately */
  789. ret = romfs_hwconfigure(rm);
  790. if (ret < 0)
  791. {
  792. ferr("ERROR: romfs_hwconfigure failed: %d\n", ret);
  793. goto errout_with_sem;
  794. }
  795. /* Then complete the mount by getting the ROMFS configuratrion from
  796. * the ROMF header
  797. */
  798. ret = romfs_fsconfigure(rm);
  799. if (ret < 0)
  800. {
  801. ferr("ERROR: romfs_fsconfigure failed: %d\n", ret);
  802. goto errout_with_buffer;
  803. }
  804. /* Mounted! */
  805. *handle = (FAR void *)rm;
  806. romfs_semgive(rm);
  807. return OK;
  808. errout_with_buffer:
  809. if (!rm->rm_xipbase)
  810. {
  811. kmm_free(rm->rm_buffer);
  812. }
  813. errout_with_sem:
  814. nxsem_destroy(&rm->rm_sem);
  815. kmm_free(rm);
  816. return ret;
  817. }
  818. /****************************************************************************
  819. * Name: romfs_unbind
  820. *
  821. * Description: This implements the filesystem portion of the umount
  822. * operation.
  823. *
  824. ****************************************************************************/
  825. static int romfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
  826. unsigned int flags)
  827. {
  828. FAR struct romfs_mountpt_s *rm = (FAR struct romfs_mountpt_s *)handle;
  829. int ret;
  830. finfo("Entry\n");
  831. #ifdef CONFIG_DEBUG_FEATURES
  832. if (!rm)
  833. {
  834. return -EINVAL;
  835. }
  836. #endif
  837. /* Check if there are sill any files opened on the filesystem. */
  838. ret = romfs_semtake(rm);
  839. if (ret < 0)
  840. {
  841. return ret;
  842. }
  843. if (rm->rm_head)
  844. {
  845. /* We cannot unmount now.. there are open files */
  846. fwarn("WARNING: There are open files\n");
  847. /* This implementation currently only supports unmounting if there are
  848. * no open file references.
  849. */
  850. ret = (flags != 0) ? -ENOSYS : -EBUSY;
  851. }
  852. else
  853. {
  854. /* Unmount ... close the block driver */
  855. if (rm->rm_blkdriver)
  856. {
  857. struct inode *inode = rm->rm_blkdriver;
  858. if (inode)
  859. {
  860. if (INODE_IS_BLOCK(inode) && inode->u.i_bops->close != NULL)
  861. {
  862. inode->u.i_bops->close(inode);
  863. }
  864. /* We hold a reference to the block driver but should
  865. * not but mucking with inodes in this context. So, we will
  866. * just return our contained reference to the block driver
  867. * inode and let the umount logic dispose of it.
  868. */
  869. if (blkdriver)
  870. {
  871. *blkdriver = inode;
  872. }
  873. }
  874. }
  875. /* Release the mountpoint private data */
  876. if (!rm->rm_xipbase && rm->rm_buffer)
  877. {
  878. kmm_free(rm->rm_buffer);
  879. }
  880. nxsem_destroy(&rm->rm_sem);
  881. kmm_free(rm);
  882. return OK;
  883. }
  884. romfs_semgive(rm);
  885. return ret;
  886. }
  887. /****************************************************************************
  888. * Name: romfs_statfs
  889. *
  890. * Description: Return filesystem statistics
  891. *
  892. ****************************************************************************/
  893. static int romfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
  894. {
  895. FAR struct romfs_mountpt_s *rm;
  896. int ret;
  897. finfo("Entry\n");
  898. /* Sanity checks */
  899. DEBUGASSERT(mountpt && mountpt->i_private);
  900. /* Get the mountpoint private data from the inode structure */
  901. rm = mountpt->i_private;
  902. /* Check if the mount is still healthy */
  903. ret = romfs_semtake(rm);
  904. if (ret < 0)
  905. {
  906. return ret;
  907. }
  908. ret = romfs_checkmount(rm);
  909. if (ret < 0)
  910. {
  911. ferr("ERROR: romfs_checkmount failed: %d\n", ret);
  912. goto errout_with_semaphore;
  913. }
  914. /* Fill in the statfs info */
  915. memset(buf, 0, sizeof(struct statfs));
  916. buf->f_type = ROMFS_MAGIC;
  917. /* We will claim that the optimal transfer size is the size of one sector */
  918. buf->f_bsize = rm->rm_hwsectorsize;
  919. /* Everything else follows in units of sectors */
  920. buf->f_blocks = SEC_NSECTORS(rm, rm->rm_volsize + SEC_NDXMASK(rm));
  921. buf->f_bfree = 0;
  922. buf->f_bavail = 0;
  923. buf->f_namelen = NAME_MAX;
  924. romfs_semgive(rm);
  925. return OK;
  926. errout_with_semaphore:
  927. romfs_semgive(rm);
  928. return ret;
  929. }
  930. /****************************************************************************
  931. * Name: romfs_stat_common
  932. *
  933. * Description:
  934. * Return information about a file or directory
  935. *
  936. ****************************************************************************/
  937. static int romfs_stat_common(uint8_t type, uint32_t size,
  938. uint16_t sectorsize, FAR struct stat *buf)
  939. {
  940. memset(buf, 0, sizeof(struct stat));
  941. if (IS_DIRECTORY(type))
  942. {
  943. /* It's a read-execute directory name */
  944. buf->st_mode = S_IFDIR | S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP |
  945. S_IRUSR | S_IXUSR;
  946. }
  947. else if (IS_FILE(type) || IS_SOFTLINK(type))
  948. {
  949. if (IS_FILE(type))
  950. {
  951. buf->st_mode = S_IFREG;
  952. }
  953. else
  954. {
  955. buf->st_mode = S_IFLNK;
  956. }
  957. /* It's a read-only file name */
  958. buf->st_mode |= S_IROTH | S_IRGRP | S_IRUSR;
  959. if (IS_EXECUTABLE(type))
  960. {
  961. /* It's a read-execute file name */
  962. buf->st_mode |= S_IXOTH | S_IXGRP | S_IXUSR;
  963. }
  964. }
  965. else
  966. {
  967. /* Otherwise, pretend like the unsupported type does not exist */
  968. finfo("Unsupported type: %d\n", type);
  969. return -ENOENT;
  970. }
  971. /* File/directory size, access block size */
  972. buf->st_size = size;
  973. buf->st_blksize = sectorsize;
  974. buf->st_blocks = (buf->st_size + sectorsize - 1) / sectorsize;
  975. return OK;
  976. }
  977. /****************************************************************************
  978. * Name: romfs_stat
  979. *
  980. * Description: Return information about a file or directory
  981. *
  982. ****************************************************************************/
  983. static int romfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
  984. FAR struct stat *buf)
  985. {
  986. FAR struct romfs_mountpt_s *rm;
  987. FAR struct romfs_dirinfo_s dirinfo;
  988. uint8_t type;
  989. int ret;
  990. finfo("Entry\n");
  991. /* Sanity checks */
  992. DEBUGASSERT(mountpt && mountpt->i_private);
  993. /* Get the mountpoint private data from the inode structure */
  994. rm = mountpt->i_private;
  995. /* Check if the mount is still healthy */
  996. ret = romfs_semtake(rm);
  997. if (ret < 0)
  998. {
  999. return ret;
  1000. }
  1001. ret = romfs_checkmount(rm);
  1002. if (ret != OK)
  1003. {
  1004. ferr("ERROR: romfs_checkmount failed: %d\n", ret);
  1005. goto errout_with_semaphore;
  1006. }
  1007. /* Find the directory entry corresponding to relpath. */
  1008. ret = romfs_finddirentry(rm, &dirinfo, relpath);
  1009. /* If nothing was found, then we fail with EEXIST */
  1010. if (ret < 0)
  1011. {
  1012. finfo("Failed to find directory: %d\n", ret);
  1013. goto errout_with_semaphore;
  1014. }
  1015. /* Return information about the directory entry */
  1016. type = (uint8_t)(dirinfo.rd_next & RFNEXT_ALLMODEMASK);
  1017. ret = romfs_stat_common(type, dirinfo.rd_size, rm->rm_hwsectorsize, buf);
  1018. errout_with_semaphore:
  1019. romfs_semgive(rm);
  1020. return ret;
  1021. }
  1022. /****************************************************************************
  1023. * Public Functions
  1024. ****************************************************************************/