hostfs.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. /****************************************************************************
  2. * nuttx/fs/hostfs/hostfs.c
  3. *
  4. * Copyright (C) 2015 Ken Pettit. All rights reserved.
  5. * Author: Ken Pettit <pettitkd@gmail.com>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <sys/stat.h>
  41. #include <sys/statfs.h>
  42. #include <stdlib.h>
  43. #include <unistd.h>
  44. #include <string.h>
  45. #include <semaphore.h>
  46. #include <assert.h>
  47. #include <fcntl.h>
  48. #include <errno.h>
  49. #include <debug.h>
  50. #include <nuttx/kmalloc.h>
  51. #include <nuttx/fs/fs.h>
  52. #include <nuttx/fs/fat.h>
  53. #include <nuttx/fs/dirent.h>
  54. #include <nuttx/fs/ioctl.h>
  55. #include <nuttx/fs/hostfs.h>
  56. #include "hostfs.h"
  57. /****************************************************************************
  58. * Pre-processor Definitions
  59. ****************************************************************************/
  60. #define HOSTFS_RETRY_DELAY_MS 10
  61. /****************************************************************************
  62. * Private Function Prototypes
  63. ****************************************************************************/
  64. static int hostfs_open(FAR struct file *filep, FAR const char *relpath,
  65. int oflags, mode_t mode);
  66. static int hostfs_close(FAR struct file *filep);
  67. static ssize_t hostfs_read(FAR struct file *filep, FAR char *buffer,
  68. size_t buflen);
  69. static ssize_t hostfs_write(FAR struct file *filep, FAR const char *buffer,
  70. size_t buflen);
  71. static off_t hostfs_seek(FAR struct file *filep, off_t offset,
  72. int whence);
  73. static int hostfs_ioctl(FAR struct file *filep, int cmd,
  74. unsigned long arg);
  75. static int hostfs_sync(FAR struct file *filep);
  76. static int hostfs_dup(FAR const struct file *oldp,
  77. FAR struct file *newp);
  78. static int hostfs_fstat(FAR const struct file *filep,
  79. FAR struct stat *buf);
  80. static int hostfs_ftruncate(FAR struct file *filep,
  81. off_t length);
  82. static int hostfs_opendir(FAR struct inode *mountpt,
  83. FAR const char *relpath,
  84. FAR struct fs_dirent_s *dir);
  85. static int hostfs_closedir(FAR struct inode *mountpt,
  86. FAR struct fs_dirent_s *dir);
  87. static int hostfs_readdir(FAR struct inode *mountpt,
  88. FAR struct fs_dirent_s *dir);
  89. static int hostfs_rewinddir(FAR struct inode *mountpt,
  90. FAR struct fs_dirent_s *dir);
  91. static int hostfs_bind(FAR struct inode *blkdriver,
  92. FAR const void *data, FAR void **handle);
  93. static int hostfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
  94. unsigned int flags);
  95. static int hostfs_statfs(FAR struct inode *mountpt,
  96. FAR struct statfs *buf);
  97. static int hostfs_unlink(FAR struct inode *mountpt,
  98. FAR const char *relpath);
  99. static int hostfs_mkdir(FAR struct inode *mountpt,
  100. FAR const char *relpath, mode_t mode);
  101. static int hostfs_rmdir(FAR struct inode *mountpt, const char *relpath);
  102. static int hostfs_rename(FAR struct inode *mountpt,
  103. FAR const char *oldrelpath,
  104. FAR const char *newrelpath);
  105. static int hostfs_stat(FAR struct inode *mountpt,
  106. FAR const char *relpath, FAR struct stat *buf);
  107. /****************************************************************************
  108. * Private Data
  109. ****************************************************************************/
  110. static uint8_t g_seminitialized = FALSE;
  111. static sem_t g_sem;
  112. /****************************************************************************
  113. * Public Data
  114. ****************************************************************************/
  115. /* See fs_mount.c -- this structure is explicitly externed there.
  116. * We use the old-fashioned kind of initializers so that this will compile
  117. * with any compiler.
  118. */
  119. const struct mountpt_operations hostfs_operations =
  120. {
  121. hostfs_open, /* open */
  122. hostfs_close, /* close */
  123. hostfs_read, /* read */
  124. hostfs_write, /* write */
  125. hostfs_seek, /* seek */
  126. hostfs_ioctl, /* ioctl */
  127. hostfs_sync, /* sync */
  128. hostfs_dup, /* dup */
  129. hostfs_fstat, /* fstat */
  130. hostfs_ftruncate, /* ftruncate */
  131. hostfs_opendir, /* opendir */
  132. hostfs_closedir, /* closedir */
  133. hostfs_readdir, /* readdir */
  134. hostfs_rewinddir, /* rewinddir */
  135. hostfs_bind, /* bind */
  136. hostfs_unbind, /* unbind */
  137. hostfs_statfs, /* statfs */
  138. hostfs_unlink, /* unlinke */
  139. hostfs_mkdir, /* mkdir */
  140. hostfs_rmdir, /* rmdir */
  141. hostfs_rename, /* rename */
  142. hostfs_stat /* stat */
  143. };
  144. /****************************************************************************
  145. * Private Functions
  146. ****************************************************************************/
  147. /****************************************************************************
  148. * Name: hostfs_semtake
  149. ****************************************************************************/
  150. void hostfs_semtake(FAR struct hostfs_mountpt_s *fs)
  151. {
  152. int ret;
  153. do
  154. {
  155. /* Take the semaphore (perhaps waiting) */
  156. ret = nxsem_wait(fs->fs_sem);
  157. /* The only case that an error should occur here is if the wait was
  158. * awakened by a signal.
  159. */
  160. DEBUGASSERT(ret == OK || ret == -EINTR);
  161. }
  162. while (ret == -EINTR);
  163. }
  164. /****************************************************************************
  165. * Name: hostfs_semgive
  166. ****************************************************************************/
  167. void hostfs_semgive(FAR struct hostfs_mountpt_s *fs)
  168. {
  169. nxsem_post(fs->fs_sem);
  170. }
  171. /****************************************************************************
  172. * Name: hostfs_mkpath
  173. *
  174. * Description: Build absolute host path from relative NuttX path.
  175. *
  176. ****************************************************************************/
  177. static void hostfs_mkpath(FAR struct hostfs_mountpt_s *fs,
  178. FAR const char *relpath,
  179. FAR char *path, int pathlen)
  180. {
  181. int depth = 0;
  182. int first;
  183. int x;
  184. /* Copy base host path to output */
  185. strncpy(path, fs->fs_root, pathlen);
  186. /* Be sure we aren't trying to use ".." to display outside of our
  187. * mounted path.
  188. */
  189. x = 0;
  190. while (relpath[x] == '/')
  191. {
  192. x++;
  193. }
  194. first = x;
  195. while (relpath[x] != '\0')
  196. {
  197. /* Test for ".." occurance */
  198. if (strncmp(&relpath[x], "..", 2) == 0)
  199. {
  200. /* Reduce depth by 1 */
  201. depth--;
  202. x += 2;
  203. }
  204. else if (relpath[x] == '/' && relpath[x + 1] != '/' &&
  205. relpath[x + 1] != '\0')
  206. {
  207. depth++;
  208. x++;
  209. }
  210. else
  211. {
  212. x++;
  213. }
  214. }
  215. if (depth >= 0)
  216. {
  217. strncat(path, &relpath[first], pathlen - strlen(path) - 1);
  218. }
  219. }
  220. /****************************************************************************
  221. * Name: hostfs_open
  222. ****************************************************************************/
  223. static int hostfs_open(FAR struct file *filep, FAR const char *relpath,
  224. int oflags, mode_t mode)
  225. {
  226. FAR struct inode *inode;
  227. FAR struct hostfs_mountpt_s *fs;
  228. FAR struct hostfs_ofile_s *hf;
  229. char path[HOSTFS_MAX_PATH];
  230. int ret;
  231. /* Sanity checks */
  232. DEBUGASSERT((filep->f_priv == NULL) && (filep->f_inode != NULL));
  233. /* Get the mountpoint inode reference from the file structure and the
  234. * mountpoint private data from the inode structure
  235. */
  236. inode = filep->f_inode;
  237. fs = inode->i_private;
  238. DEBUGASSERT(fs != NULL);
  239. /* Take the semaphore */
  240. hostfs_semtake(fs);
  241. /* Allocate memory for the open file */
  242. hf = (struct hostfs_ofile_s *) kmm_malloc(sizeof *hf);
  243. if (hf == NULL)
  244. {
  245. ret = -ENOMEM;
  246. goto errout_with_semaphore;
  247. }
  248. /* Append to the host's root directory */
  249. hostfs_mkpath(fs, relpath, path, sizeof(path));
  250. /* Try to open the file in the host file system */
  251. hf->fd = host_open(path, oflags, mode);
  252. if (hf->fd < 0)
  253. {
  254. /* Error opening file */
  255. ret = -EBADF;
  256. goto errout_with_buffer;
  257. }
  258. /* In write/append mode, we need to set the file pointer to the end of the
  259. * file.
  260. */
  261. if ((oflags & (O_APPEND | O_WRONLY)) == (O_APPEND | O_WRONLY))
  262. {
  263. ret = host_lseek(hf->fd, 0, SEEK_END);
  264. if (ret >= 0)
  265. {
  266. filep->f_pos = ret;
  267. }
  268. else
  269. {
  270. goto errout_with_buffer;
  271. }
  272. }
  273. /* Attach the private date to the struct file instance */
  274. filep->f_priv = hf;
  275. /* Then insert the new instance into the mountpoint structure.
  276. * It needs to be there (1) to handle error conditions that effect
  277. * all files, and (2) to inform the umount logic that we are busy
  278. * (but a simple reference count could have done that).
  279. */
  280. hf->fnext = fs->fs_head;
  281. hf->crefs = 1;
  282. hf->oflags = oflags;
  283. fs->fs_head = hf;
  284. ret = OK;
  285. goto errout_with_semaphore;
  286. errout_with_buffer:
  287. kmm_free(hf);
  288. errout_with_semaphore:
  289. hostfs_semgive(fs);
  290. if (ret == -EINVAL)
  291. {
  292. ret = -EIO;
  293. }
  294. return ret;
  295. }
  296. /****************************************************************************
  297. * Name: hostfs_close
  298. ****************************************************************************/
  299. static int hostfs_close(FAR struct file *filep)
  300. {
  301. FAR struct inode *inode;
  302. FAR struct hostfs_mountpt_s *fs;
  303. FAR struct hostfs_ofile_s *hf;
  304. FAR struct hostfs_ofile_s *nextfile;
  305. FAR struct hostfs_ofile_s *prevfile;
  306. /* Sanity checks */
  307. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  308. /* Recover our private data from the struct file instance */
  309. inode = filep->f_inode;
  310. fs = inode->i_private;
  311. hf = filep->f_priv;
  312. /* Take the semaphore */
  313. hostfs_semtake(fs);
  314. /* Check if we are the last one with a reference to the file and
  315. * only close if we are.
  316. */
  317. if (hf->crefs > 1)
  318. {
  319. /* The file is opened more than once. Just decrement the
  320. * reference count and return.
  321. */
  322. hf->crefs--;
  323. goto okout;
  324. }
  325. /* Remove ourselves from the linked list */
  326. nextfile = fs->fs_head;
  327. prevfile = nextfile;
  328. while ((nextfile != hf) && (nextfile != NULL))
  329. {
  330. /* Save the previous file pointer too */
  331. prevfile = nextfile;
  332. nextfile = nextfile->fnext;
  333. }
  334. if (nextfile != NULL)
  335. {
  336. /* Test if we were the first entry */
  337. if (nextfile == fs->fs_head)
  338. {
  339. /* Assign a new head */
  340. fs->fs_head = nextfile->fnext;
  341. }
  342. else
  343. {
  344. /* Take ourselves out of the list */
  345. prevfile->fnext = nextfile->fnext;
  346. }
  347. }
  348. /* Close the host file */
  349. host_close(hf->fd);
  350. /* Now free the pointer */
  351. filep->f_priv = NULL;
  352. kmm_free(hf);
  353. okout:
  354. hostfs_semgive(fs);
  355. return OK;
  356. }
  357. /****************************************************************************
  358. * Name: hostfs_read
  359. ****************************************************************************/
  360. static ssize_t hostfs_read(FAR struct file *filep, FAR char *buffer,
  361. size_t buflen)
  362. {
  363. FAR struct inode *inode;
  364. FAR struct hostfs_mountpt_s *fs;
  365. FAR struct hostfs_ofile_s *hf;
  366. ssize_t ret;
  367. /* Sanity checks */
  368. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  369. /* Recover our private data from the struct file instance */
  370. hf = filep->f_priv;
  371. inode = filep->f_inode;
  372. fs = inode->i_private;
  373. DEBUGASSERT(fs != NULL);
  374. /* Take the semaphore */
  375. hostfs_semtake(fs);
  376. /* Call the host to perform the read */
  377. ret = host_read(hf->fd, buffer, buflen);
  378. if (ret > 0)
  379. {
  380. filep->f_pos += ret;
  381. }
  382. hostfs_semgive(fs);
  383. return ret;
  384. }
  385. /****************************************************************************
  386. * Name: hostfs_write
  387. ****************************************************************************/
  388. static ssize_t hostfs_write(FAR struct file *filep, const char *buffer,
  389. size_t buflen)
  390. {
  391. FAR struct inode *inode;
  392. FAR struct hostfs_mountpt_s *fs;
  393. FAR struct hostfs_ofile_s *hf;
  394. ssize_t ret;
  395. /* Sanity checks. I have seen the following assertion misfire if
  396. * CONFIG_DEBUG_MM is enabled while re-directing output to a
  397. * file. In this case, the debug output can get generated while
  398. * the file is being opened, FAT data structures are being allocated,
  399. * and things are generally in a perverse state.
  400. */
  401. #ifdef CONFIG_DEBUG_MM
  402. if (filep->f_priv == NULL || filep->f_inode == NULL)
  403. {
  404. return -ENXIO;
  405. }
  406. #else
  407. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  408. #endif
  409. /* Recover our private data from the struct file instance */
  410. hf = filep->f_priv;
  411. inode = filep->f_inode;
  412. fs = inode->i_private;
  413. DEBUGASSERT(fs != NULL);
  414. /* Take the semaphore */
  415. hostfs_semtake(fs);
  416. /* Test the permissions. Only allow write if the file was opened with
  417. * write flags.
  418. */
  419. if ((hf->oflags & O_WROK) == 0)
  420. {
  421. ret = -EACCES;
  422. goto errout_with_semaphore;
  423. }
  424. /* Call the host to perform the write */
  425. ret = host_write(hf->fd, buffer, buflen);
  426. if (ret > 0)
  427. {
  428. filep->f_pos += ret;
  429. }
  430. errout_with_semaphore:
  431. hostfs_semgive(fs);
  432. return ret;
  433. }
  434. /****************************************************************************
  435. * Name: hostfs_seek
  436. ****************************************************************************/
  437. static off_t hostfs_seek(FAR struct file *filep, off_t offset, int whence)
  438. {
  439. FAR struct inode *inode;
  440. FAR struct hostfs_mountpt_s *fs;
  441. FAR struct hostfs_ofile_s *hf;
  442. off_t ret;
  443. /* Sanity checks */
  444. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  445. /* Recover our private data from the struct file instance */
  446. hf = filep->f_priv;
  447. inode = filep->f_inode;
  448. fs = inode->i_private;
  449. DEBUGASSERT(fs != NULL);
  450. /* Take the semaphore */
  451. hostfs_semtake(fs);
  452. /* Call our internal routine to perform the seek */
  453. ret = host_lseek(hf->fd, offset, whence);
  454. if (ret >= 0)
  455. {
  456. filep->f_pos = ret;
  457. }
  458. hostfs_semgive(fs);
  459. return ret;
  460. }
  461. /****************************************************************************
  462. * Name: hostfs_ioctl
  463. ****************************************************************************/
  464. static int hostfs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  465. {
  466. FAR struct inode *inode;
  467. FAR struct hostfs_mountpt_s *fs;
  468. FAR struct hostfs_ofile_s *hf;
  469. int ret;
  470. /* Sanity checks */
  471. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  472. /* Recover our private data from the struct file instance */
  473. hf = filep->f_priv;
  474. inode = filep->f_inode;
  475. fs = inode->i_private;
  476. DEBUGASSERT(fs != NULL);
  477. /* Take the semaphore */
  478. hostfs_semtake(fs);
  479. /* Call our internal routine to perform the ioctl */
  480. ret = host_ioctl(hf->fd, cmd, arg);
  481. hostfs_semgive(fs);
  482. return ret;
  483. }
  484. /****************************************************************************
  485. * Name: hostfs_sync
  486. *
  487. * Description: Synchronize the file state on disk to match internal, in-
  488. * memory state.
  489. *
  490. ****************************************************************************/
  491. static int hostfs_sync(FAR struct file *filep)
  492. {
  493. FAR struct inode *inode;
  494. FAR struct hostfs_mountpt_s *fs;
  495. FAR struct hostfs_ofile_s *hf;
  496. /* Sanity checks */
  497. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  498. /* Recover our private data from the struct file instance */
  499. hf = filep->f_priv;
  500. inode = filep->f_inode;
  501. fs = inode->i_private;
  502. DEBUGASSERT(fs != NULL);
  503. /* Take the semaphore */
  504. hostfs_semtake(fs);
  505. host_sync(hf->fd);
  506. hostfs_semgive(fs);
  507. return OK;
  508. }
  509. /****************************************************************************
  510. * Name: hostfs_dup
  511. *
  512. * Description: Duplicate open file data in the new file structure.
  513. *
  514. ****************************************************************************/
  515. static int hostfs_dup(FAR const struct file *oldp, FAR struct file *newp)
  516. {
  517. FAR struct hostfs_ofile_s *sf;
  518. /* Sanity checks */
  519. DEBUGASSERT(oldp->f_priv != NULL &&
  520. newp->f_priv == NULL &&
  521. newp->f_inode != NULL);
  522. /* Recover our private data from the struct file instance */
  523. sf = oldp->f_priv;
  524. DEBUGASSERT(sf != NULL);
  525. /* Just increment the reference count on the ofile */
  526. sf->crefs++;
  527. newp->f_priv = (FAR void *)sf;
  528. return OK;
  529. }
  530. /****************************************************************************
  531. * Name: hostfs_fstat
  532. *
  533. * Description:
  534. * Obtain information about an open file associated with the file
  535. * descriptor 'fd', and will write it to the area pointed to by 'buf'.
  536. *
  537. ****************************************************************************/
  538. static int hostfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
  539. {
  540. FAR struct inode *inode;
  541. FAR struct hostfs_mountpt_s *fs;
  542. FAR struct hostfs_ofile_s *hf;
  543. int ret = OK;
  544. /* Sanity checks */
  545. DEBUGASSERT(filep != NULL && buf != NULL);
  546. /* Recover our private data from the struct file instance */
  547. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  548. hf = filep->f_priv;
  549. inode = filep->f_inode;
  550. fs = inode->i_private;
  551. DEBUGASSERT(fs != NULL);
  552. /* Take the semaphore */
  553. hostfs_semtake(fs);
  554. /* Call the host to perform the read */
  555. ret = host_fstat(hf->fd, buf);
  556. hostfs_semgive(fs);
  557. return ret;
  558. }
  559. /****************************************************************************
  560. * Name: hostfs_ftruncate
  561. *
  562. * Description:
  563. * Set the length of the open, regular file associated with the file
  564. * structure 'filep' to 'length'.
  565. *
  566. ****************************************************************************/
  567. static int hostfs_ftruncate(FAR struct file *filep, off_t length)
  568. {
  569. FAR struct inode *inode;
  570. FAR struct hostfs_mountpt_s *fs;
  571. FAR struct hostfs_ofile_s *hf;
  572. int ret = OK;
  573. /* Sanity checks */
  574. DEBUGASSERT(filep != NULL);
  575. /* Recover our private data from the struct file instance */
  576. DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
  577. hf = filep->f_priv;
  578. inode = filep->f_inode;
  579. fs = inode->i_private;
  580. DEBUGASSERT(fs != NULL);
  581. /* Take the semaphore */
  582. hostfs_semtake(fs);
  583. /* Call the host to perform the truncate */
  584. ret = host_ftruncate(hf->fd, length);
  585. hostfs_semgive(fs);
  586. return ret;
  587. }
  588. /****************************************************************************
  589. * Name: hostfs_opendir
  590. *
  591. * Description: Open a directory for read access
  592. *
  593. ****************************************************************************/
  594. static int hostfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
  595. FAR struct fs_dirent_s *dir)
  596. {
  597. FAR struct hostfs_mountpt_s *fs;
  598. char path[HOSTFS_MAX_PATH];
  599. int ret;
  600. /* Sanity checks */
  601. DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
  602. /* Recover our private data from the inode instance */
  603. fs = mountpt->i_private;
  604. /* Take the semaphore */
  605. hostfs_semtake(fs);
  606. /* Append to the host's root directory */
  607. hostfs_mkpath(fs, relpath, path, sizeof(path));
  608. /* Call the host's opendir function */
  609. dir->u.hostfs.fs_dir = host_opendir(path);
  610. if (dir->u.hostfs.fs_dir == NULL)
  611. {
  612. ret = -ENOENT;
  613. goto errout_with_semaphore;
  614. }
  615. ret = OK;
  616. errout_with_semaphore:
  617. hostfs_semgive(fs);
  618. return ret;
  619. }
  620. /****************************************************************************
  621. * Name: hostfs_closedir
  622. *
  623. * Description: Open a directory for read access
  624. *
  625. ****************************************************************************/
  626. static int hostfs_closedir(FAR struct inode *mountpt,
  627. FAR struct fs_dirent_s *dir)
  628. {
  629. struct hostfs_mountpt_s *fs;
  630. /* Sanity checks */
  631. DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
  632. /* Recover our private data from the inode instance */
  633. fs = mountpt->i_private;
  634. /* Take the semaphore */
  635. hostfs_semtake(fs);
  636. /* Call the host's closedir function */
  637. host_closedir(dir->u.hostfs.fs_dir);
  638. hostfs_semgive(fs);
  639. return OK;
  640. }
  641. /****************************************************************************
  642. * Name: hostfs_readdir
  643. *
  644. * Description: Read the next directory entry
  645. *
  646. ****************************************************************************/
  647. static int hostfs_readdir(FAR struct inode *mountpt,
  648. FAR struct fs_dirent_s *dir)
  649. {
  650. FAR struct hostfs_mountpt_s *fs;
  651. int ret;
  652. /* Sanity checks */
  653. DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
  654. /* Recover our private data from the inode instance */
  655. fs = mountpt->i_private;
  656. /* Take the semaphore */
  657. hostfs_semtake(fs);
  658. /* Call the host OS's readdir function */
  659. ret = host_readdir(dir->u.hostfs.fs_dir, &dir->fd_dir);
  660. hostfs_semgive(fs);
  661. return ret;
  662. }
  663. /****************************************************************************
  664. * Name: hostfs_rewindir
  665. *
  666. * Description: Reset directory read to the first entry
  667. *
  668. ****************************************************************************/
  669. static int hostfs_rewinddir(FAR struct inode *mountpt,
  670. FAR struct fs_dirent_s *dir)
  671. {
  672. /* Sanity checks */
  673. DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);
  674. /* Call the host and let it do all the work */
  675. host_rewinddir(dir->u.hostfs.fs_dir);
  676. return OK;
  677. }
  678. /****************************************************************************
  679. * Name: hostfs_bind
  680. *
  681. * Description: This implements a portion of the mount operation. This
  682. * function allocates and initializes the mountpoint private data and
  683. * binds the blockdriver inode to the filesystem private data. The final
  684. * binding of the private data (containing the blockdriver) to the
  685. * mountpoint is performed by mount().
  686. *
  687. ****************************************************************************/
  688. static int hostfs_bind(FAR struct inode *blkdriver, FAR const void *data,
  689. FAR void **handle)
  690. {
  691. FAR struct hostfs_mountpt_s *fs;
  692. FAR char *options;
  693. char *ptr, *saveptr;
  694. int len;
  695. /* Validate the block driver is NULL */
  696. if (blkdriver || !data)
  697. {
  698. return -ENODEV;
  699. }
  700. /* Create an instance of the mountpt state structure */
  701. fs = (FAR struct hostfs_mountpt_s *)
  702. kmm_zalloc(sizeof(struct hostfs_mountpt_s));
  703. if (fs == NULL)
  704. {
  705. return -ENOMEM;
  706. }
  707. /* The options we suppor are:
  708. * "fs=whatever", remote dir
  709. */
  710. options = strdup(data);
  711. if (!options)
  712. {
  713. kmm_free(fs);
  714. return -ENOMEM;
  715. }
  716. ptr = strtok_r(options, ",", &saveptr);
  717. while (ptr != NULL)
  718. {
  719. if ((strncmp(ptr, "fs=", 3) == 0))
  720. {
  721. strncpy(fs->fs_root, &ptr[3], sizeof(fs->fs_root));
  722. }
  723. ptr = strtok_r(NULL, ",", &saveptr);
  724. }
  725. kmm_free(options);
  726. /* If the global semaphore hasn't been initialized, then
  727. * initialized it now.
  728. */
  729. fs->fs_sem = &g_sem;
  730. if (!g_seminitialized)
  731. {
  732. /* Initialize the semaphore that controls access */
  733. nxsem_init(&g_sem, 0, 0);
  734. g_seminitialized = TRUE;
  735. }
  736. else
  737. {
  738. /* Take the semaphore for the mount */
  739. hostfs_semtake(fs);
  740. }
  741. /* Initialize the allocated mountpt state structure. The filesystem is
  742. * responsible for one reference ont the blkdriver inode and does not
  743. * have to addref() here (but does have to release in ubind().
  744. */
  745. fs->fs_head = NULL;
  746. /* Now perform the mount. */
  747. len = strlen(fs->fs_root);
  748. if (len > 1 && fs->fs_root[len - 1] == '/')
  749. {
  750. /* Remove trailing '/' */
  751. fs->fs_root[len - 1] = '\0';
  752. }
  753. /* Append a '/' to the name now */
  754. if (fs->fs_root[len - 1] != '/')
  755. {
  756. strcat(fs->fs_root, "/");
  757. }
  758. *handle = (FAR void *)fs;
  759. hostfs_semgive(fs);
  760. return OK;
  761. }
  762. /****************************************************************************
  763. * Name: hostfs_unbind
  764. *
  765. * Description: This implements the filesystem portion of the umount
  766. * operation.
  767. *
  768. ****************************************************************************/
  769. static int hostfs_unbind(FAR void *handle, FAR struct inode **blkdriver,
  770. unsigned int flags)
  771. {
  772. FAR struct hostfs_mountpt_s *fs = (FAR struct hostfs_mountpt_s *)handle;
  773. int ret;
  774. if (!fs)
  775. {
  776. return -EINVAL;
  777. }
  778. /* Check if there are sill any files opened on the filesystem. */
  779. ret = OK; /* Assume success */
  780. hostfs_semtake(fs);
  781. if (fs->fs_head != NULL)
  782. {
  783. /* We cannot unmount now.. there are open files */
  784. hostfs_semgive(fs);
  785. /* This implementation currently only supports unmounting if there are
  786. * no open file references.
  787. */
  788. return (flags != 0) ? -ENOSYS : -EBUSY;
  789. }
  790. hostfs_semgive(fs);
  791. kmm_free(fs);
  792. return ret;
  793. }
  794. /****************************************************************************
  795. * Name: hostfs_statfs
  796. *
  797. * Description: Return filesystem statistics
  798. *
  799. ****************************************************************************/
  800. static int hostfs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
  801. {
  802. FAR struct hostfs_mountpt_s *fs;
  803. int ret;
  804. /* Sanity checks */
  805. DEBUGASSERT(mountpt && mountpt->i_private);
  806. /* Get the mountpoint private data from the inode structure */
  807. fs = mountpt->i_private;
  808. hostfs_semtake(fs);
  809. /* Call the host fs to perform the statfs */
  810. memset(buf, 0, sizeof(struct statfs));
  811. ret = host_statfs(fs->fs_root, buf);
  812. buf->f_type = HOSTFS_MAGIC;
  813. hostfs_semgive(fs);
  814. return ret;
  815. }
  816. /****************************************************************************
  817. * Name: hostfs_unlink
  818. *
  819. * Description: Remove a file
  820. *
  821. ****************************************************************************/
  822. static int hostfs_unlink(FAR struct inode *mountpt, FAR const char *relpath)
  823. {
  824. FAR struct hostfs_mountpt_s *fs;
  825. char path[HOSTFS_MAX_PATH];
  826. int ret;
  827. /* Sanity checks */
  828. DEBUGASSERT(mountpt && mountpt->i_private);
  829. /* Get the mountpoint private data from the inode structure */
  830. fs = mountpt->i_private;
  831. hostfs_semtake(fs);
  832. /* Append to the host's root directory */
  833. hostfs_mkpath(fs, relpath, path, sizeof(path));
  834. /* Call the host fs to perform the unlink */
  835. ret = host_unlink(path);
  836. hostfs_semgive(fs);
  837. return ret;
  838. }
  839. /****************************************************************************
  840. * Name: hostfs_mkdir
  841. *
  842. * Description: Create a directory
  843. *
  844. ****************************************************************************/
  845. static int hostfs_mkdir(FAR struct inode *mountpt, FAR const char *relpath,
  846. mode_t mode)
  847. {
  848. FAR struct hostfs_mountpt_s *fs;
  849. char path[HOSTFS_MAX_PATH];
  850. int ret;
  851. /* Sanity checks */
  852. DEBUGASSERT(mountpt && mountpt->i_private);
  853. /* Get the mountpoint private data from the inode structure */
  854. fs = mountpt->i_private;
  855. hostfs_semtake(fs);
  856. /* Append to the host's root directory */
  857. hostfs_mkpath(fs, relpath, path, sizeof(path));
  858. /* Call the host FS to do the mkdir */
  859. ret = host_mkdir(path, mode);
  860. hostfs_semgive(fs);
  861. return ret;
  862. }
  863. /****************************************************************************
  864. * Name: hostfs_rmdir
  865. *
  866. * Description: Remove a directory
  867. *
  868. ****************************************************************************/
  869. int hostfs_rmdir(FAR struct inode *mountpt, FAR const char *relpath)
  870. {
  871. FAR struct hostfs_mountpt_s *fs;
  872. char path[HOSTFS_MAX_PATH];
  873. int ret;
  874. /* Sanity checks */
  875. DEBUGASSERT(mountpt && mountpt->i_private);
  876. /* Get the mountpoint private data from the inode structure */
  877. fs = mountpt->i_private;
  878. /* Take the semaphore */
  879. hostfs_semtake(fs);
  880. /* Append to the host's root directory */
  881. hostfs_mkpath(fs, relpath, path, sizeof(path));
  882. /* Call the host FS to do the mkdir */
  883. ret = host_rmdir(path);
  884. hostfs_semgive(fs);
  885. return ret;
  886. }
  887. /****************************************************************************
  888. * Name: hostfs_rename
  889. *
  890. * Description: Rename a file or directory
  891. *
  892. ****************************************************************************/
  893. int hostfs_rename(FAR struct inode *mountpt, FAR const char *oldrelpath,
  894. FAR const char *newrelpath)
  895. {
  896. FAR struct hostfs_mountpt_s *fs;
  897. char oldpath[HOSTFS_MAX_PATH];
  898. char newpath[HOSTFS_MAX_PATH];
  899. int ret;
  900. /* Sanity checks */
  901. DEBUGASSERT(mountpt && mountpt->i_private);
  902. /* Get the mountpoint private data from the inode structure */
  903. fs = mountpt->i_private;
  904. hostfs_semtake(fs);
  905. /* Append to the host's root directory */
  906. strncpy(oldpath, fs->fs_root, sizeof(oldpath));
  907. strncat(oldpath, oldrelpath, sizeof(oldpath)-strlen(oldpath)-1);
  908. strncpy(newpath, fs->fs_root, sizeof(newpath));
  909. strncat(newpath, newrelpath, sizeof(newpath)-strlen(newpath)-1);
  910. /* Call the host FS to do the mkdir */
  911. ret = host_rename(oldpath, newpath);
  912. hostfs_semgive(fs);
  913. return ret;
  914. }
  915. /****************************************************************************
  916. * Name: hostfs_stat
  917. *
  918. * Description: Return information about a file or directory
  919. *
  920. ****************************************************************************/
  921. static int hostfs_stat(FAR struct inode *mountpt, FAR const char *relpath,
  922. FAR struct stat *buf)
  923. {
  924. FAR struct hostfs_mountpt_s *fs;
  925. char path[HOSTFS_MAX_PATH];
  926. int ret;
  927. /* Sanity checks */
  928. DEBUGASSERT(mountpt && mountpt->i_private);
  929. /* Get the mountpoint private data from the inode structure */
  930. fs = mountpt->i_private;
  931. hostfs_semtake(fs);
  932. /* Append to the host's root directory */
  933. hostfs_mkpath(fs, relpath, path, sizeof(path));
  934. /* Call the host FS to do the stat operation */
  935. ret = host_stat(path, buf);
  936. hostfs_semgive(fs);
  937. return ret;
  938. }
  939. /****************************************************************************
  940. * Public Functions
  941. ****************************************************************************/