Subversion Repositories HelenOS

Rev

Rev 2752 | Rev 2766 | 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 fs
  30.  * @{
  31.  */
  32.  
  33. /**
  34.  * @file    vfs_ops.c
  35.  * @brief   Operations that VFS offers to its clients.
  36.  */
  37.  
  38. #include "vfs.h"
  39. #include <ipc/ipc.h>
  40. #include <async.h>
  41. #include <errno.h>
  42. #include <stdio.h>
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <bool.h>
  46. #include <futex.h>
  47. #include <rwlock.h>
  48. #include <libadt/list.h>
  49. #include <unistd.h>
  50. #include <ctype.h>
  51. #include <fcntl.h>
  52. #include <assert.h>
  53. #include <atomic.h>
  54. #include <vfs/canonify.h>
  55.  
  56. /* Forward declarations of static functions. */
  57. static int vfs_truncate_internal(int, int, unsigned long, size_t);
  58.  
  59. /**
  60.  * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
  61.  * concurrent VFS operation which modifies the file system namespace.
  62.  */
  63. RWLOCK_INITIALIZE(namespace_rwlock);
  64.  
  65. atomic_t rootfs_futex = FUTEX_INITIALIZER;
  66. vfs_triplet_t rootfs = {
  67.     .fs_handle = 0,
  68.     .dev_handle = 0,
  69.     .index = 0,
  70. };
  71.  
  72. static int lookup_root(int fs_handle, int dev_handle, vfs_lookup_res_t *result)
  73. {
  74.     vfs_pair_t altroot = {
  75.         .fs_handle = fs_handle,
  76.         .dev_handle = dev_handle,
  77.     };
  78.  
  79.     return vfs_lookup_internal("/", L_DIRECTORY, result, &altroot);
  80. }
  81.  
  82. void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
  83. {
  84.     int dev_handle;
  85.     vfs_node_t *mp_node = NULL;
  86.  
  87.     /*
  88.      * We expect the library to do the device-name to device-handle
  89.      * translation for us, thus the device handle will arrive as ARG1
  90.      * in the request.
  91.      */
  92.     dev_handle = IPC_GET_ARG1(*request);
  93.  
  94.     /*
  95.      * For now, don't make use of ARG2 and ARG3, but they can be used to
  96.      * carry mount options in the future.
  97.      */
  98.  
  99.     ipc_callid_t callid;
  100.     size_t size;
  101.  
  102.     /*
  103.      * Now, we expect the client to send us data with the name of the file
  104.      * system.
  105.      */
  106.     if (!ipc_data_write_receive(&callid, &size)) {
  107.         ipc_answer_0(callid, EINVAL);
  108.         ipc_answer_0(rid, EINVAL);
  109.         return;
  110.     }
  111.  
  112.     /*
  113.      * Don't receive more than is necessary for storing a full file system
  114.      * name.
  115.      */
  116.     if (size < 1 || size > FS_NAME_MAXLEN) {
  117.         ipc_answer_0(callid, EINVAL);
  118.         ipc_answer_0(rid, EINVAL);
  119.         return;
  120.     }
  121.  
  122.     /* Deliver the file system name. */
  123.     char fs_name[FS_NAME_MAXLEN + 1];
  124.     (void) ipc_data_write_finalize(callid, fs_name, size);
  125.     fs_name[size] = '\0';
  126.    
  127.     /*
  128.      * Check if we know a file system with the same name as is in fs_name.
  129.      * This will also give us its file system handle.
  130.      */
  131.     int fs_handle = fs_name_to_handle(fs_name, true);
  132.     if (!fs_handle) {
  133.         ipc_answer_0(rid, ENOENT);
  134.         return;
  135.     }
  136.  
  137.     /* Now, we want the client to send us the mount point. */
  138.     if (!ipc_data_write_receive(&callid, &size)) {
  139.         ipc_answer_0(callid, EINVAL);
  140.         ipc_answer_0(rid, EINVAL);
  141.         return;
  142.     }
  143.  
  144.     /* Check whether size is reasonable wrt. the mount point. */
  145.     if (size < 1 || size > MAX_PATH_LEN) {
  146.         ipc_answer_0(callid, EINVAL);
  147.         ipc_answer_0(rid, EINVAL);
  148.         return;
  149.     }
  150.     /* Allocate buffer for the mount point data being received. */
  151.     uint8_t *buf;
  152.     buf = malloc(size + 1);
  153.     if (!buf) {
  154.         ipc_answer_0(callid, ENOMEM);
  155.         ipc_answer_0(rid, ENOMEM);
  156.         return;
  157.     }
  158.  
  159.     /* Deliver the mount point. */
  160.     (void) ipc_data_write_finalize(callid, buf, size);
  161.     buf[size] = '\0';
  162.  
  163.     /*
  164.      * Lookup the root node of the filesystem being mounted.
  165.      * In this case, we don't need to take the namespace_futex as the root
  166.      * node cannot be removed. However, we do take a reference to it so
  167.      * that we can track how many times it has been mounted.
  168.      */
  169.     int rc;
  170.     vfs_lookup_res_t mr_res;
  171.     rc = lookup_root(fs_handle, dev_handle, &mr_res);
  172.     if (rc != EOK) {
  173.         free(buf);
  174.         ipc_answer_0(rid, rc);
  175.         return;
  176.     }
  177.     vfs_node_t *mr_node = vfs_node_get(&mr_res);
  178.     if (!mr_node) {
  179.         free(buf);
  180.         ipc_answer_0(rid, ENOMEM);
  181.         return;
  182.     }
  183.  
  184.     /* Finally, we need to resolve the path to the mountpoint. */
  185.     vfs_lookup_res_t mp_res;
  186.     futex_down(&rootfs_futex);
  187.     if (rootfs.fs_handle) {
  188.         /* We already have the root FS. */
  189.         rwlock_write_lock(&namespace_rwlock);
  190.         rc = vfs_lookup_internal(buf, L_DIRECTORY, &mp_res, NULL);
  191.         if (rc != EOK) {
  192.             /* The lookup failed for some reason. */
  193.             rwlock_write_unlock(&namespace_rwlock);
  194.             futex_up(&rootfs_futex);
  195.             vfs_node_put(mr_node);  /* failed -> drop reference */
  196.             free(buf);
  197.             ipc_answer_0(rid, rc);
  198.             return;
  199.         }
  200.         mp_node = vfs_node_get(&mp_res);
  201.         if (!mp_node) {
  202.             rwlock_write_unlock(&namespace_rwlock);
  203.             futex_up(&rootfs_futex);
  204.             vfs_node_put(mr_node);  /* failed -> drop reference */
  205.             free(buf);
  206.             ipc_answer_0(rid, ENOMEM);
  207.             return;
  208.         }
  209.         /*
  210.          * Now we hold a reference to mp_node.
  211.          * It will be dropped upon the corresponding VFS_UNMOUNT.
  212.          * This prevents the mount point from being deleted.
  213.          */
  214.         rwlock_write_unlock(&namespace_rwlock);
  215.     } else {
  216.         /* We still don't have the root file system mounted. */
  217.         if ((size == 1) && (buf[0] == '/')) {
  218.             /* For this simple, but important case, we are done. */
  219.             rootfs = mr_res.triplet;
  220.             futex_up(&rootfs_futex);
  221.             free(buf);
  222.             ipc_answer_0(rid, EOK);
  223.             return;
  224.         } else {
  225.             /*
  226.              * We can't resolve this without the root filesystem
  227.              * being mounted first.
  228.              */
  229.             futex_up(&rootfs_futex);
  230.             free(buf);
  231.             vfs_node_put(mr_node);  /* failed -> drop reference */
  232.             ipc_answer_0(rid, ENOENT);
  233.             return;
  234.         }
  235.     }
  236.     futex_up(&rootfs_futex);
  237.    
  238.     free(buf);  /* The buffer is not needed anymore. */
  239.    
  240.     /*
  241.      * At this point, we have all necessary pieces: file system and device
  242.      * handles, and we know the mount point VFS node and also the root node
  243.      * of the file system being mounted.
  244.      */
  245.  
  246.     int phone = vfs_grab_phone(mp_res.triplet.fs_handle);
  247.     /* Later we can use ARG3 to pass mode/flags. */
  248.     aid_t req1 = async_send_3(phone, VFS_MOUNT,
  249.         (ipcarg_t) mp_res.triplet.dev_handle,
  250.         (ipcarg_t) mp_res.triplet.index, 0, NULL);
  251.     /* The second call uses the same method. */
  252.     aid_t req2 = async_send_3(phone, VFS_MOUNT,
  253.         (ipcarg_t) mr_res.triplet.fs_handle,
  254.         (ipcarg_t) mr_res.triplet.dev_handle,
  255.         (ipcarg_t) mr_res.triplet.index, NULL);
  256.     vfs_release_phone(phone);
  257.  
  258.     ipcarg_t rc1;
  259.     ipcarg_t rc2;
  260.     async_wait_for(req1, &rc1);
  261.     async_wait_for(req2, &rc2);
  262.  
  263.     if ((rc1 != EOK) || (rc2 != EOK)) {
  264.         /* Mount failed, drop references to mr_node and mp_node. */
  265.         vfs_node_put(mr_node);
  266.         if (mp_node)
  267.             vfs_node_put(mp_node);
  268.     }
  269.    
  270.     if (rc2 == EOK)
  271.         ipc_answer_0(rid, rc1);
  272.     else if (rc1 == EOK)
  273.         ipc_answer_0(rid, rc2);
  274.     else
  275.         ipc_answer_0(rid, rc1);
  276. }
  277.  
  278. void vfs_open(ipc_callid_t rid, ipc_call_t *request)
  279. {
  280.     if (!vfs_files_init()) {
  281.         ipc_answer_0(rid, ENOMEM);
  282.         return;
  283.     }
  284.  
  285.     /*
  286.      * The POSIX interface is open(path, oflag, mode).
  287.      * We can receive oflags and mode along with the VFS_OPEN call; the path
  288.      * will need to arrive in another call.
  289.      *
  290.      * We also receive one private, non-POSIX set of flags called lflag
  291.      * used to pass information to vfs_lookup_internal().
  292.      */
  293.     int lflag = IPC_GET_ARG1(*request);
  294.     int oflag = IPC_GET_ARG2(*request);
  295.     int mode = IPC_GET_ARG3(*request);
  296.     size_t len;
  297.  
  298.     if (oflag & O_CREAT)
  299.         lflag |= L_CREATE;
  300.     if (oflag & O_EXCL)
  301.         lflag |= L_EXCLUSIVE;
  302.  
  303.     ipc_callid_t callid;
  304.  
  305.     if (!ipc_data_write_receive(&callid, &len)) {
  306.         ipc_answer_0(callid, EINVAL);
  307.         ipc_answer_0(rid, EINVAL);
  308.         return;
  309.     }
  310.     char *path = malloc(len + 1);
  311.     if (!path) {
  312.         ipc_answer_0(callid, ENOMEM);
  313.         ipc_answer_0(rid, ENOMEM);
  314.         return;
  315.     }
  316.     int rc;
  317.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  318.         ipc_answer_0(rid, rc);
  319.         free(path);
  320.         return;
  321.     }
  322.     path[len] = '\0';
  323.    
  324.     /*
  325.      * Avoid the race condition in which the file can be deleted before we
  326.      * find/create-and-lock the VFS node corresponding to the looked-up
  327.      * triplet.
  328.      */
  329.     if (lflag & L_CREATE)
  330.         rwlock_write_lock(&namespace_rwlock);
  331.     else
  332.         rwlock_read_lock(&namespace_rwlock);
  333.  
  334.     /* The path is now populated and we can call vfs_lookup_internal(). */
  335.     vfs_lookup_res_t lr;
  336.     rc = vfs_lookup_internal(path, lflag, &lr, NULL);
  337.     if (rc) {
  338.         if (lflag & L_CREATE)
  339.             rwlock_write_unlock(&namespace_rwlock);
  340.         else
  341.             rwlock_read_unlock(&namespace_rwlock);
  342.         ipc_answer_0(rid, rc);
  343.         free(path);
  344.         return;
  345.     }
  346.  
  347.     /* Path is no longer needed. */
  348.     free(path);
  349.  
  350.     vfs_node_t *node = vfs_node_get(&lr);
  351.     if (lflag & L_CREATE)
  352.         rwlock_write_unlock(&namespace_rwlock);
  353.     else
  354.         rwlock_read_unlock(&namespace_rwlock);
  355.  
  356.     /* Truncate the file if requested and if necessary. */
  357.     if (oflag & O_TRUNC) {
  358.         rwlock_write_lock(&node->contents_rwlock);
  359.         if (node->size) {
  360.             rc = vfs_truncate_internal(node->fs_handle,
  361.                 node->dev_handle, node->index, 0);
  362.             if (rc) {
  363.                 rwlock_write_unlock(&node->contents_rwlock);
  364.                 vfs_node_put(node);
  365.                 ipc_answer_0(rid, rc);
  366.                 return;
  367.             }
  368.             node->size = 0;
  369.         }
  370.         rwlock_write_unlock(&node->contents_rwlock);
  371.     }
  372.  
  373.     /*
  374.      * Get ourselves a file descriptor and the corresponding vfs_file_t
  375.      * structure.
  376.      */
  377.     int fd = vfs_fd_alloc();
  378.     if (fd < 0) {
  379.         vfs_node_put(node);
  380.         ipc_answer_0(rid, fd);
  381.         return;
  382.     }
  383.     vfs_file_t *file = vfs_file_get(fd);
  384.     file->node = node;
  385.     if (oflag & O_APPEND)
  386.         file->append = true;
  387.  
  388.     /*
  389.      * The following increase in reference count is for the fact that the
  390.      * file is being opened and that a file structure is pointing to it.
  391.      * It is necessary so that the file will not disappear when
  392.      * vfs_node_put() is called. The reference will be dropped by the
  393.      * respective VFS_CLOSE.
  394.      */
  395.     vfs_node_addref(node);
  396.     vfs_node_put(node);
  397.  
  398.     /* Success! Return the new file descriptor to the client. */
  399.     ipc_answer_1(rid, EOK, fd);
  400. }
  401.  
  402. void vfs_close(ipc_callid_t rid, ipc_call_t *request)
  403. {
  404.     int fd = IPC_GET_ARG1(*request);
  405.     if (fd >= MAX_OPEN_FILES) {
  406.         ipc_answer_0(rid, EBADF);
  407.         return;
  408.     }
  409.     vfs_fd_free(fd);
  410.     ipc_answer_0(rid, EOK);
  411. }
  412.  
  413. static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
  414. {
  415.  
  416.     /*
  417.      * The following code strongly depends on the fact that the files data
  418.      * structure can be only accessed by a single fibril and all file
  419.      * operations are serialized (i.e. the reads and writes cannot
  420.      * interleave and a file cannot be closed while it is being read).
  421.      *
  422.      * Additional synchronization needs to be added once the table of
  423.      * open files supports parallel access!
  424.      */
  425.  
  426.     int fd = IPC_GET_ARG1(*request);
  427.  
  428.     /* Lookup the file structure corresponding to the file descriptor. */
  429.     vfs_file_t *file = vfs_file_get(fd);
  430.     if (!file) {
  431.         ipc_answer_0(rid, ENOENT);
  432.         return;
  433.     }
  434.  
  435.     /*
  436.      * Now we need to receive a call with client's
  437.      * IPC_M_DATA_READ/IPC_M_DATA_WRITE request.
  438.      */
  439.     ipc_callid_t callid;
  440.     int res;
  441.     if (read)
  442.         res = ipc_data_read_receive(&callid, NULL);
  443.     else
  444.         res = ipc_data_write_receive(&callid, NULL);
  445.     if (!res) {
  446.         ipc_answer_0(callid, EINVAL);
  447.         ipc_answer_0(rid, EINVAL);
  448.         return;
  449.     }
  450.  
  451.     /*
  452.      * Lock the open file structure so that no other thread can manipulate
  453.      * the same open file at a time.
  454.      */
  455.     futex_down(&file->lock);
  456.  
  457.     /*
  458.      * Lock the file's node so that no other client can read/write to it at
  459.      * the same time.
  460.      */
  461.     if (read)
  462.         rwlock_read_lock(&file->node->contents_rwlock);
  463.     else
  464.         rwlock_write_lock(&file->node->contents_rwlock);
  465.  
  466.     int fs_phone = vfs_grab_phone(file->node->fs_handle);  
  467.    
  468.     /* Make a VFS_READ/VFS_WRITE request at the destination FS server. */
  469.     aid_t msg;
  470.     ipc_call_t answer;
  471.     if (!read && file->append)
  472.         file->pos = file->node->size;
  473.     msg = async_send_3(fs_phone, IPC_GET_METHOD(*request),
  474.         file->node->dev_handle, file->node->index, file->pos, &answer);
  475.    
  476.     /*
  477.      * Forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
  478.      * destination FS server. The call will be routed as if sent by
  479.      * ourselves. Note that call arguments are immutable in this case so we
  480.      * don't have to bother.
  481.      */
  482.     ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  483.  
  484.     vfs_release_phone(fs_phone);
  485.  
  486.     /* Wait for reply from the FS server. */
  487.     ipcarg_t rc;
  488.     async_wait_for(msg, &rc);
  489.     size_t bytes = IPC_GET_ARG1(answer);
  490.  
  491.     /* Unlock the VFS node. */
  492.     if (read)
  493.         rwlock_read_unlock(&file->node->contents_rwlock);
  494.     else {
  495.         /* Update the cached version of node's size. */
  496.         if (rc == EOK)
  497.             file->node->size = IPC_GET_ARG2(answer);
  498.         rwlock_write_unlock(&file->node->contents_rwlock);
  499.     }
  500.  
  501.     /* Update the position pointer and unlock the open file. */
  502.     if (rc == EOK)
  503.         file->pos += bytes;
  504.     futex_up(&file->lock);
  505.  
  506.     /*
  507.      * FS server's reply is the final result of the whole operation we
  508.      * return to the client.
  509.      */
  510.     ipc_answer_1(rid, rc, bytes);
  511. }
  512.  
  513. void vfs_read(ipc_callid_t rid, ipc_call_t *request)
  514. {
  515.     vfs_rdwr(rid, request, true);
  516. }
  517.  
  518. void vfs_write(ipc_callid_t rid, ipc_call_t *request)
  519. {
  520.     vfs_rdwr(rid, request, false);
  521. }
  522.  
  523. void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
  524. {
  525.     int fd = (int) IPC_GET_ARG1(*request);
  526.     off_t off = (off_t) IPC_GET_ARG2(*request);
  527.     int whence = (int) IPC_GET_ARG3(*request);
  528.  
  529.  
  530.     /* Lookup the file structure corresponding to the file descriptor. */
  531.     vfs_file_t *file = vfs_file_get(fd);
  532.     if (!file) {
  533.         ipc_answer_0(rid, ENOENT);
  534.         return;
  535.     }
  536.  
  537.     off_t newpos;
  538.     futex_down(&file->lock);
  539.     if (whence == SEEK_SET) {
  540.         file->pos = off;
  541.         futex_up(&file->lock);
  542.         ipc_answer_1(rid, EOK, off);
  543.         return;
  544.     }
  545.     if (whence == SEEK_CUR) {
  546.         if (file->pos + off < file->pos) {
  547.             futex_up(&file->lock);
  548.             ipc_answer_0(rid, EOVERFLOW);
  549.             return;
  550.         }
  551.         file->pos += off;
  552.         newpos = file->pos;
  553.         futex_up(&file->lock);
  554.         ipc_answer_1(rid, EOK, newpos);
  555.         return;
  556.     }
  557.     if (whence == SEEK_END) {
  558.         rwlock_read_lock(&file->node->contents_rwlock);
  559.         size_t size = file->node->size;
  560.         rwlock_read_unlock(&file->node->contents_rwlock);
  561.         if (size + off < size) {
  562.             futex_up(&file->lock);
  563.             ipc_answer_0(rid, EOVERFLOW);
  564.             return;
  565.         }
  566.         newpos = size + off;
  567.         futex_up(&file->lock);
  568.         ipc_answer_1(rid, EOK, newpos);
  569.         return;
  570.     }
  571.     futex_up(&file->lock);
  572.     ipc_answer_0(rid, EINVAL);
  573. }
  574.  
  575. int vfs_truncate_internal(int fs_handle, int dev_handle, unsigned long index,
  576.     size_t size)
  577. {
  578.     ipcarg_t rc;
  579.     int fs_phone;
  580.    
  581.     fs_phone = vfs_grab_phone(fs_handle);
  582.     rc = async_req_3_0(fs_phone, VFS_TRUNCATE, (ipcarg_t)dev_handle,
  583.         (ipcarg_t)index, (ipcarg_t)size);
  584.     vfs_release_phone(fs_phone);
  585.     return (int)rc;
  586. }
  587.  
  588. void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
  589. {
  590.     int fd = IPC_GET_ARG1(*request);
  591.     size_t size = IPC_GET_ARG2(*request);
  592.     int rc;
  593.  
  594.     vfs_file_t *file = vfs_file_get(fd);
  595.     if (!file) {
  596.         ipc_answer_0(rid, ENOENT);
  597.         return;
  598.     }
  599.     futex_down(&file->lock);
  600.  
  601.     rwlock_write_lock(&file->node->contents_rwlock);
  602.     rc = vfs_truncate_internal(file->node->fs_handle,
  603.         file->node->dev_handle, file->node->index, size);
  604.     if (rc == EOK)
  605.         file->node->size = size;
  606.     rwlock_write_unlock(&file->node->contents_rwlock);
  607.  
  608.     futex_up(&file->lock);
  609.     ipc_answer_0(rid, (ipcarg_t)rc);
  610. }
  611.  
  612. void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
  613. {
  614.     int mode = IPC_GET_ARG1(*request);
  615.  
  616.     size_t len;
  617.     ipc_callid_t callid;
  618.  
  619.     if (!ipc_data_write_receive(&callid, &len)) {
  620.         ipc_answer_0(callid, EINVAL);
  621.         ipc_answer_0(rid, EINVAL);
  622.         return;
  623.     }
  624.     char *path = malloc(len + 1);
  625.     if (!path) {
  626.         ipc_answer_0(callid, ENOMEM);
  627.         ipc_answer_0(rid, ENOMEM);
  628.         return;
  629.     }
  630.     int rc;
  631.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  632.         ipc_answer_0(rid, rc);
  633.         free(path);
  634.         return;
  635.     }
  636.     path[len] = '\0';
  637.    
  638.     rwlock_write_lock(&namespace_rwlock);
  639.     int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
  640.     rc = vfs_lookup_internal(path, lflag, NULL, NULL);
  641.     rwlock_write_unlock(&namespace_rwlock);
  642.     free(path);
  643.     ipc_answer_0(rid, rc);
  644. }
  645.  
  646. void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
  647. {
  648.     int lflag = IPC_GET_ARG1(*request);
  649.  
  650.     size_t len;
  651.     ipc_callid_t callid;
  652.  
  653.     if (!ipc_data_write_receive(&callid, &len)) {
  654.         ipc_answer_0(callid, EINVAL);
  655.         ipc_answer_0(rid, EINVAL);
  656.         return;
  657.     }
  658.     char *path = malloc(len + 1);
  659.     if (!path) {
  660.         ipc_answer_0(callid, ENOMEM);
  661.         ipc_answer_0(rid, ENOMEM);
  662.         return;
  663.     }
  664.     int rc;
  665.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  666.         ipc_answer_0(rid, rc);
  667.         free(path);
  668.         return;
  669.     }
  670.     path[len] = '\0';
  671.    
  672.     rwlock_write_lock(&namespace_rwlock);
  673.     lflag &= L_DIRECTORY;   /* sanitize lflag */
  674.     vfs_lookup_res_t lr;
  675.     rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
  676.     free(path);
  677.     if (rc != EOK) {
  678.         rwlock_write_unlock(&namespace_rwlock);
  679.         ipc_answer_0(rid, rc);
  680.         return;
  681.     }
  682.  
  683.     /*
  684.      * The name has already been unlinked by vfs_lookup_internal().
  685.      * We have to get and put the VFS node to ensure that it is
  686.      * VFS_DESTROY'ed after the last reference to it is dropped.
  687.      */
  688.     vfs_node_t *node = vfs_node_get(&lr);
  689.     node->lnkcnt--;
  690.     rwlock_write_unlock(&namespace_rwlock);
  691.     vfs_node_put(node);
  692.     ipc_answer_0(rid, EOK);
  693. }
  694.  
  695. void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
  696. {
  697.     size_t len;
  698.     ipc_callid_t callid;
  699.     int rc;
  700.  
  701.     /* Retrieve the old path. */
  702.     if (!ipc_data_write_receive(&callid, &len)) {
  703.         ipc_answer_0(callid, EINVAL);
  704.         ipc_answer_0(rid, EINVAL);
  705.         return;
  706.     }
  707.     char *old = malloc(len + 1);
  708.     if (!old) {
  709.         ipc_answer_0(callid, ENOMEM);
  710.         ipc_answer_0(rid, ENOMEM);
  711.         return;
  712.     }
  713.     if ((rc = ipc_data_write_finalize(callid, old, len))) {
  714.         ipc_answer_0(rid, rc);
  715.         free(old);
  716.         return;
  717.     }
  718.     old[len] = '\0';
  719.    
  720.     /* Retrieve the new path. */
  721.     if (!ipc_data_write_receive(&callid, &len)) {
  722.         ipc_answer_0(callid, EINVAL);
  723.         ipc_answer_0(rid, EINVAL);
  724.         free(old);
  725.         return;
  726.     }
  727.     char *new = malloc(len + 1);
  728.     if (!new) {
  729.         ipc_answer_0(callid, ENOMEM);
  730.         ipc_answer_0(rid, ENOMEM);
  731.         free(old);
  732.         return;
  733.     }
  734.     if ((rc = ipc_data_write_finalize(callid, new, len))) {
  735.         ipc_answer_0(rid, rc);
  736.         free(old);
  737.         free(new);
  738.         return;
  739.     }
  740.     new[len] = '\0';
  741.  
  742.     char *oldc = canonify(old, &len);
  743.     char *newc = canonify(new, NULL);
  744.     if (!oldc || !newc) {
  745.         ipc_answer_0(rid, EINVAL);
  746.         free(old);
  747.         free(new);
  748.         return;
  749.     }
  750.     if (!strncmp(newc, oldc, len)) {
  751.         /* oldc is a prefix of newc */
  752.         ipc_answer_0(rid, EINVAL);
  753.         free(old);
  754.         free(new);
  755.         return;
  756.     }
  757.    
  758.     vfs_lookup_res_t old_lr;
  759.     vfs_lookup_res_t new_lr;
  760.     vfs_lookup_res_t new_par_lr;
  761.     rwlock_write_lock(&namespace_rwlock);
  762.     /* Lookup the node belonging to the old file name. */
  763.     rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
  764.     if (rc != EOK) {
  765.         rwlock_write_unlock(&namespace_rwlock);
  766.         ipc_answer_0(rid, rc);
  767.         free(old);
  768.         free(new);
  769.         return;
  770.     }
  771.     vfs_node_t *old_node = vfs_node_get(&old_lr);
  772.     if (!old_node) {
  773.         rwlock_write_unlock(&namespace_rwlock);
  774.         ipc_answer_0(rid, ENOMEM);
  775.         free(old);
  776.         free(new);
  777.         return;
  778.     }
  779.     /* Lookup parent of the new file name. */
  780.     rc = vfs_lookup_internal(newc, L_PARENT, &new_par_lr, NULL);
  781.     if (rc != EOK) {
  782.         rwlock_write_unlock(&namespace_rwlock);
  783.         ipc_answer_0(rid, rc);
  784.         free(old);
  785.         free(new);
  786.         return;
  787.     }
  788.     /* Check whether linking to the same file system instance. */
  789.     if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
  790.         (old_node->dev_handle != new_par_lr.triplet.dev_handle)) {
  791.         rwlock_write_unlock(&namespace_rwlock);
  792.         ipc_answer_0(rid, EXDEV);   /* different file systems */
  793.         free(old);
  794.         free(new);
  795.         return;
  796.     }
  797.     /* Destroy the old link for the new name. */
  798.     vfs_node_t *new_node = NULL;
  799.     rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
  800.     switch (rc) {
  801.     case ENOENT:
  802.         /* simply not in our way */
  803.         break;
  804.     case EOK:
  805.         new_node = vfs_node_get(&new_lr);
  806.         if (!new_node) {
  807.             rwlock_write_unlock(&namespace_rwlock);
  808.             ipc_answer_0(rid, ENOMEM);
  809.             free(old);
  810.             free(new);
  811.             return;
  812.         }
  813.         new_node->lnkcnt--;
  814.         break;
  815.     default:
  816.         rwlock_write_unlock(&namespace_rwlock);
  817.         ipc_answer_0(rid, ENOTEMPTY);
  818.         free(old);
  819.         free(new);
  820.         return;
  821.     }
  822.     /* Create the new link for the new name. */
  823.     rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
  824.     if (rc != EOK) {
  825.         rwlock_write_unlock(&namespace_rwlock);
  826.         if (new_node)
  827.             vfs_node_put(new_node);
  828.         ipc_answer_0(rid, rc);
  829.         free(old);
  830.         free(new);
  831.         return;
  832.     }
  833.     old_node->lnkcnt++;
  834.     /* Destroy the link for the old name. */
  835.     rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
  836.     if (rc != EOK) {
  837.         rwlock_write_unlock(&namespace_rwlock);
  838.         vfs_node_put(old_node);
  839.         if (new_node)
  840.             vfs_node_put(new_node);
  841.         ipc_answer_0(rid, rc);
  842.         free(old);
  843.         free(new);
  844.         return;
  845.     }
  846.     old_node->lnkcnt--;
  847.     rwlock_write_unlock(&namespace_rwlock);
  848.     vfs_node_put(old_node);
  849.     if (new_node)
  850.         vfs_node_put(new_node);
  851.     free(old);
  852.     free(new);
  853.     ipc_answer_0(rid, EOK);
  854. }
  855.  
  856. /**
  857.  * @}
  858.  */
  859.