Subversion Repositories HelenOS

Rev

Rev 4584 | Rev 4587 | 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 <stdio.h>
  42. #include <sys/stat.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 <devmap.h>
  52. #include <ipc/vfs.h>
  53. #include <ipc/devmap.h>
  54.  
  55. static int vfs_phone = -1;
  56. static futex_t vfs_phone_futex = FUTEX_INITIALIZER;
  57. static futex_t cwd_futex = FUTEX_INITIALIZER;
  58.  
  59. DIR *cwd_dir = NULL;
  60. char *cwd_path = NULL;
  61. size_t cwd_size = 0;
  62.  
  63. char *absolutize(const char *path, size_t *retlen)
  64. {
  65.     char *ncwd_path;
  66.     char *ncwd_path_nc;
  67.  
  68.     futex_down(&cwd_futex);
  69.     size_t size = str_size(path);
  70.     if (*path != '/') {
  71.         if (!cwd_path) {
  72.             futex_up(&cwd_futex);
  73.             return NULL;
  74.         }
  75.         ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
  76.         if (!ncwd_path_nc) {
  77.             futex_up(&cwd_futex);
  78.             return NULL;
  79.         }
  80.         str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
  81.         ncwd_path_nc[cwd_size] = '/';
  82.         ncwd_path_nc[cwd_size + 1] = '\0';
  83.     } else {
  84.         ncwd_path_nc = malloc(size + 1);
  85.         if (!ncwd_path_nc) {
  86.             futex_up(&cwd_futex);
  87.             return NULL;
  88.         }
  89.         ncwd_path_nc[0] = '\0';
  90.     }
  91.     str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
  92.     ncwd_path = canonify(ncwd_path_nc, retlen);
  93.     if (!ncwd_path) {
  94.         futex_up(&cwd_futex);
  95.         free(ncwd_path_nc);
  96.         return NULL;
  97.     }
  98.     /*
  99.      * We need to clone ncwd_path because canonify() works in-place and thus
  100.      * the address in ncwd_path need not be the same as ncwd_path_nc, even
  101.      * though they both point into the same dynamically allocated buffer.
  102.      */
  103.     ncwd_path = str_dup(ncwd_path);
  104.     free(ncwd_path_nc);
  105.     if (!ncwd_path) {
  106.         futex_up(&cwd_futex);
  107.         return NULL;
  108.     }
  109.     futex_up(&cwd_futex);
  110.     return ncwd_path;
  111. }
  112.  
  113. static void vfs_connect(void)
  114. {
  115.     while (vfs_phone < 0)
  116.         vfs_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VFS, 0, 0);
  117. }
  118.  
  119. int mount(const char *fs_name, const char *mp, const char *dev,
  120.     const char *opts, unsigned int flags)
  121. {
  122.     int res;
  123.     ipcarg_t rc;
  124.     aid_t req;
  125.     dev_handle_t dev_handle;
  126.    
  127.     res = devmap_device_get_handle(dev, &dev_handle, flags);
  128.     if (res != EOK)
  129.         return res;
  130.    
  131.     size_t mpa_size;
  132.     char *mpa = absolutize(mp, &mpa_size);
  133.     if (!mpa)
  134.         return ENOMEM;
  135.    
  136.     futex_down(&vfs_phone_futex);
  137.     async_serialize_start();
  138.     vfs_connect();
  139.    
  140.     req = async_send_2(vfs_phone, VFS_IN_MOUNT, dev_handle, flags, NULL);
  141.     rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size);
  142.     if (rc != EOK) {
  143.         async_wait_for(req, NULL);
  144.         async_serialize_end();
  145.         futex_up(&vfs_phone_futex);
  146.         free(mpa);
  147.         return (int) rc;
  148.     }
  149.    
  150.     rc = ipc_data_write_start(vfs_phone, (void *) opts, str_size(opts));
  151.     if (rc != EOK) {
  152.         async_wait_for(req, NULL);
  153.         async_serialize_end();
  154.         futex_up(&vfs_phone_futex);
  155.         free(mpa);
  156.         return (int) rc;
  157.     }
  158.  
  159.     rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
  160.     if (rc != EOK) {
  161.         async_wait_for(req, NULL);
  162.         async_serialize_end();
  163.         futex_up(&vfs_phone_futex);
  164.         free(mpa);
  165.         return (int) rc;
  166.     }
  167.  
  168.     /* Ask VFS whether it likes fs_name. */
  169.     rc = async_req_0_0(vfs_phone, IPC_M_PING);
  170.     if (rc != EOK) {
  171.         async_wait_for(req, NULL);
  172.         async_serialize_end();
  173.         futex_up(&vfs_phone_futex);
  174.         free(mpa);
  175.         return (int) rc;
  176.     }
  177.    
  178.     async_wait_for(req, &rc);
  179.     async_serialize_end();
  180.     futex_up(&vfs_phone_futex);
  181.     free(mpa);
  182.    
  183.     return (int) rc;
  184. }
  185.  
  186. static int _open(const char *path, int lflag, int oflag, ...)
  187. {
  188.     ipcarg_t rc;
  189.     ipc_call_t answer;
  190.     aid_t req;
  191.    
  192.     size_t pa_size;
  193.     char *pa = absolutize(path, &pa_size);
  194.     if (!pa)
  195.         return ENOMEM;
  196.    
  197.     futex_down(&vfs_phone_futex);
  198.     async_serialize_start();
  199.     vfs_connect();
  200.    
  201.     req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer);
  202.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  203.     if (rc != EOK) {
  204.         async_wait_for(req, NULL);
  205.         async_serialize_end();
  206.         futex_up(&vfs_phone_futex);
  207.         free(pa);
  208.         return (int) rc;
  209.     }
  210.     async_wait_for(req, &rc);
  211.     async_serialize_end();
  212.     futex_up(&vfs_phone_futex);
  213.     free(pa);
  214.    
  215.     if (rc != EOK)
  216.         return (int) rc;
  217.    
  218.     return (int) IPC_GET_ARG1(answer);
  219. }
  220.  
  221. int open(const char *path, int oflag, ...)
  222. {
  223.     return _open(path, L_FILE, oflag);
  224. }
  225.  
  226. int open_node(fdi_node_t *node, int oflag)
  227. {
  228.     futex_down(&vfs_phone_futex);
  229.     async_serialize_start();
  230.     vfs_connect();
  231.    
  232.     ipc_call_t answer;
  233.     aid_t req = async_send_4(vfs_phone, VFS_IN_OPEN_NODE, node->fs_handle,
  234.         node->dev_handle, node->index, oflag, &answer);
  235.    
  236.     ipcarg_t rc;
  237.     async_wait_for(req, &rc);
  238.     async_serialize_end();
  239.     futex_up(&vfs_phone_futex);
  240.    
  241.     if (rc != EOK)
  242.         return (int) rc;
  243.    
  244.     return (int) IPC_GET_ARG1(answer);
  245. }
  246.  
  247. int close(int fildes)
  248. {
  249.     ipcarg_t rc;
  250.    
  251.     futex_down(&vfs_phone_futex);
  252.     async_serialize_start();
  253.     vfs_connect();
  254.    
  255.     rc = async_req_1_0(vfs_phone, VFS_IN_CLOSE, fildes);
  256.    
  257.     async_serialize_end();
  258.     futex_up(&vfs_phone_futex);
  259.    
  260.     return (int)rc;
  261. }
  262.  
  263. ssize_t read(int fildes, void *buf, size_t nbyte)
  264. {
  265.     ipcarg_t rc;
  266.     ipc_call_t answer;
  267.     aid_t req;
  268.  
  269.     futex_down(&vfs_phone_futex);
  270.     async_serialize_start();
  271.     vfs_connect();
  272.    
  273.     req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer);
  274.     rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
  275.     if (rc != EOK) {
  276.         async_wait_for(req, NULL);
  277.         async_serialize_end();
  278.         futex_up(&vfs_phone_futex);
  279.         return (ssize_t) rc;
  280.     }
  281.     async_wait_for(req, &rc);
  282.     async_serialize_end();
  283.     futex_up(&vfs_phone_futex);
  284.     if (rc == EOK)
  285.         return (ssize_t) IPC_GET_ARG1(answer);
  286.     else
  287.         return rc;
  288. }
  289.  
  290. ssize_t write(int fildes, const void *buf, size_t nbyte)
  291. {
  292.     ipcarg_t rc;
  293.     ipc_call_t answer;
  294.     aid_t req;
  295.  
  296.     futex_down(&vfs_phone_futex);
  297.     async_serialize_start();
  298.     vfs_connect();
  299.    
  300.     req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer);
  301.     rc = ipc_data_write_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 -1;
  315. }
  316.  
  317. int fsync(int fildes)
  318. {
  319.     futex_down(&vfs_phone_futex);
  320.     async_serialize_start();
  321.     vfs_connect();
  322.    
  323.     ipcarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes);
  324.    
  325.     async_serialize_end();
  326.     futex_up(&vfs_phone_futex);
  327.    
  328.     return (int) rc;
  329. }
  330.  
  331. off_t lseek(int fildes, off_t offset, int whence)
  332. {
  333.     ipcarg_t rc;
  334.  
  335.     futex_down(&vfs_phone_futex);
  336.     async_serialize_start();
  337.     vfs_connect();
  338.    
  339.     ipcarg_t newoffs;
  340.     rc = async_req_3_1(vfs_phone, VFS_IN_SEEK, fildes, offset, whence,
  341.         &newoffs);
  342.  
  343.     async_serialize_end();
  344.     futex_up(&vfs_phone_futex);
  345.  
  346.     if (rc != EOK)
  347.         return (off_t) -1;
  348.    
  349.     return (off_t) newoffs;
  350. }
  351.  
  352. int ftruncate(int fildes, off_t length)
  353. {
  354.     ipcarg_t rc;
  355.    
  356.     futex_down(&vfs_phone_futex);
  357.     async_serialize_start();
  358.     vfs_connect();
  359.    
  360.     rc = async_req_2_0(vfs_phone, VFS_IN_TRUNCATE, fildes, length);
  361.     async_serialize_end();
  362.     futex_up(&vfs_phone_futex);
  363.     return (int) rc;
  364. }
  365.  
  366. int fstat(int fildes, struct stat *stat)
  367. {
  368.     ipcarg_t rc;
  369.     ipc_call_t answer;
  370.     aid_t req;
  371.  
  372.     futex_down(&vfs_phone_futex);
  373.     async_serialize_start();
  374.     vfs_connect();
  375.    
  376.     req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL);
  377.     rc = ipc_data_read_start(vfs_phone, (void *)stat, sizeof(struct stat));
  378.     if (rc != EOK) {
  379.         async_wait_for(req, NULL);
  380.         async_serialize_end();
  381.         futex_up(&vfs_phone_futex);
  382.         return (ssize_t) rc;
  383.     }
  384.     async_wait_for(req, &rc);
  385.     async_serialize_end();
  386.     futex_up(&vfs_phone_futex);
  387.  
  388.     return rc;
  389. }
  390.  
  391. DIR *opendir(const char *dirname)
  392. {
  393.     DIR *dirp = malloc(sizeof(DIR));
  394.     if (!dirp)
  395.         return NULL;
  396.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  397.     if (dirp->fd < 0) {
  398.         free(dirp);
  399.         return NULL;
  400.     }
  401.     return dirp;
  402. }
  403.  
  404. struct dirent *readdir(DIR *dirp)
  405. {
  406.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  407.     if (len <= 0)
  408.         return NULL;
  409.     return &dirp->res;
  410. }
  411.  
  412. void rewinddir(DIR *dirp)
  413. {
  414.     (void) lseek(dirp->fd, 0, SEEK_SET);
  415. }
  416.  
  417. int closedir(DIR *dirp)
  418. {
  419.     (void) close(dirp->fd);
  420.     free(dirp);
  421.     return 0;
  422. }
  423.  
  424. int mkdir(const char *path, mode_t mode)
  425. {
  426.     ipcarg_t rc;
  427.     aid_t req;
  428.    
  429.     size_t pa_size;
  430.     char *pa = absolutize(path, &pa_size);
  431.     if (!pa)
  432.         return ENOMEM;
  433.    
  434.     futex_down(&vfs_phone_futex);
  435.     async_serialize_start();
  436.     vfs_connect();
  437.    
  438.     req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL);
  439.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  440.     if (rc != EOK) {
  441.         async_wait_for(req, NULL);
  442.         async_serialize_end();
  443.         futex_up(&vfs_phone_futex);
  444.         free(pa);
  445.         return (int) rc;
  446.     }
  447.     async_wait_for(req, &rc);
  448.     async_serialize_end();
  449.     futex_up(&vfs_phone_futex);
  450.     free(pa);
  451.     return rc;
  452. }
  453.  
  454. static int _unlink(const char *path, int lflag)
  455. {
  456.     ipcarg_t rc;
  457.     aid_t req;
  458.    
  459.     size_t pa_size;
  460.     char *pa = absolutize(path, &pa_size);
  461.     if (!pa)
  462.         return ENOMEM;
  463.  
  464.     futex_down(&vfs_phone_futex);
  465.     async_serialize_start();
  466.     vfs_connect();
  467.    
  468.     req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL);
  469.     rc = ipc_data_write_start(vfs_phone, pa, pa_size);
  470.     if (rc != EOK) {
  471.         async_wait_for(req, NULL);
  472.         async_serialize_end();
  473.         futex_up(&vfs_phone_futex);
  474.         free(pa);
  475.         return (int) rc;
  476.     }
  477.     async_wait_for(req, &rc);
  478.     async_serialize_end();
  479.     futex_up(&vfs_phone_futex);
  480.     free(pa);
  481.     return rc;
  482. }
  483.  
  484. int unlink(const char *path)
  485. {
  486.     return _unlink(path, L_NONE);
  487. }
  488.  
  489. int rmdir(const char *path)
  490. {
  491.     return _unlink(path, L_DIRECTORY);
  492. }
  493.  
  494. int rename(const char *old, const char *new)
  495. {
  496.     ipcarg_t rc;
  497.     aid_t req;
  498.    
  499.     size_t olda_size;
  500.     char *olda = absolutize(old, &olda_size);
  501.     if (!olda)
  502.         return ENOMEM;
  503.  
  504.     size_t newa_size;
  505.     char *newa = absolutize(new, &newa_size);
  506.     if (!newa) {
  507.         free(olda);
  508.         return ENOMEM;
  509.     }
  510.  
  511.     futex_down(&vfs_phone_futex);
  512.     async_serialize_start();
  513.     vfs_connect();
  514.    
  515.     req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL);
  516.     rc = ipc_data_write_start(vfs_phone, olda, olda_size);
  517.     if (rc != EOK) {
  518.         async_wait_for(req, NULL);
  519.         async_serialize_end();
  520.         futex_up(&vfs_phone_futex);
  521.         free(olda);
  522.         free(newa);
  523.         return (int) rc;
  524.     }
  525.     rc = ipc_data_write_start(vfs_phone, newa, newa_size);
  526.     if (rc != EOK) {
  527.         async_wait_for(req, NULL);
  528.         async_serialize_end();
  529.         futex_up(&vfs_phone_futex);
  530.         free(olda);
  531.         free(newa);
  532.         return (int) rc;
  533.     }
  534.     async_wait_for(req, &rc);
  535.     async_serialize_end();
  536.     futex_up(&vfs_phone_futex);
  537.     free(olda);
  538.     free(newa);
  539.     return rc;
  540. }
  541.  
  542. int chdir(const char *path)
  543. {
  544.     size_t pa_size;
  545.     char *pa = absolutize(path, &pa_size);
  546.     if (!pa)
  547.         return ENOMEM;
  548.  
  549.     DIR *d = opendir(pa);
  550.     if (!d) {
  551.         free(pa);
  552.         return ENOENT;
  553.     }
  554.  
  555.     futex_down(&cwd_futex);
  556.     if (cwd_dir) {
  557.         closedir(cwd_dir);
  558.         cwd_dir = NULL;
  559.         free(cwd_path);
  560.         cwd_path = NULL;
  561.         cwd_size = 0;
  562.     }
  563.     cwd_dir = d;
  564.     cwd_path = pa;
  565.     cwd_size = pa_size;
  566.     futex_up(&cwd_futex);
  567.     return EOK;
  568. }
  569.  
  570. char *getcwd(char *buf, size_t size)
  571. {
  572.     if (!size)
  573.         return NULL;
  574.     futex_down(&cwd_futex);
  575.     if (size < cwd_size + 1) {
  576.         futex_up(&cwd_futex);
  577.         return NULL;
  578.     }
  579.     str_cpy(buf, size, cwd_path);
  580.     futex_up(&cwd_futex);
  581.     return buf;
  582. }
  583.  
  584. int fd_phone(int fildes)
  585. {
  586.     struct stat stat;
  587.     int rc;
  588.  
  589.     rc = fstat(fildes, &stat);
  590.  
  591.     if (!stat.devfs_stat.device)
  592.         return -1;
  593.    
  594.     return devmap_device_connect(stat.devfs_stat.device, 0);
  595. }
  596.  
  597. int fd_node(int fildes, fdi_node_t *node)
  598. {
  599.     struct stat stat;
  600.     int rc;
  601.  
  602.     rc = fstat(fildes, &stat);
  603.    
  604.     if (rc == EOK) {
  605.         node->fs_handle = stat.fs_handle;
  606.         node->dev_handle = stat.dev_handle;
  607.         node->index = stat.index;
  608.     }
  609.    
  610.     return rc;
  611. }
  612.  
  613. /** @}
  614.  */
  615.