Subversion Repositories HelenOS

Rev

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