Subversion Repositories HelenOS

Rev

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