Subversion Repositories HelenOS

Rev

Rev 4296 | 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 "../../../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. int mount(const char *fs_name, const char *mp, const char *dev,
  119.     const char *opts, unsigned int flags)
  120. {
  121.     int res;
  122.     ipcarg_t rc;
  123.     aid_t req;
  124.     dev_handle_t dev_handle;
  125.    
  126.     res = devmap_device_get_handle(dev, &dev_handle, flags);
  127.     if (res != EOK)
  128.         return res;
  129.    
  130.     size_t mpa_size;
  131.     char *mpa = absolutize(mp, &mpa_size);
  132.     if (!mpa)
  133.         return ENOMEM;
  134.    
  135.     futex_down(&vfs_phone_futex);
  136.     async_serialize_start();
  137.     vfs_connect();
  138.    
  139.     req = async_send_2(vfs_phone, VFS_MOUNT, dev_handle, flags, NULL);
  140.     rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size);
  141.     if (rc != EOK) {
  142.         async_wait_for(req, NULL);
  143.         async_serialize_end();
  144.         futex_up(&vfs_phone_futex);
  145.         free(mpa);
  146.         return (int) rc;
  147.     }
  148.    
  149.     rc = ipc_data_write_start(vfs_phone, (void *) opts, str_size(opts));
  150.     if (rc != EOK) {
  151.         async_wait_for(req, NULL);
  152.         async_serialize_end();
  153.         futex_up(&vfs_phone_futex);
  154.         free(mpa);
  155.         return (int) rc;
  156.     }
  157.  
  158.     rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
  159.     if (rc != EOK) {
  160.         async_wait_for(req, NULL);
  161.         async_serialize_end();
  162.         futex_up(&vfs_phone_futex);
  163.         free(mpa);
  164.         return (int) rc;
  165.     }
  166.  
  167.     /* Ask VFS whether it likes fs_name. */
  168.     rc = async_req_0_0(vfs_phone, IPC_M_PING);
  169.     if (rc != EOK) {
  170.         async_wait_for(req, NULL);
  171.         async_serialize_end();
  172.         futex_up(&vfs_phone_futex);
  173.         free(mpa);
  174.         return (int) rc;
  175.     }
  176.    
  177.     async_wait_for(req, &rc);
  178.     async_serialize_end();
  179.     futex_up(&vfs_phone_futex);
  180.     free(mpa);
  181.    
  182.     return (int) rc;
  183. }
  184.  
  185. static int _open(const char *path, int lflag, int oflag, ...)
  186. {
  187.     ipcarg_t rc;
  188.     ipc_call_t answer;
  189.     aid_t req;
  190.    
  191.     size_t pa_size;
  192.     char *pa = absolutize(path, &pa_size);
  193.     if (!pa)
  194.         return ENOMEM;
  195.    
  196.     futex_down(&vfs_phone_futex);
  197.     async_serialize_start();
  198.     vfs_connect();
  199.    
  200.     req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
  201.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  202.     if (rc != EOK) {
  203.         async_wait_for(req, NULL);
  204.         async_serialize_end();
  205.         futex_up(&vfs_phone_futex);
  206.         free(pa);
  207.         return (int) rc;
  208.     }
  209.     async_wait_for(req, &rc);
  210.     async_serialize_end();
  211.     futex_up(&vfs_phone_futex);
  212.     free(pa);
  213.  
  214.     if (rc != EOK)
  215.         return (int) rc;
  216.     return (int) IPC_GET_ARG1(answer);
  217. }
  218.  
  219. int open(const char *path, int oflag, ...)
  220. {
  221.     return _open(path, L_FILE, oflag);
  222. }
  223.  
  224. int close(int fildes)
  225. {
  226.     ipcarg_t rc;
  227.    
  228.     futex_down(&vfs_phone_futex);
  229.     async_serialize_start();
  230.     vfs_connect();
  231.    
  232.     rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes);
  233.    
  234.     async_serialize_end();
  235.     futex_up(&vfs_phone_futex);
  236.    
  237.     return (int)rc;
  238. }
  239.  
  240. ssize_t read(int fildes, void *buf, size_t nbyte)
  241. {
  242.     ipcarg_t rc;
  243.     ipc_call_t answer;
  244.     aid_t req;
  245.  
  246.     futex_down(&vfs_phone_futex);
  247.     async_serialize_start();
  248.     vfs_connect();
  249.    
  250.     req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
  251.     rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
  252.     if (rc != EOK) {
  253.         async_wait_for(req, NULL);
  254.         async_serialize_end();
  255.         futex_up(&vfs_phone_futex);
  256.         return (ssize_t) rc;
  257.     }
  258.     async_wait_for(req, &rc);
  259.     async_serialize_end();
  260.     futex_up(&vfs_phone_futex);
  261.     if (rc == EOK)
  262.         return (ssize_t) IPC_GET_ARG1(answer);
  263.     else
  264.         return rc;
  265. }
  266.  
  267. ssize_t write(int fildes, const void *buf, size_t nbyte)
  268. {
  269.     ipcarg_t rc;
  270.     ipc_call_t answer;
  271.     aid_t req;
  272.  
  273.     futex_down(&vfs_phone_futex);
  274.     async_serialize_start();
  275.     vfs_connect();
  276.    
  277.     req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer);
  278.     rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
  279.     if (rc != EOK) {
  280.         async_wait_for(req, NULL);
  281.         async_serialize_end();
  282.         futex_up(&vfs_phone_futex);
  283.         return (ssize_t) rc;
  284.     }
  285.     async_wait_for(req, &rc);
  286.     async_serialize_end();
  287.     futex_up(&vfs_phone_futex);
  288.     if (rc == EOK)
  289.         return (ssize_t) IPC_GET_ARG1(answer);
  290.     else
  291.         return -1;
  292. }
  293.  
  294. off_t lseek(int fildes, off_t offset, int whence)
  295. {
  296.     ipcarg_t rc;
  297.  
  298.     futex_down(&vfs_phone_futex);
  299.     async_serialize_start();
  300.     vfs_connect();
  301.    
  302.     ipcarg_t newoffs;
  303.     rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
  304.         &newoffs);
  305.  
  306.     async_serialize_end();
  307.     futex_up(&vfs_phone_futex);
  308.  
  309.     if (rc != EOK)
  310.         return (off_t) -1;
  311.    
  312.     return (off_t) newoffs;
  313. }
  314.  
  315. int ftruncate(int fildes, off_t length)
  316. {
  317.     ipcarg_t rc;
  318.    
  319.     futex_down(&vfs_phone_futex);
  320.     async_serialize_start();
  321.     vfs_connect();
  322.    
  323.     rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
  324.     async_serialize_end();
  325.     futex_up(&vfs_phone_futex);
  326.     return (int) rc;
  327. }
  328.  
  329. DIR *opendir(const char *dirname)
  330. {
  331.     DIR *dirp = malloc(sizeof(DIR));
  332.     if (!dirp)
  333.         return NULL;
  334.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  335.     if (dirp->fd < 0) {
  336.         free(dirp);
  337.         return NULL;
  338.     }
  339.     return dirp;
  340. }
  341.  
  342. struct dirent *readdir(DIR *dirp)
  343. {
  344.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  345.     if (len <= 0)
  346.         return NULL;
  347.     return &dirp->res;
  348. }
  349.  
  350. void rewinddir(DIR *dirp)
  351. {
  352.     (void) lseek(dirp->fd, 0, SEEK_SET);
  353. }
  354.  
  355. int closedir(DIR *dirp)
  356. {
  357.     (void) close(dirp->fd);
  358.     free(dirp);
  359.     return 0;
  360. }
  361.  
  362. int mkdir(const char *path, mode_t mode)
  363. {
  364.     ipcarg_t rc;
  365.     aid_t req;
  366.    
  367.     size_t pa_size;
  368.     char *pa = absolutize(path, &pa_size);
  369.     if (!pa)
  370.         return ENOMEM;
  371.    
  372.     futex_down(&vfs_phone_futex);
  373.     async_serialize_start();
  374.     vfs_connect();
  375.    
  376.     req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
  377.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  378.     if (rc != EOK) {
  379.         async_wait_for(req, NULL);
  380.         async_serialize_end();
  381.         futex_up(&vfs_phone_futex);
  382.         free(pa);
  383.         return (int) rc;
  384.     }
  385.     async_wait_for(req, &rc);
  386.     async_serialize_end();
  387.     futex_up(&vfs_phone_futex);
  388.     free(pa);
  389.     return rc;
  390. }
  391.  
  392. static int _unlink(const char *path, int lflag)
  393. {
  394.     ipcarg_t rc;
  395.     aid_t req;
  396.    
  397.     size_t pa_size;
  398.     char *pa = absolutize(path, &pa_size);
  399.     if (!pa)
  400.         return ENOMEM;
  401.  
  402.     futex_down(&vfs_phone_futex);
  403.     async_serialize_start();
  404.     vfs_connect();
  405.    
  406.     req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
  407.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  408.     if (rc != EOK) {
  409.         async_wait_for(req, NULL);
  410.         async_serialize_end();
  411.         futex_up(&vfs_phone_futex);
  412.         free(pa);
  413.         return (int) rc;
  414.     }
  415.     async_wait_for(req, &rc);
  416.     async_serialize_end();
  417.     futex_up(&vfs_phone_futex);
  418.     free(pa);
  419.     return rc;
  420. }
  421.  
  422. int unlink(const char *path)
  423. {
  424.     return _unlink(path, L_NONE);
  425. }
  426.  
  427. int rmdir(const char *path)
  428. {
  429.     return _unlink(path, L_DIRECTORY);
  430. }
  431.  
  432. int rename(const char *old, const char *new)
  433. {
  434.     ipcarg_t rc;
  435.     aid_t req;
  436.    
  437.     size_t olda_size;
  438.     char *olda = absolutize(old, &olda_size);
  439.     if (!olda)
  440.         return ENOMEM;
  441.  
  442.     size_t newa_size;
  443.     char *newa = absolutize(new, &newa_size);
  444.     if (!newa) {
  445.         free(olda);
  446.         return ENOMEM;
  447.     }
  448.  
  449.     futex_down(&vfs_phone_futex);
  450.     async_serialize_start();
  451.     vfs_connect();
  452.    
  453.     req = async_send_0(vfs_phone, VFS_RENAME, NULL);
  454.     rc = ipc_data_write_start(vfs_phone, olda, olda_size);
  455.     if (rc != EOK) {
  456.         async_wait_for(req, NULL);
  457.         async_serialize_end();
  458.         futex_up(&vfs_phone_futex);
  459.         free(olda);
  460.         free(newa);
  461.         return (int) rc;
  462.     }
  463.     rc = ipc_data_write_start(vfs_phone, newa, newa_size);
  464.     if (rc != EOK) {
  465.         async_wait_for(req, NULL);
  466.         async_serialize_end();
  467.         futex_up(&vfs_phone_futex);
  468.         free(olda);
  469.         free(newa);
  470.         return (int) rc;
  471.     }
  472.     async_wait_for(req, &rc);
  473.     async_serialize_end();
  474.     futex_up(&vfs_phone_futex);
  475.     free(olda);
  476.     free(newa);
  477.     return rc;
  478. }
  479.  
  480. int chdir(const char *path)
  481. {
  482.     size_t pa_size;
  483.     char *pa = absolutize(path, &pa_size);
  484.     if (!pa)
  485.         return ENOMEM;
  486.  
  487.     DIR *d = opendir(pa);
  488.     if (!d) {
  489.         free(pa);
  490.         return ENOENT;
  491.     }
  492.  
  493.     futex_down(&cwd_futex);
  494.     if (cwd_dir) {
  495.         closedir(cwd_dir);
  496.         cwd_dir = NULL;
  497.         free(cwd_path);
  498.         cwd_path = NULL;
  499.         cwd_size = 0;
  500.     }
  501.     cwd_dir = d;
  502.     cwd_path = pa;
  503.     cwd_size = pa_size;
  504.     futex_up(&cwd_futex);
  505.     return EOK;
  506. }
  507.  
  508. char *getcwd(char *buf, size_t size)
  509. {
  510.     if (!size)
  511.         return NULL;
  512.     futex_down(&cwd_futex);
  513.     if (size < cwd_size + 1) {
  514.         futex_up(&cwd_futex);
  515.         return NULL;
  516.     }
  517.     str_cpy(buf, size, cwd_path);
  518.     futex_up(&cwd_futex);
  519.     return buf;
  520. }
  521.  
  522. /** @}
  523.  */
  524.