hostfs.c 32 KB

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