Subversion Repositories HelenOS

Rev

Rev 4491 | Rev 4508 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Jakub Jermar
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup libc
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <vfs/vfs.h>
  36. #include <vfs/canonify.h>
  37. #include <stdlib.h>
  38. #include <unistd.h>
  39. #include <dirent.h>
  40. #include <fcntl.h>
  41. #include <sys/stat.h>
  42. #include <stdio.h>
  43. #include <sys/types.h>
  44. #include <ipc/ipc.h>
  45. #include <ipc/services.h>
  46. #include <async.h>
  47. #include <atomic.h>
  48. #include <futex.h>
  49. #include <errno.h>
  50. #include <string.h>
  51. #include <devmap.h>
  52. #include <ipc/vfs.h>
  53. #include <ipc/devmap.h>
  54.  
  55. static int vfs_phone = -1;
  56. static futex_t vfs_phone_futex = FUTEX_INITIALIZER;
  57. static futex_t cwd_futex = FUTEX_INITIALIZER;
  58.  
  59. DIR *cwd_dir = NULL;
  60. char *cwd_path = NULL;
  61. size_t cwd_size = 0;
  62.  
  63. char *absolutize(const char *path, size_t *retlen)
  64. {
  65.     char *ncwd_path;
  66.     char *ncwd_path_nc;
  67.  
  68.     futex_down(&cwd_futex);
  69.     size_t size = str_size(path);
  70.     if (*path != '/') {
  71.         if (!cwd_path) {
  72.             futex_up(&cwd_futex);
  73.             return NULL;
  74.         }
  75.         ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
  76.         if (!ncwd_path_nc) {
  77.             futex_up(&cwd_futex);
  78.             return NULL;
  79.         }
  80.         str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
  81.         ncwd_path_nc[cwd_size] = '/';
  82.         ncwd_path_nc[cwd_size + 1] = '\0';
  83.     } else {
  84.         ncwd_path_nc = malloc(size + 1);
  85.         if (!ncwd_path_nc) {
  86.             futex_up(&cwd_futex);
  87.             return NULL;
  88.         }
  89.         ncwd_path_nc[0] = '\0';
  90.     }
  91.     str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
  92.     ncwd_path = canonify(ncwd_path_nc, retlen);
  93.     if (!ncwd_path) {
  94.         futex_up(&cwd_futex);
  95.         free(ncwd_path_nc);
  96.         return NULL;
  97.     }
  98.     /*
  99.      * We need to clone ncwd_path because canonify() works in-place and thus
  100.      * the address in ncwd_path need not be the same as ncwd_path_nc, even
  101.      * though they both point into the same dynamically allocated buffer.
  102.      */
  103.     ncwd_path = str_dup(ncwd_path);
  104.     free(ncwd_path_nc);
  105.     if (!ncwd_path) {
  106.         futex_up(&cwd_futex);
  107.         return NULL;
  108.     }
  109.     futex_up(&cwd_futex);
  110.     return ncwd_path;
  111. }
  112.  
  113. static void vfs_connect(void)
  114. {
  115.     while (vfs_phone < 0)
  116.         vfs_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VFS, 0, 0);
  117. }
  118.  
  119. int mount(const char *fs_name, const char *mp, const char *dev,
  120.     const char *opts, unsigned int flags)
  121. {
  122.     int res;
  123.     ipcarg_t rc;
  124.     aid_t req;
  125.     dev_handle_t dev_handle;
  126.    
  127.     res = devmap_device_get_handle(dev, &dev_handle, flags);
  128.     if (res != EOK)
  129.         return res;
  130.    
  131.     size_t mpa_size;
  132.     char *mpa = absolutize(mp, &mpa_size);
  133.     if (!mpa)
  134.         return ENOMEM;
  135.    
  136.     futex_down(&vfs_phone_futex);
  137.     async_serialize_start();
  138.     vfs_connect();
  139.    
  140.     req = async_send_2(vfs_phone, VFS_MOUNT, dev_handle, flags, NULL);
  141.     rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size);
  142.     if (rc != EOK) {
  143.         async_wait_for(req, NULL);
  144.         async_serialize_end();
  145.         futex_up(&vfs_phone_futex);
  146.         free(mpa);
  147.         return (int) rc;
  148.     }
  149.    
  150.     rc = ipc_data_write_start(vfs_phone, (void *) opts, str_size(opts));
  151.     if (rc != EOK) {
  152.         async_wait_for(req, NULL);
  153.         async_serialize_end();
  154.         futex_up(&vfs_phone_futex);
  155.         free(mpa);
  156.         return (int) rc;
  157.     }
  158.  
  159.     rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
  160.     if (rc != EOK) {
  161.         async_wait_for(req, NULL);
  162.         async_serialize_end();
  163.         futex_up(&vfs_phone_futex);
  164.         free(mpa);
  165.         return (int) rc;
  166.     }
  167.  
  168.     /* Ask VFS whether it likes fs_name. */
  169.     rc = async_req_0_0(vfs_phone, IPC_M_PING);
  170.     if (rc != EOK) {
  171.         async_wait_for(req, NULL);
  172.         async_serialize_end();
  173.         futex_up(&vfs_phone_futex);
  174.         free(mpa);
  175.         return (int) rc;
  176.     }
  177.    
  178.     async_wait_for(req, &rc);
  179.     async_serialize_end();
  180.     futex_up(&vfs_phone_futex);
  181.     free(mpa);
  182.    
  183.     return (int) rc;
  184. }
  185.  
  186. static int _open(const char *path, int lflag, int oflag, ...)
  187. {
  188.     ipcarg_t rc;
  189.     ipc_call_t answer;
  190.     aid_t req;
  191.    
  192.     size_t pa_size;
  193.     char *pa = absolutize(path, &pa_size);
  194.     if (!pa)
  195.         return ENOMEM;
  196.    
  197.     futex_down(&vfs_phone_futex);
  198.     async_serialize_start();
  199.     vfs_connect();
  200.    
  201.     req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
  202.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  203.     if (rc != EOK) {
  204.         async_wait_for(req, NULL);
  205.         async_serialize_end();
  206.         futex_up(&vfs_phone_futex);
  207.         free(pa);
  208.         return (int) rc;
  209.     }
  210.     async_wait_for(req, &rc);
  211.     async_serialize_end();
  212.     futex_up(&vfs_phone_futex);
  213.     free(pa);
  214.    
  215.     if (rc != EOK)
  216.         return (int) rc;
  217.    
  218.     return (int) IPC_GET_ARG1(answer);
  219. }
  220.  
  221. int open(const char *path, int oflag, ...)
  222. {
  223.     return _open(path, L_FILE, oflag);
  224. }
  225.  
  226. int open_node(fdi_node_t *node, int oflag)
  227. {
  228.     futex_down(&vfs_phone_futex);
  229.     async_serialize_start();
  230.     vfs_connect();
  231.    
  232.     ipc_call_t answer;
  233.     aid_t req = async_send_4(vfs_phone, VFS_OPEN_NODE, node->fs_handle,
  234.         node->dev_handle, node->index, oflag, &answer);
  235.    
  236.     ipcarg_t rc;
  237.     async_wait_for(req, &rc);
  238.     async_serialize_end();
  239.     futex_up(&vfs_phone_futex);
  240.    
  241.     if (rc != EOK)
  242.         return (int) rc;
  243.    
  244.     return (int) IPC_GET_ARG1(answer);
  245. }
  246.  
  247. int close(int fildes)
  248. {
  249.     ipcarg_t rc;
  250.    
  251.     futex_down(&vfs_phone_futex);
  252.     async_serialize_start();
  253.     vfs_connect();
  254.    
  255.     rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes);
  256.    
  257.     async_serialize_end();
  258.     futex_up(&vfs_phone_futex);
  259.    
  260.     return (int)rc;
  261. }
  262.  
  263. ssize_t read(int fildes, void *buf, size_t nbyte)
  264. {
  265.     ipcarg_t rc;
  266.     ipc_call_t answer;
  267.     aid_t req;
  268.  
  269.     futex_down(&vfs_phone_futex);
  270.     async_serialize_start();
  271.     vfs_connect();
  272.    
  273.     req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
  274.     rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
  275.     if (rc != EOK) {
  276.         async_wait_for(req, NULL);
  277.         async_serialize_end();
  278.         futex_up(&vfs_phone_futex);
  279.         return (ssize_t) rc;
  280.     }
  281.     async_wait_for(req, &rc);
  282.     async_serialize_end();
  283.     futex_up(&vfs_phone_futex);
  284.     if (rc == EOK)
  285.         return (ssize_t) IPC_GET_ARG1(answer);
  286.     else
  287.         return rc;
  288. }
  289.  
  290. ssize_t write(int fildes, const void *buf, size_t nbyte)
  291. {
  292.     ipcarg_t rc;
  293.     ipc_call_t answer;
  294.     aid_t req;
  295.  
  296.     futex_down(&vfs_phone_futex);
  297.     async_serialize_start();
  298.     vfs_connect();
  299.    
  300.     req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer);
  301.     rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
  302.     if (rc != EOK) {
  303.         async_wait_for(req, NULL);
  304.         async_serialize_end();
  305.         futex_up(&vfs_phone_futex);
  306.         return (ssize_t) rc;
  307.     }
  308.     async_wait_for(req, &rc);
  309.     async_serialize_end();
  310.     futex_up(&vfs_phone_futex);
  311.     if (rc == EOK)
  312.         return (ssize_t) IPC_GET_ARG1(answer);
  313.     else
  314.         return -1;
  315. }
  316.  
  317. int fd_phone(int fildes)
  318. {
  319.     futex_down(&vfs_phone_futex);
  320.     async_serialize_start();
  321.     vfs_connect();
  322.    
  323.     ipcarg_t device;
  324.     ipcarg_t rc = async_req_1_1(vfs_phone, VFS_DEVICE, fildes, &device);
  325.    
  326.     async_serialize_end();
  327.     futex_up(&vfs_phone_futex);
  328.    
  329.     if (rc != EOK)
  330.         return -1;
  331.    
  332.     return devmap_device_connect((dev_handle_t) device, 0);
  333. }
  334.  
  335. void fd_node(int fildes, fdi_node_t *node)
  336. {
  337.     futex_down(&vfs_phone_futex);
  338.     async_serialize_start();
  339.     vfs_connect();
  340.    
  341.     ipcarg_t fs_handle;
  342.     ipcarg_t dev_handle;
  343.     ipcarg_t index;
  344.     ipcarg_t rc = async_req_1_3(vfs_phone, VFS_NODE, fildes, &fs_handle,
  345.         &dev_handle, &index);
  346.    
  347.     async_serialize_end();
  348.     futex_up(&vfs_phone_futex);
  349.    
  350.     if (rc == EOK) {
  351.         node->fs_handle = (fs_handle_t) fs_handle;
  352.         node->dev_handle = (dev_handle_t) dev_handle;
  353.         node->index = (fs_index_t) index;
  354.     } else {
  355.         node->fs_handle = 0;
  356.         node->dev_handle = 0;
  357.         node->index = 0;
  358.     }
  359. }
  360.  
  361. int fsync(int fildes)
  362. {
  363.     futex_down(&vfs_phone_futex);
  364.     async_serialize_start();
  365.     vfs_connect();
  366.    
  367.     ipcarg_t rc = async_req_1_0(vfs_phone, VFS_SYNC, fildes);
  368.    
  369.     async_serialize_end();
  370.     futex_up(&vfs_phone_futex);
  371.    
  372.     return (int) rc;
  373. }
  374.  
  375. off_t lseek(int fildes, off_t offset, int whence)
  376. {
  377.     ipcarg_t rc;
  378.  
  379.     futex_down(&vfs_phone_futex);
  380.     async_serialize_start();
  381.     vfs_connect();
  382.    
  383.     ipcarg_t newoffs;
  384.     rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
  385.         &newoffs);
  386.  
  387.     async_serialize_end();
  388.     futex_up(&vfs_phone_futex);
  389.  
  390.     if (rc != EOK)
  391.         return (off_t) -1;
  392.    
  393.     return (off_t) newoffs;
  394. }
  395.  
  396. int ftruncate(int fildes, off_t length)
  397. {
  398.     ipcarg_t rc;
  399.    
  400.     futex_down(&vfs_phone_futex);
  401.     async_serialize_start();
  402.     vfs_connect();
  403.    
  404.     rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
  405.     async_serialize_end();
  406.     futex_up(&vfs_phone_futex);
  407.     return (int) rc;
  408. }
  409.  
  410. DIR *opendir(const char *dirname)
  411. {
  412.     DIR *dirp = malloc(sizeof(DIR));
  413.     if (!dirp)
  414.         return NULL;
  415.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  416.     if (dirp->fd < 0) {
  417.         free(dirp);
  418.         return NULL;
  419.     }
  420.     return dirp;
  421. }
  422.  
  423. struct dirent *readdir(DIR *dirp)
  424. {
  425.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  426.     if (len <= 0)
  427.         return NULL;
  428.     return &dirp->res;
  429. }
  430.  
  431. void rewinddir(DIR *dirp)
  432. {
  433.     (void) lseek(dirp->fd, 0, SEEK_SET);
  434. }
  435.  
  436. int closedir(DIR *dirp)
  437. {
  438.     (void) close(dirp->fd);
  439.     free(dirp);
  440.     return 0;
  441. }
  442.  
  443. int mkdir(const char *path, mode_t mode)
  444. {
  445.     ipcarg_t rc;
  446.     aid_t req;
  447.    
  448.     size_t pa_size;
  449.     char *pa = absolutize(path, &pa_size);
  450.     if (!pa)
  451.         return ENOMEM;
  452.    
  453.     futex_down(&vfs_phone_futex);
  454.     async_serialize_start();
  455.     vfs_connect();
  456.    
  457.     req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
  458.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  459.     if (rc != EOK) {
  460.         async_wait_for(req, NULL);
  461.         async_serialize_end();
  462.         futex_up(&vfs_phone_futex);
  463.         free(pa);
  464.         return (int) rc;
  465.     }
  466.     async_wait_for(req, &rc);
  467.     async_serialize_end();
  468.     futex_up(&vfs_phone_futex);
  469.     free(pa);
  470.     return rc;
  471. }
  472.  
  473. static int _unlink(const char *path, int lflag)
  474. {
  475.     ipcarg_t rc;
  476.     aid_t req;
  477.    
  478.     size_t pa_size;
  479.     char *pa = absolutize(path, &pa_size);
  480.     if (!pa)
  481.         return ENOMEM;
  482.  
  483.     futex_down(&vfs_phone_futex);
  484.     async_serialize_start();
  485.     vfs_connect();
  486.    
  487.     req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
  488.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  489.     if (rc != EOK) {
  490.         async_wait_for(req, NULL);
  491.         async_serialize_end();
  492.         futex_up(&vfs_phone_futex);
  493.         free(pa);
  494.         return (int) rc;
  495.     }
  496.     async_wait_for(req, &rc);
  497.     async_serialize_end();
  498.     futex_up(&vfs_phone_futex);
  499.     free(pa);
  500.     return rc;
  501. }
  502.  
  503. int unlink(const char *path)
  504. {
  505.     return _unlink(path, L_NONE);
  506. }
  507.  
  508. int rmdir(const char *path)
  509. {
  510.     return _unlink(path, L_DIRECTORY);
  511. }
  512.  
  513. int rename(const char *old, const char *new)
  514. {
  515.     ipcarg_t rc;
  516.     aid_t req;
  517.    
  518.     size_t olda_size;
  519.     char *olda = absolutize(old, &olda_size);
  520.     if (!olda)
  521.         return ENOMEM;
  522.  
  523.     size_t newa_size;
  524.     char *newa = absolutize(new, &newa_size);
  525.     if (!newa) {
  526.         free(olda);
  527.         return ENOMEM;
  528.     }
  529.  
  530.     futex_down(&vfs_phone_futex);
  531.     async_serialize_start();
  532.     vfs_connect();
  533.    
  534.     req = async_send_0(vfs_phone, VFS_RENAME, NULL);
  535.     rc = ipc_data_write_start(vfs_phone, olda, olda_size);
  536.     if (rc != EOK) {
  537.         async_wait_for(req, NULL);
  538.         async_serialize_end();
  539.         futex_up(&vfs_phone_futex);
  540.         free(olda);
  541.         free(newa);
  542.         return (int) rc;
  543.     }
  544.     rc = ipc_data_write_start(vfs_phone, newa, newa_size);
  545.     if (rc != EOK) {
  546.         async_wait_for(req, NULL);
  547.         async_serialize_end();
  548.         futex_up(&vfs_phone_futex);
  549.         free(olda);
  550.         free(newa);
  551.         return (int) rc;
  552.     }
  553.     async_wait_for(req, &rc);
  554.     async_serialize_end();
  555.     futex_up(&vfs_phone_futex);
  556.     free(olda);
  557.     free(newa);
  558.     return rc;
  559. }
  560.  
  561. int chdir(const char *path)
  562. {
  563.     size_t pa_size;
  564.     char *pa = absolutize(path, &pa_size);
  565.     if (!pa)
  566.         return ENOMEM;
  567.  
  568.     DIR *d = opendir(pa);
  569.     if (!d) {
  570.         free(pa);
  571.         return ENOENT;
  572.     }
  573.  
  574.     futex_down(&cwd_futex);
  575.     if (cwd_dir) {
  576.         closedir(cwd_dir);
  577.         cwd_dir = NULL;
  578.         free(cwd_path);
  579.         cwd_path = NULL;
  580.         cwd_size = 0;
  581.     }
  582.     cwd_dir = d;
  583.     cwd_path = pa;
  584.     cwd_size = pa_size;
  585.     futex_up(&cwd_futex);
  586.     return EOK;
  587. }
  588.  
  589. char *getcwd(char *buf, size_t size)
  590. {
  591.     if (!size)
  592.         return NULL;
  593.     futex_down(&cwd_futex);
  594.     if (size < cwd_size + 1) {
  595.         futex_up(&cwd_futex);
  596.         return NULL;
  597.     }
  598.     str_cpy(buf, size, cwd_path);
  599.     futex_up(&cwd_futex);
  600.     return buf;
  601. }
  602.  
  603. /** @}
  604.  */
  605.