Subversion Repositories HelenOS

Rev

Rev 4537 | 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 <stdio.h>
  42. #include <sys/stat.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_IN_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_IN_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_IN_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_IN_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_IN_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_IN_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 fsync(int fildes)
  318. {
  319.     futex_down(&vfs_phone_futex);
  320.     async_serialize_start();
  321.     vfs_connect();
  322.    
  323.     ipcarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes);
  324.    
  325.     async_serialize_end();
  326.     futex_up(&vfs_phone_futex);
  327.    
  328.     return (int) rc;
  329. }
  330.  
  331. off_t lseek(int fildes, off_t offset, int whence)
  332. {
  333.     ipcarg_t rc;
  334.  
  335.     futex_down(&vfs_phone_futex);
  336.     async_serialize_start();
  337.     vfs_connect();
  338.    
  339.     ipcarg_t newoffs;
  340.     rc = async_req_3_1(vfs_phone, VFS_IN_SEEK, fildes, offset, whence,
  341.         &newoffs);
  342.  
  343.     async_serialize_end();
  344.     futex_up(&vfs_phone_futex);
  345.  
  346.     if (rc != EOK)
  347.         return (off_t) -1;
  348.    
  349.     return (off_t) newoffs;
  350. }
  351.  
  352. int ftruncate(int fildes, off_t length)
  353. {
  354.     ipcarg_t rc;
  355.    
  356.     futex_down(&vfs_phone_futex);
  357.     async_serialize_start();
  358.     vfs_connect();
  359.    
  360.     rc = async_req_2_0(vfs_phone, VFS_IN_TRUNCATE, fildes, length);
  361.     async_serialize_end();
  362.     futex_up(&vfs_phone_futex);
  363.     return (int) rc;
  364. }
  365.  
  366. int fstat(int fildes, struct stat *stat)
  367. {
  368.     ipcarg_t rc;
  369.     ipc_call_t answer;
  370.     aid_t req;
  371.  
  372.     futex_down(&vfs_phone_futex);
  373.     async_serialize_start();
  374.     vfs_connect();
  375.    
  376.     req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL);
  377.     rc = ipc_data_read_start(vfs_phone, (void *)stat, sizeof(struct stat));
  378.     if (rc != EOK) {
  379.         async_wait_for(req, NULL);
  380.         async_serialize_end();
  381.         futex_up(&vfs_phone_futex);
  382.         return (ssize_t) rc;
  383.     }
  384.     async_wait_for(req, &rc);
  385.     async_serialize_end();
  386.     futex_up(&vfs_phone_futex);
  387.  
  388.     return rc;
  389. }
  390.  
  391. int stat(const char *path, struct stat *stat)
  392. {
  393.     ipcarg_t rc;
  394.     aid_t req;
  395.    
  396.     size_t pa_size;
  397.     char *pa = absolutize(path, &pa_size);
  398.     if (!pa)
  399.         return ENOMEM;
  400.    
  401.     futex_down(&vfs_phone_futex);
  402.     async_serialize_start();
  403.     vfs_connect();
  404.    
  405.     req = async_send_0(vfs_phone, VFS_IN_STAT, NULL);
  406.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  407.     if (rc != EOK) {
  408.         async_wait_for(req, NULL);
  409.         async_serialize_end();
  410.         futex_up(&vfs_phone_futex);
  411.         free(pa);
  412.         return (int) rc;
  413.     }
  414.     rc = ipc_data_read_start(vfs_phone, stat, sizeof(struct stat));
  415.     if (rc != EOK) {
  416.         async_wait_for(req, NULL);
  417.         async_serialize_end();
  418.         futex_up(&vfs_phone_futex);
  419.         free(pa);
  420.         return (int) rc;
  421.     }
  422.     async_wait_for(req, &rc);
  423.     async_serialize_end();
  424.     futex_up(&vfs_phone_futex);
  425.     free(pa);
  426.     return rc;
  427. }
  428.  
  429. DIR *opendir(const char *dirname)
  430. {
  431.     DIR *dirp = malloc(sizeof(DIR));
  432.     if (!dirp)
  433.         return NULL;
  434.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  435.     if (dirp->fd < 0) {
  436.         free(dirp);
  437.         return NULL;
  438.     }
  439.     return dirp;
  440. }
  441.  
  442. struct dirent *readdir(DIR *dirp)
  443. {
  444.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  445.     if (len <= 0)
  446.         return NULL;
  447.     return &dirp->res;
  448. }
  449.  
  450. void rewinddir(DIR *dirp)
  451. {
  452.     (void) lseek(dirp->fd, 0, SEEK_SET);
  453. }
  454.  
  455. int closedir(DIR *dirp)
  456. {
  457.     (void) close(dirp->fd);
  458.     free(dirp);
  459.     return 0;
  460. }
  461.  
  462. int mkdir(const char *path, mode_t mode)
  463. {
  464.     ipcarg_t rc;
  465.     aid_t req;
  466.    
  467.     size_t pa_size;
  468.     char *pa = absolutize(path, &pa_size);
  469.     if (!pa)
  470.         return ENOMEM;
  471.    
  472.     futex_down(&vfs_phone_futex);
  473.     async_serialize_start();
  474.     vfs_connect();
  475.    
  476.     req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL);
  477.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  478.     if (rc != EOK) {
  479.         async_wait_for(req, NULL);
  480.         async_serialize_end();
  481.         futex_up(&vfs_phone_futex);
  482.         free(pa);
  483.         return (int) rc;
  484.     }
  485.     async_wait_for(req, &rc);
  486.     async_serialize_end();
  487.     futex_up(&vfs_phone_futex);
  488.     free(pa);
  489.     return rc;
  490. }
  491.  
  492. static int _unlink(const char *path, int lflag)
  493. {
  494.     ipcarg_t rc;
  495.     aid_t req;
  496.    
  497.     size_t pa_size;
  498.     char *pa = absolutize(path, &pa_size);
  499.     if (!pa)
  500.         return ENOMEM;
  501.  
  502.     futex_down(&vfs_phone_futex);
  503.     async_serialize_start();
  504.     vfs_connect();
  505.    
  506.     req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL);
  507.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  508.     if (rc != EOK) {
  509.         async_wait_for(req, NULL);
  510.         async_serialize_end();
  511.         futex_up(&vfs_phone_futex);
  512.         free(pa);
  513.         return (int) rc;
  514.     }
  515.     async_wait_for(req, &rc);
  516.     async_serialize_end();
  517.     futex_up(&vfs_phone_futex);
  518.     free(pa);
  519.     return rc;
  520. }
  521.  
  522. int unlink(const char *path)
  523. {
  524.     return _unlink(path, L_NONE);
  525. }
  526.  
  527. int rmdir(const char *path)
  528. {
  529.     return _unlink(path, L_DIRECTORY);
  530. }
  531.  
  532. int rename(const char *old, const char *new)
  533. {
  534.     ipcarg_t rc;
  535.     aid_t req;
  536.    
  537.     size_t olda_size;
  538.     char *olda = absolutize(old, &olda_size);
  539.     if (!olda)
  540.         return ENOMEM;
  541.  
  542.     size_t newa_size;
  543.     char *newa = absolutize(new, &newa_size);
  544.     if (!newa) {
  545.         free(olda);
  546.         return ENOMEM;
  547.     }
  548.  
  549.     futex_down(&vfs_phone_futex);
  550.     async_serialize_start();
  551.     vfs_connect();
  552.    
  553.     req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL);
  554.     rc = ipc_data_write_start(vfs_phone, olda, olda_size);
  555.     if (rc != EOK) {
  556.         async_wait_for(req, NULL);
  557.         async_serialize_end();
  558.         futex_up(&vfs_phone_futex);
  559.         free(olda);
  560.         free(newa);
  561.         return (int) rc;
  562.     }
  563.     rc = ipc_data_write_start(vfs_phone, newa, newa_size);
  564.     if (rc != EOK) {
  565.         async_wait_for(req, NULL);
  566.         async_serialize_end();
  567.         futex_up(&vfs_phone_futex);
  568.         free(olda);
  569.         free(newa);
  570.         return (int) rc;
  571.     }
  572.     async_wait_for(req, &rc);
  573.     async_serialize_end();
  574.     futex_up(&vfs_phone_futex);
  575.     free(olda);
  576.     free(newa);
  577.     return rc;
  578. }
  579.  
  580. int chdir(const char *path)
  581. {
  582.     size_t pa_size;
  583.     char *pa = absolutize(path, &pa_size);
  584.     if (!pa)
  585.         return ENOMEM;
  586.  
  587.     DIR *d = opendir(pa);
  588.     if (!d) {
  589.         free(pa);
  590.         return ENOENT;
  591.     }
  592.  
  593.     futex_down(&cwd_futex);
  594.     if (cwd_dir) {
  595.         closedir(cwd_dir);
  596.         cwd_dir = NULL;
  597.         free(cwd_path);
  598.         cwd_path = NULL;
  599.         cwd_size = 0;
  600.     }
  601.     cwd_dir = d;
  602.     cwd_path = pa;
  603.     cwd_size = pa_size;
  604.     futex_up(&cwd_futex);
  605.     return EOK;
  606. }
  607.  
  608. char *getcwd(char *buf, size_t size)
  609. {
  610.     if (!size)
  611.         return NULL;
  612.     futex_down(&cwd_futex);
  613.     if (size < cwd_size + 1) {
  614.         futex_up(&cwd_futex);
  615.         return NULL;
  616.     }
  617.     str_cpy(buf, size, cwd_path);
  618.     futex_up(&cwd_futex);
  619.     return buf;
  620. }
  621.  
  622. int fd_phone(int fildes)
  623. {
  624.     struct stat stat;
  625.     int rc;
  626.  
  627.     rc = fstat(fildes, &stat);
  628.  
  629.     if (!stat.devfs_stat.device)
  630.         return -1;
  631.    
  632.     return devmap_device_connect(stat.devfs_stat.device, 0);
  633. }
  634.  
  635. int fd_node(int fildes, fdi_node_t *node)
  636. {
  637.     struct stat stat;
  638.     int rc;
  639.  
  640.     rc = fstat(fildes, &stat);
  641.    
  642.     if (rc == EOK) {
  643.         node->fs_handle = stat.fs_handle;
  644.         node->dev_handle = stat.dev_handle;
  645.         node->index = stat.index;
  646.     }
  647.    
  648.     return rc;
  649. }
  650.  
  651. /** @}
  652.  */
  653.