Subversion Repositories HelenOS

Rev

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