Subversion Repositories HelenOS

Rev

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