Subversion Repositories HelenOS

Rev

Rev 4420 | 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 <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. int 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.     }
  355.    
  356.     return rc;
  357. }
  358.  
  359. int fsync(int fildes)
  360. {
  361.     futex_down(&vfs_phone_futex);
  362.     async_serialize_start();
  363.     vfs_connect();
  364.    
  365.     ipcarg_t rc = async_req_1_0(vfs_phone, VFS_SYNC, fildes);
  366.    
  367.     async_serialize_end();
  368.     futex_up(&vfs_phone_futex);
  369.    
  370.     return (int) rc;
  371. }
  372.  
  373. off_t lseek(int fildes, off_t offset, int whence)
  374. {
  375.     ipcarg_t rc;
  376.  
  377.     futex_down(&vfs_phone_futex);
  378.     async_serialize_start();
  379.     vfs_connect();
  380.    
  381.     ipcarg_t newoffs;
  382.     rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
  383.         &newoffs);
  384.  
  385.     async_serialize_end();
  386.     futex_up(&vfs_phone_futex);
  387.  
  388.     if (rc != EOK)
  389.         return (off_t) -1;
  390.    
  391.     return (off_t) newoffs;
  392. }
  393.  
  394. int ftruncate(int fildes, off_t length)
  395. {
  396.     ipcarg_t rc;
  397.    
  398.     futex_down(&vfs_phone_futex);
  399.     async_serialize_start();
  400.     vfs_connect();
  401.    
  402.     rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
  403.     async_serialize_end();
  404.     futex_up(&vfs_phone_futex);
  405.     return (int) rc;
  406. }
  407.  
  408. DIR *opendir(const char *dirname)
  409. {
  410.     DIR *dirp = malloc(sizeof(DIR));
  411.     if (!dirp)
  412.         return NULL;
  413.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  414.     if (dirp->fd < 0) {
  415.         free(dirp);
  416.         return NULL;
  417.     }
  418.     return dirp;
  419. }
  420.  
  421. struct dirent *readdir(DIR *dirp)
  422. {
  423.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  424.     if (len <= 0)
  425.         return NULL;
  426.     return &dirp->res;
  427. }
  428.  
  429. void rewinddir(DIR *dirp)
  430. {
  431.     (void) lseek(dirp->fd, 0, SEEK_SET);
  432. }
  433.  
  434. int closedir(DIR *dirp)
  435. {
  436.     (void) close(dirp->fd);
  437.     free(dirp);
  438.     return 0;
  439. }
  440.  
  441. int mkdir(const char *path, mode_t mode)
  442. {
  443.     ipcarg_t rc;
  444.     aid_t req;
  445.    
  446.     size_t pa_size;
  447.     char *pa = absolutize(path, &pa_size);
  448.     if (!pa)
  449.         return ENOMEM;
  450.    
  451.     futex_down(&vfs_phone_futex);
  452.     async_serialize_start();
  453.     vfs_connect();
  454.    
  455.     req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
  456.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  457.     if (rc != EOK) {
  458.         async_wait_for(req, NULL);
  459.         async_serialize_end();
  460.         futex_up(&vfs_phone_futex);
  461.         free(pa);
  462.         return (int) rc;
  463.     }
  464.     async_wait_for(req, &rc);
  465.     async_serialize_end();
  466.     futex_up(&vfs_phone_futex);
  467.     free(pa);
  468.     return rc;
  469. }
  470.  
  471. static int _unlink(const char *path, int lflag)
  472. {
  473.     ipcarg_t rc;
  474.     aid_t req;
  475.    
  476.     size_t pa_size;
  477.     char *pa = absolutize(path, &pa_size);
  478.     if (!pa)
  479.         return ENOMEM;
  480.  
  481.     futex_down(&vfs_phone_futex);
  482.     async_serialize_start();
  483.     vfs_connect();
  484.    
  485.     req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
  486.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  487.     if (rc != EOK) {
  488.         async_wait_for(req, NULL);
  489.         async_serialize_end();
  490.         futex_up(&vfs_phone_futex);
  491.         free(pa);
  492.         return (int) rc;
  493.     }
  494.     async_wait_for(req, &rc);
  495.     async_serialize_end();
  496.     futex_up(&vfs_phone_futex);
  497.     free(pa);
  498.     return rc;
  499. }
  500.  
  501. int unlink(const char *path)
  502. {
  503.     return _unlink(path, L_NONE);
  504. }
  505.  
  506. int rmdir(const char *path)
  507. {
  508.     return _unlink(path, L_DIRECTORY);
  509. }
  510.  
  511. int rename(const char *old, const char *new)
  512. {
  513.     ipcarg_t rc;
  514.     aid_t req;
  515.    
  516.     size_t olda_size;
  517.     char *olda = absolutize(old, &olda_size);
  518.     if (!olda)
  519.         return ENOMEM;
  520.  
  521.     size_t newa_size;
  522.     char *newa = absolutize(new, &newa_size);
  523.     if (!newa) {
  524.         free(olda);
  525.         return ENOMEM;
  526.     }
  527.  
  528.     futex_down(&vfs_phone_futex);
  529.     async_serialize_start();
  530.     vfs_connect();
  531.    
  532.     req = async_send_0(vfs_phone, VFS_RENAME, NULL);
  533.     rc = ipc_data_write_start(vfs_phone, olda, olda_size);
  534.     if (rc != EOK) {
  535.         async_wait_for(req, NULL);
  536.         async_serialize_end();
  537.         futex_up(&vfs_phone_futex);
  538.         free(olda);
  539.         free(newa);
  540.         return (int) rc;
  541.     }
  542.     rc = ipc_data_write_start(vfs_phone, newa, newa_size);
  543.     if (rc != EOK) {
  544.         async_wait_for(req, NULL);
  545.         async_serialize_end();
  546.         futex_up(&vfs_phone_futex);
  547.         free(olda);
  548.         free(newa);
  549.         return (int) rc;
  550.     }
  551.     async_wait_for(req, &rc);
  552.     async_serialize_end();
  553.     futex_up(&vfs_phone_futex);
  554.     free(olda);
  555.     free(newa);
  556.     return rc;
  557. }
  558.  
  559. int chdir(const char *path)
  560. {
  561.     size_t pa_size;
  562.     char *pa = absolutize(path, &pa_size);
  563.     if (!pa)
  564.         return ENOMEM;
  565.  
  566.     DIR *d = opendir(pa);
  567.     if (!d) {
  568.         free(pa);
  569.         return ENOENT;
  570.     }
  571.  
  572.     futex_down(&cwd_futex);
  573.     if (cwd_dir) {
  574.         closedir(cwd_dir);
  575.         cwd_dir = NULL;
  576.         free(cwd_path);
  577.         cwd_path = NULL;
  578.         cwd_size = 0;
  579.     }
  580.     cwd_dir = d;
  581.     cwd_path = pa;
  582.     cwd_size = pa_size;
  583.     futex_up(&cwd_futex);
  584.     return EOK;
  585. }
  586.  
  587. char *getcwd(char *buf, size_t size)
  588. {
  589.     if (!size)
  590.         return NULL;
  591.     futex_down(&cwd_futex);
  592.     if (size < cwd_size + 1) {
  593.         futex_up(&cwd_futex);
  594.         return NULL;
  595.     }
  596.     str_cpy(buf, size, cwd_path);
  597.     futex_up(&cwd_futex);
  598.     return buf;
  599. }
  600.  
  601. /** @}
  602.  */
  603.