fs_romfs.c 34 KB

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