Subversion Repositories HelenOS

Rev

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