Subversion Repositories HelenOS

Rev

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