Subversion Repositories HelenOS

Rev

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