Subversion Repositories HelenOS

Rev

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