Subversion Repositories HelenOS

Rev

Rev 4055 | 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 <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 <ipc/devmap.h>
  52. #include "../../../srv/vfs/vfs.h"
  53.  
  54. int vfs_phone = -1;
  55. futex_t vfs_phone_futex = FUTEX_INITIALIZER;
  56.  
  57. futex_t cwd_futex = FUTEX_INITIALIZER;
  58. DIR *cwd_dir = NULL;
  59. char *cwd_path = NULL;
  60. size_t cwd_size = 0;
  61.  
  62. char *absolutize(const char *path, size_t *retlen)
  63. {
  64.     char *ncwd_path;
  65.     char *ncwd_path_nc;
  66.  
  67.     futex_down(&cwd_futex);
  68.     size_t size = str_size(path);
  69.     if (*path != '/') {
  70.         if (!cwd_path) {
  71.             futex_up(&cwd_futex);
  72.             return NULL;
  73.         }
  74.         ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
  75.         if (!ncwd_path_nc) {
  76.             futex_up(&cwd_futex);
  77.             return NULL;
  78.         }
  79.         str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
  80.         ncwd_path_nc[cwd_size] = '/';
  81.         ncwd_path_nc[cwd_size + 1] = '\0';
  82.     } else {
  83.         ncwd_path_nc = malloc(size + 1);
  84.         if (!ncwd_path_nc) {
  85.             futex_up(&cwd_futex);
  86.             return NULL;
  87.         }
  88.         ncwd_path_nc[0] = '\0';
  89.     }
  90.     str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
  91.     ncwd_path = canonify(ncwd_path_nc, retlen);
  92.     if (!ncwd_path) {
  93.         futex_up(&cwd_futex);
  94.         free(ncwd_path_nc);
  95.         return NULL;
  96.     }
  97.     /*
  98.      * We need to clone ncwd_path because canonify() works in-place and thus
  99.      * the address in ncwd_path need not be the same as ncwd_path_nc, even
  100.      * though they both point into the same dynamically allocated buffer.
  101.      */
  102.     ncwd_path = str_dup(ncwd_path);
  103.     free(ncwd_path_nc);
  104.     if (!ncwd_path) {
  105.         futex_up(&cwd_futex);
  106.         return NULL;
  107.     }
  108.     futex_up(&cwd_futex);
  109.     return ncwd_path;
  110. }
  111.  
  112. static void vfs_connect(void)
  113. {
  114.     while (vfs_phone < 0)
  115.         vfs_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VFS, 0, 0);
  116. }
  117.  
  118. static int device_get_handle(const char *name, dev_handle_t *handle,
  119.     const unsigned int flags)
  120. {
  121.     int phone;
  122.    
  123.     if (flags & IPC_FLAG_BLOCKING)
  124.         phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CLIENT, 0);
  125.     else
  126.         phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CLIENT, 0);
  127.    
  128.     if (phone < 0)
  129.         return phone;
  130.    
  131.     ipc_call_t answer;
  132.     aid_t req = async_send_2(phone, DEVMAP_DEVICE_GET_HANDLE, flags, 0,
  133.         &answer);
  134.    
  135.     ipcarg_t retval = ipc_data_write_start(phone, name, str_size(name) + 1);
  136.    
  137.     if (retval != EOK) {
  138.         async_wait_for(req, NULL);
  139.         ipc_hangup(phone);
  140.         return retval;
  141.     }
  142.    
  143.     async_wait_for(req, &retval);
  144.    
  145.     if (handle != NULL)
  146.         *handle = -1;
  147.    
  148.     if (retval == EOK) {
  149.         if (handle != NULL)
  150.             *handle = (dev_handle_t) IPC_GET_ARG1(answer);
  151.     }
  152.    
  153.     ipc_hangup(phone);
  154.     return retval;
  155. }
  156.  
  157. int mount(const char *fs_name, const char *mp, const char *dev,
  158.     const unsigned int flags)
  159. {
  160.     int res;
  161.     ipcarg_t rc;
  162.     aid_t req;
  163.     dev_handle_t dev_handle;
  164.    
  165.     res = device_get_handle(dev, &dev_handle, flags);
  166.     if (res != EOK)
  167.         return res;
  168.    
  169.     size_t mpa_size;
  170.     char *mpa = absolutize(mp, &mpa_size);
  171.     if (!mpa)
  172.         return ENOMEM;
  173.    
  174.     futex_down(&vfs_phone_futex);
  175.     async_serialize_start();
  176.     vfs_connect();
  177.    
  178.     req = async_send_2(vfs_phone, VFS_MOUNT, dev_handle, flags, NULL);
  179.     rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size);
  180.     if (rc != EOK) {
  181.         async_wait_for(req, NULL);
  182.         async_serialize_end();
  183.         futex_up(&vfs_phone_futex);
  184.         free(mpa);
  185.         return (int) rc;
  186.     }
  187.    
  188.     rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
  189.     if (rc != EOK) {
  190.         async_wait_for(req, NULL);
  191.         async_serialize_end();
  192.         futex_up(&vfs_phone_futex);
  193.         free(mpa);
  194.         return (int) rc;
  195.     }
  196.    
  197.     async_wait_for(req, &rc);
  198.     async_serialize_end();
  199.     futex_up(&vfs_phone_futex);
  200.     free(mpa);
  201.    
  202.     return (int) rc;
  203. }
  204.  
  205. static int _open(const char *path, int lflag, int oflag, ...)
  206. {
  207.     ipcarg_t rc;
  208.     ipc_call_t answer;
  209.     aid_t req;
  210.    
  211.     size_t pa_size;
  212.     char *pa = absolutize(path, &pa_size);
  213.     if (!pa)
  214.         return ENOMEM;
  215.    
  216.     futex_down(&vfs_phone_futex);
  217.     async_serialize_start();
  218.     vfs_connect();
  219.    
  220.     req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
  221.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  222.     if (rc != EOK) {
  223.         async_wait_for(req, NULL);
  224.         async_serialize_end();
  225.         futex_up(&vfs_phone_futex);
  226.         free(pa);
  227.         return (int) rc;
  228.     }
  229.     async_wait_for(req, &rc);
  230.     async_serialize_end();
  231.     futex_up(&vfs_phone_futex);
  232.     free(pa);
  233.  
  234.     if (rc != EOK)
  235.         return (int) rc;
  236.     return (int) IPC_GET_ARG1(answer);
  237. }
  238.  
  239. int open(const char *path, int oflag, ...)
  240. {
  241.     return _open(path, L_FILE, oflag);
  242. }
  243.  
  244. int close(int fildes)
  245. {
  246.     ipcarg_t rc;
  247.    
  248.     futex_down(&vfs_phone_futex);
  249.     async_serialize_start();
  250.     vfs_connect();
  251.    
  252.     rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes);
  253.    
  254.     async_serialize_end();
  255.     futex_up(&vfs_phone_futex);
  256.    
  257.     return (int)rc;
  258. }
  259.  
  260. ssize_t read(int fildes, void *buf, size_t nbyte)
  261. {
  262.     ipcarg_t rc;
  263.     ipc_call_t answer;
  264.     aid_t req;
  265.  
  266.     futex_down(&vfs_phone_futex);
  267.     async_serialize_start();
  268.     vfs_connect();
  269.    
  270.     req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
  271.     rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
  272.     if (rc != EOK) {
  273.         async_wait_for(req, NULL);
  274.         async_serialize_end();
  275.         futex_up(&vfs_phone_futex);
  276.         return (ssize_t) rc;
  277.     }
  278.     async_wait_for(req, &rc);
  279.     async_serialize_end();
  280.     futex_up(&vfs_phone_futex);
  281.     if (rc == EOK)
  282.         return (ssize_t) IPC_GET_ARG1(answer);
  283.     else
  284.         return rc;
  285. }
  286.  
  287. ssize_t write(int fildes, const void *buf, size_t nbyte)
  288. {
  289.     ipcarg_t rc;
  290.     ipc_call_t answer;
  291.     aid_t req;
  292.  
  293.     futex_down(&vfs_phone_futex);
  294.     async_serialize_start();
  295.     vfs_connect();
  296.    
  297.     req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer);
  298.     rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
  299.     if (rc != EOK) {
  300.         async_wait_for(req, NULL);
  301.         async_serialize_end();
  302.         futex_up(&vfs_phone_futex);
  303.         return (ssize_t) rc;
  304.     }
  305.     async_wait_for(req, &rc);
  306.     async_serialize_end();
  307.     futex_up(&vfs_phone_futex);
  308.     if (rc == EOK)
  309.         return (ssize_t) IPC_GET_ARG1(answer);
  310.     else
  311.         return -1;
  312. }
  313.  
  314. off_t lseek(int fildes, off_t offset, int whence)
  315. {
  316.     ipcarg_t rc;
  317.  
  318.     futex_down(&vfs_phone_futex);
  319.     async_serialize_start();
  320.     vfs_connect();
  321.    
  322.     ipcarg_t newoffs;
  323.     rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
  324.         &newoffs);
  325.  
  326.     async_serialize_end();
  327.     futex_up(&vfs_phone_futex);
  328.  
  329.     if (rc != EOK)
  330.         return (off_t) -1;
  331.    
  332.     return (off_t) newoffs;
  333. }
  334.  
  335. int ftruncate(int fildes, off_t length)
  336. {
  337.     ipcarg_t rc;
  338.    
  339.     futex_down(&vfs_phone_futex);
  340.     async_serialize_start();
  341.     vfs_connect();
  342.    
  343.     rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
  344.     async_serialize_end();
  345.     futex_up(&vfs_phone_futex);
  346.     return (int) rc;
  347. }
  348.  
  349. DIR *opendir(const char *dirname)
  350. {
  351.     DIR *dirp = malloc(sizeof(DIR));
  352.     if (!dirp)
  353.         return NULL;
  354.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  355.     if (dirp->fd < 0) {
  356.         free(dirp);
  357.         return NULL;
  358.     }
  359.     return dirp;
  360. }
  361.  
  362. struct dirent *readdir(DIR *dirp)
  363. {
  364.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  365.     if (len <= 0)
  366.         return NULL;
  367.     return &dirp->res;
  368. }
  369.  
  370. void rewinddir(DIR *dirp)
  371. {
  372.     (void) lseek(dirp->fd, 0, SEEK_SET);
  373. }
  374.  
  375. int closedir(DIR *dirp)
  376. {
  377.     (void) close(dirp->fd);
  378.     free(dirp);
  379.     return 0;
  380. }
  381.  
  382. int mkdir(const char *path, mode_t mode)
  383. {
  384.     ipcarg_t rc;
  385.     aid_t req;
  386.    
  387.     size_t pa_size;
  388.     char *pa = absolutize(path, &pa_size);
  389.     if (!pa)
  390.         return ENOMEM;
  391.    
  392.     futex_down(&vfs_phone_futex);
  393.     async_serialize_start();
  394.     vfs_connect();
  395.    
  396.     req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
  397.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  398.     if (rc != EOK) {
  399.         async_wait_for(req, NULL);
  400.         async_serialize_end();
  401.         futex_up(&vfs_phone_futex);
  402.         free(pa);
  403.         return (int) rc;
  404.     }
  405.     async_wait_for(req, &rc);
  406.     async_serialize_end();
  407.     futex_up(&vfs_phone_futex);
  408.     free(pa);
  409.     return rc;
  410. }
  411.  
  412. static int _unlink(const char *path, int lflag)
  413. {
  414.     ipcarg_t rc;
  415.     aid_t req;
  416.    
  417.     size_t pa_size;
  418.     char *pa = absolutize(path, &pa_size);
  419.     if (!pa)
  420.         return ENOMEM;
  421.  
  422.     futex_down(&vfs_phone_futex);
  423.     async_serialize_start();
  424.     vfs_connect();
  425.    
  426.     req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
  427.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  428.     if (rc != EOK) {
  429.         async_wait_for(req, NULL);
  430.         async_serialize_end();
  431.         futex_up(&vfs_phone_futex);
  432.         free(pa);
  433.         return (int) rc;
  434.     }
  435.     async_wait_for(req, &rc);
  436.     async_serialize_end();
  437.     futex_up(&vfs_phone_futex);
  438.     free(pa);
  439.     return rc;
  440. }
  441.  
  442. int unlink(const char *path)
  443. {
  444.     return _unlink(path, L_NONE);
  445. }
  446.  
  447. int rmdir(const char *path)
  448. {
  449.     return _unlink(path, L_DIRECTORY);
  450. }
  451.  
  452. int rename(const char *old, const char *new)
  453. {
  454.     ipcarg_t rc;
  455.     aid_t req;
  456.    
  457.     size_t olda_size;
  458.     char *olda = absolutize(old, &olda_size);
  459.     if (!olda)
  460.         return ENOMEM;
  461.  
  462.     size_t newa_size;
  463.     char *newa = absolutize(new, &newa_size);
  464.     if (!newa) {
  465.         free(olda);
  466.         return ENOMEM;
  467.     }
  468.  
  469.     futex_down(&vfs_phone_futex);
  470.     async_serialize_start();
  471.     vfs_connect();
  472.    
  473.     req = async_send_0(vfs_phone, VFS_RENAME, NULL);
  474.     rc = ipc_data_write_start(vfs_phone, olda, olda_size);
  475.     if (rc != EOK) {
  476.         async_wait_for(req, NULL);
  477.         async_serialize_end();
  478.         futex_up(&vfs_phone_futex);
  479.         free(olda);
  480.         free(newa);
  481.         return (int) rc;
  482.     }
  483.     rc = ipc_data_write_start(vfs_phone, newa, newa_size);
  484.     if (rc != EOK) {
  485.         async_wait_for(req, NULL);
  486.         async_serialize_end();
  487.         futex_up(&vfs_phone_futex);
  488.         free(olda);
  489.         free(newa);
  490.         return (int) rc;
  491.     }
  492.     async_wait_for(req, &rc);
  493.     async_serialize_end();
  494.     futex_up(&vfs_phone_futex);
  495.     free(olda);
  496.     free(newa);
  497.     return rc;
  498. }
  499.  
  500. int chdir(const char *path)
  501. {
  502.     size_t pa_size;
  503.     char *pa = absolutize(path, &pa_size);
  504.     if (!pa)
  505.         return ENOMEM;
  506.  
  507.     DIR *d = opendir(pa);
  508.     if (!d) {
  509.         free(pa);
  510.         return ENOENT;
  511.     }
  512.  
  513.     futex_down(&cwd_futex);
  514.     if (cwd_dir) {
  515.         closedir(cwd_dir);
  516.         cwd_dir = NULL;
  517.         free(cwd_path);
  518.         cwd_path = NULL;
  519.         cwd_size = 0;
  520.     }
  521.     cwd_dir = d;
  522.     cwd_path = pa;
  523.     cwd_size = pa_size;
  524.     futex_up(&cwd_futex);
  525.     return EOK;
  526. }
  527.  
  528. char *getcwd(char *buf, size_t size)
  529. {
  530.     if (!size)
  531.         return NULL;
  532.     futex_down(&cwd_futex);
  533.     if (size < cwd_size + 1) {
  534.         futex_up(&cwd_futex);
  535.         return NULL;
  536.     }
  537.     str_cpy(buf, size, cwd_path);
  538.     futex_up(&cwd_futex);
  539.     return buf;
  540. }
  541.  
  542. /** @}
  543.  */
  544.