Subversion Repositories HelenOS

Rev

Rev 4302 | Rev 4401 | 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 char *opts, 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 *) opts, str_size(opts));
  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.     rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
  198.     if (rc != EOK) {
  199.         async_wait_for(req, NULL);
  200.         async_serialize_end();
  201.         futex_up(&vfs_phone_futex);
  202.         free(mpa);
  203.         return (int) rc;
  204.     }
  205.  
  206.     /* Ask VFS whether it likes fs_name. */
  207.     rc = async_req_0_0(vfs_phone, IPC_M_PING);
  208.     if (rc != EOK) {
  209.         async_wait_for(req, NULL);
  210.         async_serialize_end();
  211.         futex_up(&vfs_phone_futex);
  212.         free(mpa);
  213.         return (int) rc;
  214.     }
  215.    
  216.     async_wait_for(req, &rc);
  217.     async_serialize_end();
  218.     futex_up(&vfs_phone_futex);
  219.     free(mpa);
  220.    
  221.     return (int) rc;
  222. }
  223.  
  224. static int _open(const char *path, int lflag, int oflag, ...)
  225. {
  226.     ipcarg_t rc;
  227.     ipc_call_t answer;
  228.     aid_t req;
  229.    
  230.     size_t pa_size;
  231.     char *pa = absolutize(path, &pa_size);
  232.     if (!pa)
  233.         return ENOMEM;
  234.    
  235.     futex_down(&vfs_phone_futex);
  236.     async_serialize_start();
  237.     vfs_connect();
  238.    
  239.     req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
  240.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  241.     if (rc != EOK) {
  242.         async_wait_for(req, NULL);
  243.         async_serialize_end();
  244.         futex_up(&vfs_phone_futex);
  245.         free(pa);
  246.         return (int) rc;
  247.     }
  248.     async_wait_for(req, &rc);
  249.     async_serialize_end();
  250.     futex_up(&vfs_phone_futex);
  251.     free(pa);
  252.  
  253.     if (rc != EOK)
  254.         return (int) rc;
  255.     return (int) IPC_GET_ARG1(answer);
  256. }
  257.  
  258. int open(const char *path, int oflag, ...)
  259. {
  260.     return _open(path, L_FILE, oflag);
  261. }
  262.  
  263. int close(int fildes)
  264. {
  265.     ipcarg_t rc;
  266.    
  267.     futex_down(&vfs_phone_futex);
  268.     async_serialize_start();
  269.     vfs_connect();
  270.    
  271.     rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes);
  272.    
  273.     async_serialize_end();
  274.     futex_up(&vfs_phone_futex);
  275.    
  276.     return (int)rc;
  277. }
  278.  
  279. ssize_t read(int fildes, void *buf, size_t nbyte)
  280. {
  281.     ipcarg_t rc;
  282.     ipc_call_t answer;
  283.     aid_t req;
  284.  
  285.     futex_down(&vfs_phone_futex);
  286.     async_serialize_start();
  287.     vfs_connect();
  288.    
  289.     req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
  290.     rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
  291.     if (rc != EOK) {
  292.         async_wait_for(req, NULL);
  293.         async_serialize_end();
  294.         futex_up(&vfs_phone_futex);
  295.         return (ssize_t) rc;
  296.     }
  297.     async_wait_for(req, &rc);
  298.     async_serialize_end();
  299.     futex_up(&vfs_phone_futex);
  300.     if (rc == EOK)
  301.         return (ssize_t) IPC_GET_ARG1(answer);
  302.     else
  303.         return rc;
  304. }
  305.  
  306. ssize_t write(int fildes, const void *buf, size_t nbyte)
  307. {
  308.     ipcarg_t rc;
  309.     ipc_call_t answer;
  310.     aid_t req;
  311.  
  312.     futex_down(&vfs_phone_futex);
  313.     async_serialize_start();
  314.     vfs_connect();
  315.    
  316.     req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer);
  317.     rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
  318.     if (rc != EOK) {
  319.         async_wait_for(req, NULL);
  320.         async_serialize_end();
  321.         futex_up(&vfs_phone_futex);
  322.         return (ssize_t) rc;
  323.     }
  324.     async_wait_for(req, &rc);
  325.     async_serialize_end();
  326.     futex_up(&vfs_phone_futex);
  327.     if (rc == EOK)
  328.         return (ssize_t) IPC_GET_ARG1(answer);
  329.     else
  330.         return -1;
  331. }
  332.  
  333. off_t lseek(int fildes, off_t offset, int whence)
  334. {
  335.     ipcarg_t rc;
  336.  
  337.     futex_down(&vfs_phone_futex);
  338.     async_serialize_start();
  339.     vfs_connect();
  340.    
  341.     ipcarg_t newoffs;
  342.     rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
  343.         &newoffs);
  344.  
  345.     async_serialize_end();
  346.     futex_up(&vfs_phone_futex);
  347.  
  348.     if (rc != EOK)
  349.         return (off_t) -1;
  350.    
  351.     return (off_t) newoffs;
  352. }
  353.  
  354. int ftruncate(int fildes, off_t length)
  355. {
  356.     ipcarg_t rc;
  357.    
  358.     futex_down(&vfs_phone_futex);
  359.     async_serialize_start();
  360.     vfs_connect();
  361.    
  362.     rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
  363.     async_serialize_end();
  364.     futex_up(&vfs_phone_futex);
  365.     return (int) rc;
  366. }
  367.  
  368. DIR *opendir(const char *dirname)
  369. {
  370.     DIR *dirp = malloc(sizeof(DIR));
  371.     if (!dirp)
  372.         return NULL;
  373.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  374.     if (dirp->fd < 0) {
  375.         free(dirp);
  376.         return NULL;
  377.     }
  378.     return dirp;
  379. }
  380.  
  381. struct dirent *readdir(DIR *dirp)
  382. {
  383.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  384.     if (len <= 0)
  385.         return NULL;
  386.     return &dirp->res;
  387. }
  388.  
  389. void rewinddir(DIR *dirp)
  390. {
  391.     (void) lseek(dirp->fd, 0, SEEK_SET);
  392. }
  393.  
  394. int closedir(DIR *dirp)
  395. {
  396.     (void) close(dirp->fd);
  397.     free(dirp);
  398.     return 0;
  399. }
  400.  
  401. int mkdir(const char *path, mode_t mode)
  402. {
  403.     ipcarg_t rc;
  404.     aid_t req;
  405.    
  406.     size_t pa_size;
  407.     char *pa = absolutize(path, &pa_size);
  408.     if (!pa)
  409.         return ENOMEM;
  410.    
  411.     futex_down(&vfs_phone_futex);
  412.     async_serialize_start();
  413.     vfs_connect();
  414.    
  415.     req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
  416.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  417.     if (rc != EOK) {
  418.         async_wait_for(req, NULL);
  419.         async_serialize_end();
  420.         futex_up(&vfs_phone_futex);
  421.         free(pa);
  422.         return (int) rc;
  423.     }
  424.     async_wait_for(req, &rc);
  425.     async_serialize_end();
  426.     futex_up(&vfs_phone_futex);
  427.     free(pa);
  428.     return rc;
  429. }
  430.  
  431. static int _unlink(const char *path, int lflag)
  432. {
  433.     ipcarg_t rc;
  434.     aid_t req;
  435.    
  436.     size_t pa_size;
  437.     char *pa = absolutize(path, &pa_size);
  438.     if (!pa)
  439.         return ENOMEM;
  440.  
  441.     futex_down(&vfs_phone_futex);
  442.     async_serialize_start();
  443.     vfs_connect();
  444.    
  445.     req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
  446.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  447.     if (rc != EOK) {
  448.         async_wait_for(req, NULL);
  449.         async_serialize_end();
  450.         futex_up(&vfs_phone_futex);
  451.         free(pa);
  452.         return (int) rc;
  453.     }
  454.     async_wait_for(req, &rc);
  455.     async_serialize_end();
  456.     futex_up(&vfs_phone_futex);
  457.     free(pa);
  458.     return rc;
  459. }
  460.  
  461. int unlink(const char *path)
  462. {
  463.     return _unlink(path, L_NONE);
  464. }
  465.  
  466. int rmdir(const char *path)
  467. {
  468.     return _unlink(path, L_DIRECTORY);
  469. }
  470.  
  471. int rename(const char *old, const char *new)
  472. {
  473.     ipcarg_t rc;
  474.     aid_t req;
  475.    
  476.     size_t olda_size;
  477.     char *olda = absolutize(old, &olda_size);
  478.     if (!olda)
  479.         return ENOMEM;
  480.  
  481.     size_t newa_size;
  482.     char *newa = absolutize(new, &newa_size);
  483.     if (!newa) {
  484.         free(olda);
  485.         return ENOMEM;
  486.     }
  487.  
  488.     futex_down(&vfs_phone_futex);
  489.     async_serialize_start();
  490.     vfs_connect();
  491.    
  492.     req = async_send_0(vfs_phone, VFS_RENAME, NULL);
  493.     rc = ipc_data_write_start(vfs_phone, olda, olda_size);
  494.     if (rc != EOK) {
  495.         async_wait_for(req, NULL);
  496.         async_serialize_end();
  497.         futex_up(&vfs_phone_futex);
  498.         free(olda);
  499.         free(newa);
  500.         return (int) rc;
  501.     }
  502.     rc = ipc_data_write_start(vfs_phone, newa, newa_size);
  503.     if (rc != EOK) {
  504.         async_wait_for(req, NULL);
  505.         async_serialize_end();
  506.         futex_up(&vfs_phone_futex);
  507.         free(olda);
  508.         free(newa);
  509.         return (int) rc;
  510.     }
  511.     async_wait_for(req, &rc);
  512.     async_serialize_end();
  513.     futex_up(&vfs_phone_futex);
  514.     free(olda);
  515.     free(newa);
  516.     return rc;
  517. }
  518.  
  519. int chdir(const char *path)
  520. {
  521.     size_t pa_size;
  522.     char *pa = absolutize(path, &pa_size);
  523.     if (!pa)
  524.         return ENOMEM;
  525.  
  526.     DIR *d = opendir(pa);
  527.     if (!d) {
  528.         free(pa);
  529.         return ENOENT;
  530.     }
  531.  
  532.     futex_down(&cwd_futex);
  533.     if (cwd_dir) {
  534.         closedir(cwd_dir);
  535.         cwd_dir = NULL;
  536.         free(cwd_path);
  537.         cwd_path = NULL;
  538.         cwd_size = 0;
  539.     }
  540.     cwd_dir = d;
  541.     cwd_path = pa;
  542.     cwd_size = pa_size;
  543.     futex_up(&cwd_futex);
  544.     return EOK;
  545. }
  546.  
  547. char *getcwd(char *buf, size_t size)
  548. {
  549.     if (!size)
  550.         return NULL;
  551.     futex_down(&cwd_futex);
  552.     if (size < cwd_size + 1) {
  553.         futex_up(&cwd_futex);
  554.         return NULL;
  555.     }
  556.     str_cpy(buf, size, cwd_path);
  557.     futex_up(&cwd_futex);
  558.     return buf;
  559. }
  560.  
  561. /** @}
  562.  */
  563.