Subversion Repositories HelenOS

Rev

Rev 2761 | Rev 2771 | 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 <sys/types.h>
  43. #include <ipc/ipc.h>
  44. #include <ipc/services.h>
  45. #include <async.h>
  46. #include <atomic.h>
  47. #include <futex.h>
  48. #include <errno.h>
  49. #include <string.h>
  50. #include "../../srv/vfs/vfs.h"
  51.  
  52. int vfs_phone = -1;
  53. futex_t vfs_phone_futex = FUTEX_INITIALIZER;
  54.  
  55. futex_t cwd_futex = FUTEX_INITIALIZER;
  56. DIR *cwd_dir = NULL;
  57. char *cwd_path = NULL;
  58. size_t cwd_len = 0;
  59.  
  60. static char *absolutize(const char *path)
  61. {
  62.     char *ncwd_path;
  63.  
  64.     futex_down(&cwd_futex);
  65.     size_t len = strlen(path);
  66.     if (*path != '/') {
  67.         if (!cwd_path) {
  68.             futex_up(&cwd_futex);
  69.             return NULL;
  70.         }
  71.         ncwd_path = malloc(len + cwd_len + 1);
  72.         if (!ncwd_path) {
  73.             futex_up(&cwd_futex);
  74.             return NULL;
  75.         }
  76.         strcpy(ncwd_path, cwd_path);
  77.         ncwd_path[cwd_len] = '/';
  78.         ncwd_path[cwd_len + 1] = '\0';
  79.     } else {
  80.         ncwd_path = malloc(len + 1);
  81.         if (!ncwd_path) {
  82.             futex_up(&cwd_futex);
  83.             return NULL;
  84.         }
  85.         ncwd_path[0] = '\0';
  86.     }
  87.     strcat(ncwd_path, path);
  88.     futex_up(&cwd_futex);
  89.     return ncwd_path;
  90. }
  91.  
  92. static int vfs_connect(void)
  93. {
  94.     if (vfs_phone < 0)
  95.         vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
  96.     return vfs_phone;
  97. }
  98.  
  99. int mount(const char *fs_name, const char *mp, const char *dev)
  100. {
  101.     int res;
  102.     ipcarg_t rc;
  103.     aid_t req;
  104.  
  105.     int dev_handle = 0; /* TODO */
  106.  
  107.     char *mpa = absolutize(mp);
  108.     if (!mpa)
  109.         return ENOMEM;
  110.     size_t mpc_len;
  111.     char *mpc = canonify(mpa, &mpc_len);
  112.     if (!mpc) {
  113.         free(mpa);
  114.         return EINVAL;
  115.     }
  116.  
  117.     futex_down(&vfs_phone_futex);
  118.     async_serialize_start();
  119.     if (vfs_phone < 0) {
  120.         res = vfs_connect();
  121.         if (res < 0) {
  122.             async_serialize_end();
  123.             futex_up(&vfs_phone_futex);
  124.             free(mpa);
  125.             return res;
  126.         }
  127.     }
  128.     req = async_send_1(vfs_phone, VFS_MOUNT, dev_handle, NULL);
  129.     rc = ipc_data_write_start(vfs_phone, (void *)fs_name, strlen(fs_name));
  130.     if (rc != EOK) {
  131.         async_wait_for(req, NULL);
  132.         async_serialize_end();
  133.         futex_up(&vfs_phone_futex);
  134.         free(mpa);
  135.         return (int) rc;
  136.     }
  137.     rc = ipc_data_write_start(vfs_phone, (void *)mpc, mpc_len);
  138.     if (rc != EOK) {
  139.         async_wait_for(req, NULL);
  140.         async_serialize_end();
  141.         futex_up(&vfs_phone_futex);
  142.         free(mpa);
  143.         return (int) rc;
  144.     }
  145.     async_wait_for(req, &rc);
  146.     async_serialize_end();
  147.     futex_up(&vfs_phone_futex);
  148.     free(mpa);
  149.     return (int) rc;
  150. }
  151.  
  152. static int _open(const char *path, int lflag, int oflag, ...)
  153. {
  154.     int res;
  155.     ipcarg_t rc;
  156.     ipc_call_t answer;
  157.     aid_t req;
  158.    
  159.     char *pa = absolutize(path);
  160.     if (!pa)
  161.         return ENOMEM;
  162.     size_t pc_len;
  163.     char *pc = canonify(pa, &pc_len);
  164.     if (!pc) {
  165.         free(pa);
  166.         return EINVAL;
  167.     }
  168.    
  169.     futex_down(&vfs_phone_futex);
  170.     async_serialize_start();
  171.     if (vfs_phone < 0) {
  172.         res = vfs_connect();
  173.         if (res < 0) {
  174.             async_serialize_end();
  175.             futex_up(&vfs_phone_futex);
  176.             free(pa);
  177.             return res;
  178.         }
  179.     }
  180.     req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
  181.     rc = ipc_data_write_start(vfs_phone, pc, pc_len);
  182.     if (rc != EOK) {
  183.         async_wait_for(req, NULL);
  184.         async_serialize_end();
  185.         futex_up(&vfs_phone_futex);
  186.         free(pa);
  187.         return (int) rc;
  188.     }
  189.     async_wait_for(req, &rc);
  190.     async_serialize_end();
  191.     futex_up(&vfs_phone_futex);
  192.     free(pa);
  193.     return (int) IPC_GET_ARG1(answer);
  194. }
  195.  
  196. int open(const char *path, int oflag, ...)
  197. {
  198.     return _open(path, L_FILE, oflag);
  199. }
  200.  
  201. int close(int fildes)
  202. {
  203.     int res;
  204.     ipcarg_t rc;
  205.  
  206.     futex_down(&vfs_phone_futex);
  207.     async_serialize_start();
  208.     if (vfs_phone < 0) {
  209.         res = vfs_connect();
  210.         if (res < 0) {
  211.             async_serialize_end();
  212.             futex_up(&vfs_phone_futex);
  213.             return res;
  214.         }
  215.     }
  216.        
  217.     rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes);
  218.  
  219.     async_serialize_end();
  220.     futex_up(&vfs_phone_futex);
  221.    
  222.     return (int)rc;
  223. }
  224.  
  225. ssize_t read(int fildes, void *buf, size_t nbyte)
  226. {
  227.     int res;
  228.     ipcarg_t rc;
  229.     ipc_call_t answer;
  230.     aid_t req;
  231.  
  232.     futex_down(&vfs_phone_futex);
  233.     async_serialize_start();
  234.     if (vfs_phone < 0) {
  235.         res = vfs_connect();
  236.         if (res < 0) {
  237.             async_serialize_end();
  238.             futex_up(&vfs_phone_futex);
  239.             return res;
  240.         }
  241.     }
  242.     req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
  243.     rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
  244.     if (rc != EOK) {
  245.         async_wait_for(req, NULL);
  246.         async_serialize_end();
  247.         futex_up(&vfs_phone_futex);
  248.         return (ssize_t) rc;
  249.     }
  250.     async_wait_for(req, &rc);
  251.     async_serialize_end();
  252.     futex_up(&vfs_phone_futex);
  253.     if (rc == EOK)
  254.         return (ssize_t) IPC_GET_ARG1(answer);
  255.     else
  256.         return -1;
  257. }
  258.  
  259. ssize_t write(int fildes, const 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_WRITE, fildes, &answer);
  277.     rc = ipc_data_write_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. off_t lseek(int fildes, off_t offset, int whence)
  294. {
  295.     int res;
  296.     ipcarg_t rc;
  297.  
  298.     futex_down(&vfs_phone_futex);
  299.     async_serialize_start();
  300.     if (vfs_phone < 0) {
  301.         res = vfs_connect();
  302.         if (res < 0) {
  303.             async_serialize_end();
  304.             futex_up(&vfs_phone_futex);
  305.             return res;
  306.         }
  307.     }
  308.        
  309.     off_t newoffs;
  310.     rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
  311.         (ipcarg_t)&newoffs);
  312.  
  313.     async_serialize_end();
  314.     futex_up(&vfs_phone_futex);
  315.  
  316.     if (rc != EOK)
  317.         return (off_t) -1;
  318.    
  319.     return newoffs;
  320. }
  321.  
  322. int ftruncate(int fildes, off_t length)
  323. {
  324.     int res;
  325.     ipcarg_t rc;
  326.    
  327.     futex_down(&vfs_phone_futex);
  328.     async_serialize_start();
  329.     if (vfs_phone < 0) {
  330.         res = vfs_connect();
  331.         if (res < 0) {
  332.             async_serialize_end();
  333.             futex_up(&vfs_phone_futex);
  334.             return res;
  335.         }
  336.     }
  337.     rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
  338.     async_serialize_end();
  339.     futex_up(&vfs_phone_futex);
  340.     return (int) rc;
  341. }
  342.  
  343. DIR *opendir(const char *dirname)
  344. {
  345.     DIR *dirp = malloc(sizeof(DIR));
  346.     if (!dirp)
  347.         return NULL;
  348.     dirp->fd = _open(dirname, L_DIRECTORY, 0);
  349.     if (dirp->fd < 0) {
  350.         free(dirp);
  351.         return NULL;
  352.     }
  353.     return dirp;
  354. }
  355.  
  356. struct dirent *readdir(DIR *dirp)
  357. {
  358.     ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
  359.     if (len <= 0)
  360.         return NULL;
  361.     return &dirp->res;
  362. }
  363.  
  364. void rewinddir(DIR *dirp)
  365. {
  366.     (void) lseek(dirp->fd, 0, SEEK_SET);
  367. }
  368.  
  369. int closedir(DIR *dirp)
  370. {
  371.     (void) close(dirp->fd);
  372.     free(dirp);
  373.     return 0;
  374. }
  375.  
  376. int mkdir(const char *path, mode_t mode)
  377. {
  378.     int res;
  379.     ipcarg_t rc;
  380.     aid_t req;
  381.    
  382.     char *pa = absolutize(path);
  383.     if (!pa)
  384.         return ENOMEM;
  385.     size_t pc_len;
  386.     char *pc = canonify(pa, &pc_len);
  387.     if (!pc) {
  388.         free(pa);
  389.         return EINVAL;
  390.     }
  391.  
  392.     futex_down(&vfs_phone_futex);
  393.     async_serialize_start();
  394.     if (vfs_phone < 0) {
  395.         res = vfs_connect();
  396.         if (res < 0) {
  397.             async_serialize_end();
  398.             futex_up(&vfs_phone_futex);
  399.             free(pa);
  400.             return res;
  401.         }
  402.     }
  403.     req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
  404.     rc = ipc_data_write_start(vfs_phone, pc, pc_len);
  405.     if (rc != EOK) {
  406.         async_wait_for(req, NULL);
  407.         async_serialize_end();
  408.         futex_up(&vfs_phone_futex);
  409.         free(pa);
  410.         return (int) rc;
  411.     }
  412.     async_wait_for(req, &rc);
  413.     async_serialize_end();
  414.     futex_up(&vfs_phone_futex);
  415.     free(pa);
  416.     return rc;
  417. }
  418.  
  419. static int _unlink(const char *path, int lflag)
  420. {
  421.     int res;
  422.     ipcarg_t rc;
  423.     aid_t req;
  424.    
  425.     char *pa = absolutize(path);
  426.     if (!pa)
  427.         return ENOMEM;
  428.     size_t pc_len;
  429.     char *pc = canonify(pa, &pc_len);
  430.     if (!pc) {
  431.         free(pa);
  432.         return EINVAL;
  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_0(vfs_phone, VFS_UNLINK, NULL);
  446.     rc = ipc_data_write_start(vfs_phone, pc, pc_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. int unlink(const char *path)
  462. {
  463.     return _unlink(path, L_NONE);
  464. }
  465.  
  466. int rmdir(const char *path)
  467. {
  468.     return _unlink(path, L_DIRECTORY);
  469. }
  470.  
  471. int rename(const char *old, const char *new)
  472. {
  473.     int res;
  474.     ipcarg_t rc;
  475.     aid_t req;
  476.    
  477.     char *olda = absolutize(old);
  478.     if (!olda)
  479.         return ENOMEM;
  480.     size_t oldc_len;
  481.     char *oldc = canonify(olda, &oldc_len);
  482.     if (!oldc) {
  483.         free(olda);
  484.         return EINVAL;
  485.     }
  486.     char *newa = absolutize(new);
  487.     if (!newa) {
  488.         free(olda);
  489.         return ENOMEM;
  490.     }
  491.     size_t newc_len;
  492.     char *newc = canonify(newa, &newc_len);
  493.     if (!newc) {
  494.         free(olda);
  495.         free(newa);
  496.         return EINVAL;
  497.     }
  498.  
  499.     futex_down(&vfs_phone_futex);
  500.     async_serialize_start();
  501.     if (vfs_phone < 0) {
  502.         res = vfs_connect();
  503.         if (res < 0) {
  504.             async_serialize_end();
  505.             futex_up(&vfs_phone_futex);
  506.             free(olda);
  507.             free(newa);
  508.             return res;
  509.         }
  510.     }
  511.     req = async_send_0(vfs_phone, VFS_RENAME, NULL);
  512.     rc = ipc_data_write_start(vfs_phone, oldc, oldc_len);
  513.     if (rc != EOK) {
  514.         async_wait_for(req, NULL);
  515.         async_serialize_end();
  516.         futex_up(&vfs_phone_futex);
  517.         free(olda);
  518.         free(newa);
  519.         return (int) rc;
  520.     }
  521.     rc = ipc_data_write_start(vfs_phone, newc, newc_len);
  522.     if (rc != EOK) {
  523.         async_wait_for(req, NULL);
  524.         async_serialize_end();
  525.         futex_up(&vfs_phone_futex);
  526.         free(olda);
  527.         free(newa);
  528.         return (int) rc;
  529.     }
  530.     async_wait_for(req, &rc);
  531.     async_serialize_end();
  532.     futex_up(&vfs_phone_futex);
  533.     free(olda);
  534.     free(newa);
  535.     return rc;
  536. }
  537.  
  538. int chdir(const char *path)
  539. {
  540.     char *pa = absolutize(path);
  541.     if (!pa)
  542.         return ENOMEM;
  543.     size_t pc_len;
  544.     char *pc = canonify(pa, &pc_len);
  545.     if (!pc) {
  546.         free(pa);
  547.         return ENOENT;
  548.     }
  549.  
  550.     DIR *d = opendir(pc);
  551.     if (!d) {
  552.         free(pa);
  553.         return ENOENT;
  554.     }
  555.  
  556.     futex_down(&cwd_futex);
  557.     if (cwd_dir) {
  558.         closedir(cwd_dir);
  559.         cwd_dir = NULL;
  560.         free(cwd_path);
  561.         cwd_path = NULL;
  562.         cwd_len = 0;
  563.     }
  564.     cwd_dir = d;
  565.     cwd_path = pc;
  566.     cwd_len = pc_len;
  567.     futex_up(&cwd_futex);
  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_len + 1) {
  576.         futex_up(&cwd_futex);
  577.         return NULL;
  578.     }
  579.     strcpy(buf, cwd_path);
  580.     futex_up(&cwd_futex);
  581.     return buf;
  582. }
  583.  
  584. /** @}
  585.  */
  586.