| [62da45a] | 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 | 
 | 
|---|
| [b1834a01] | 29 | /** @addtogroup vfs
 | 
|---|
| [62da45a] | 30 |  * @{
 | 
|---|
| [05b9912] | 31 |  */
 | 
|---|
| [62da45a] | 32 | 
 | 
|---|
 | 33 | /**
 | 
|---|
| [05b9912] | 34 |  * @file vfs_lookup.c
 | 
|---|
| [62da45a] | 35 |  * @brief
 | 
|---|
 | 36 |  */
 | 
|---|
 | 37 | 
 | 
|---|
| [dadcec1] | 38 | #include "vfs.h"
 | 
|---|
| [ed903174] | 39 | #include <macros.h>
 | 
|---|
| [62da45a] | 40 | #include <async.h>
 | 
|---|
 | 41 | #include <errno.h>
 | 
|---|
| [19f857a] | 42 | #include <str.h>
 | 
|---|
| [a8e9ab8d] | 43 | #include <stdarg.h>
 | 
|---|
| [3e6a98c5] | 44 | #include <stdbool.h>
 | 
|---|
| [1e4cada] | 45 | #include <fibril_synch.h>
 | 
|---|
| [d9c8c81] | 46 | #include <adt/list.h>
 | 
|---|
| [dadcec1] | 47 | #include <vfs/canonify.h>
 | 
|---|
| [bf9dc4e2] | 48 | #include <dirent.h>
 | 
|---|
 | 49 | #include <assert.h>
 | 
|---|
 | 50 | 
 | 
|---|
| [553492be] | 51 | FIBRIL_MUTEX_INITIALIZE(plb_mutex);
 | 
|---|
| [b72efe8] | 52 | LIST_INITIALIZE(plb_entries);   /**< PLB entry ring buffer. */
 | 
|---|
| [62da45a] | 53 | uint8_t *plb = NULL;
 | 
|---|
 | 54 | 
 | 
|---|
| [b7fd2a0] | 55 | static errno_t plb_insert_entry(plb_entry_t *entry, char *path, size_t *start,
 | 
|---|
| [61042de] | 56 |     size_t len)
 | 
|---|
| [62da45a] | 57 | {
 | 
|---|
| [553492be] | 58 |         fibril_mutex_lock(&plb_mutex);
 | 
|---|
| [62da45a] | 59 | 
 | 
|---|
| [bf9dc4e2] | 60 |         link_initialize(&entry->plb_link);
 | 
|---|
 | 61 |         entry->len = len;
 | 
|---|
| [62da45a] | 62 | 
 | 
|---|
| [ed903174] | 63 |         size_t first;   /* the first free index */
 | 
|---|
 | 64 |         size_t last;    /* the last free index */
 | 
|---|
| [62da45a] | 65 | 
 | 
|---|
| [b72efe8] | 66 |         if (list_empty(&plb_entries)) {
 | 
|---|
| [62da45a] | 67 |                 first = 0;
 | 
|---|
 | 68 |                 last = PLB_SIZE - 1;
 | 
|---|
 | 69 |         } else {
 | 
|---|
| [b72efe8] | 70 |                 plb_entry_t *oldest = list_get_instance(
 | 
|---|
 | 71 |                     list_first(&plb_entries), plb_entry_t, plb_link);
 | 
|---|
 | 72 |                 plb_entry_t *newest = list_get_instance(
 | 
|---|
 | 73 |                     list_last(&plb_entries), plb_entry_t, plb_link);
 | 
|---|
| [62da45a] | 74 | 
 | 
|---|
 | 75 |                 first = (newest->index + newest->len) % PLB_SIZE;
 | 
|---|
 | 76 |                 last = (oldest->index - 1) % PLB_SIZE;
 | 
|---|
 | 77 |         }
 | 
|---|
 | 78 | 
 | 
|---|
 | 79 |         if (first <= last) {
 | 
|---|
 | 80 |                 if ((last - first) + 1 < len) {
 | 
|---|
 | 81 |                         /*
 | 
|---|
 | 82 |                          * The buffer cannot absorb the path.
 | 
|---|
 | 83 |                          */
 | 
|---|
| [553492be] | 84 |                         fibril_mutex_unlock(&plb_mutex);
 | 
|---|
| [62da45a] | 85 |                         return ELIMIT;
 | 
|---|
 | 86 |                 }
 | 
|---|
 | 87 |         } else {
 | 
|---|
 | 88 |                 if (PLB_SIZE - ((first - last) + 1) < len) {
 | 
|---|
 | 89 |                         /*
 | 
|---|
 | 90 |                          * The buffer cannot absorb the path.
 | 
|---|
 | 91 |                          */
 | 
|---|
| [553492be] | 92 |                         fibril_mutex_unlock(&plb_mutex);
 | 
|---|
| [62da45a] | 93 |                         return ELIMIT;
 | 
|---|
 | 94 |                 }
 | 
|---|
 | 95 |         }
 | 
|---|
 | 96 | 
 | 
|---|
 | 97 |         /*
 | 
|---|
 | 98 |          * We know the first free index in PLB and we also know that there is
 | 
|---|
 | 99 |          * enough space in the buffer to hold our path.
 | 
|---|
 | 100 |          */
 | 
|---|
 | 101 | 
 | 
|---|
| [bf9dc4e2] | 102 |         entry->index = first;
 | 
|---|
 | 103 |         entry->len = len;
 | 
|---|
| [62da45a] | 104 | 
 | 
|---|
 | 105 |         /*
 | 
|---|
 | 106 |          * Claim PLB space by inserting the entry into the PLB entry ring
 | 
|---|
 | 107 |          * buffer.
 | 
|---|
 | 108 |          */
 | 
|---|
| [bf9dc4e2] | 109 |         list_append(&entry->plb_link, &plb_entries);
 | 
|---|
| [a35b458] | 110 | 
 | 
|---|
| [553492be] | 111 |         fibril_mutex_unlock(&plb_mutex);
 | 
|---|
| [62da45a] | 112 | 
 | 
|---|
 | 113 |         /*
 | 
|---|
 | 114 |          * Copy the path into PLB.
 | 
|---|
 | 115 |          */
 | 
|---|
 | 116 |         size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
 | 
|---|
 | 117 |         size_t cnt2 = len - cnt1;
 | 
|---|
| [a35b458] | 118 | 
 | 
|---|
| [62da45a] | 119 |         memcpy(&plb[first], path, cnt1);
 | 
|---|
 | 120 |         memcpy(plb, &path[cnt1], cnt2);
 | 
|---|
 | 121 | 
 | 
|---|
| [bf9dc4e2] | 122 |         *start = first;
 | 
|---|
 | 123 |         return EOK;
 | 
|---|
 | 124 | }
 | 
|---|
 | 125 | 
 | 
|---|
 | 126 | static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
 | 
|---|
 | 127 | {
 | 
|---|
| [553492be] | 128 |         fibril_mutex_lock(&plb_mutex);
 | 
|---|
| [bf9dc4e2] | 129 |         list_remove(&entry->plb_link);
 | 
|---|
| [62da45a] | 130 |         /*
 | 
|---|
 | 131 |          * Erasing the path from PLB will come handy for debugging purposes.
 | 
|---|
 | 132 |          */
 | 
|---|
| [bf9dc4e2] | 133 |         size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
 | 
|---|
 | 134 |         size_t cnt2 = len - cnt1;
 | 
|---|
| [62da45a] | 135 |         memset(&plb[first], 0, cnt1);
 | 
|---|
 | 136 |         memset(plb, 0, cnt2);
 | 
|---|
| [553492be] | 137 |         fibril_mutex_unlock(&plb_mutex);
 | 
|---|
| [bf9dc4e2] | 138 | }
 | 
|---|
 | 139 | 
 | 
|---|
| [b7fd2a0] | 140 | errno_t vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
 | 
|---|
| [bf9dc4e2] | 141 | {
 | 
|---|
 | 142 |         assert(base != NULL);
 | 
|---|
 | 143 |         assert(child != NULL);
 | 
|---|
 | 144 |         assert(base->fs_handle);
 | 
|---|
 | 145 |         assert(child->fs_handle);
 | 
|---|
 | 146 |         assert(path != NULL);
 | 
|---|
| [a35b458] | 147 | 
 | 
|---|
| [bf9dc4e2] | 148 |         vfs_lookup_res_t res;
 | 
|---|
 | 149 |         char component[NAME_MAX + 1];
 | 
|---|
| [b7fd2a0] | 150 |         errno_t rc;
 | 
|---|
| [a35b458] | 151 | 
 | 
|---|
| [bf9dc4e2] | 152 |         size_t len;
 | 
|---|
 | 153 |         char *npath = canonify(path, &len);
 | 
|---|
 | 154 |         if (!npath) {
 | 
|---|
 | 155 |                 rc = EINVAL;
 | 
|---|
 | 156 |                 goto out;
 | 
|---|
 | 157 |         }
 | 
|---|
 | 158 |         path = npath;
 | 
|---|
| [a35b458] | 159 | 
 | 
|---|
| [5bcd5b7] | 160 |         vfs_triplet_t *triplet;
 | 
|---|
| [a35b458] | 161 | 
 | 
|---|
| [f6b6b40] | 162 |         char *slash = str_rchr(path, L'/');
 | 
|---|
| [bf9dc4e2] | 163 |         if (slash && slash != path) {
 | 
|---|
 | 164 |                 if (slash[1] == 0) {
 | 
|---|
 | 165 |                         rc = EINVAL;
 | 
|---|
 | 166 |                         goto out;
 | 
|---|
 | 167 |                 }
 | 
|---|
| [a35b458] | 168 | 
 | 
|---|
| [bf9dc4e2] | 169 |                 memcpy(component, slash + 1, str_size(slash));
 | 
|---|
 | 170 |                 *slash = 0;
 | 
|---|
| [a35b458] | 171 | 
 | 
|---|
| [bf9dc4e2] | 172 |                 rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
 | 
|---|
| [61042de] | 173 |                 if (rc != EOK)
 | 
|---|
| [bf9dc4e2] | 174 |                         goto out;
 | 
|---|
| [5bcd5b7] | 175 |                 triplet = &res.triplet;
 | 
|---|
| [a35b458] | 176 | 
 | 
|---|
| [bf9dc4e2] | 177 |                 *slash = '/';
 | 
|---|
 | 178 |         } else {
 | 
|---|
| [5bcd5b7] | 179 |                 if (base->mount != NULL) {
 | 
|---|
 | 180 |                         rc = EINVAL;
 | 
|---|
 | 181 |                         goto out;
 | 
|---|
 | 182 |                 }
 | 
|---|
| [a35b458] | 183 | 
 | 
|---|
| [bf9dc4e2] | 184 |                 memcpy(component, path + 1, str_size(path));
 | 
|---|
| [5bcd5b7] | 185 |                 triplet = (vfs_triplet_t *) base;
 | 
|---|
| [bf9dc4e2] | 186 |         }
 | 
|---|
| [a35b458] | 187 | 
 | 
|---|
| [61042de] | 188 |         if (triplet->fs_handle != child->fs_handle ||
 | 
|---|
 | 189 |             triplet->service_id != child->service_id) {
 | 
|---|
| [bf9dc4e2] | 190 |                 rc = EXDEV;
 | 
|---|
 | 191 |                 goto out;
 | 
|---|
 | 192 |         }
 | 
|---|
| [a35b458] | 193 | 
 | 
|---|
| [5bcd5b7] | 194 |         async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
 | 
|---|
| [61042de] | 195 |         aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id,
 | 
|---|
 | 196 |             triplet->index, child->index, NULL);
 | 
|---|
| [a35b458] | 197 | 
 | 
|---|
| [bf9dc4e2] | 198 |         rc = async_data_write_start(exch, component, str_size(component) + 1);
 | 
|---|
| [b7fd2a0] | 199 |         errno_t orig_rc;
 | 
|---|
| [bf9dc4e2] | 200 |         async_wait_for(req, &orig_rc);
 | 
|---|
 | 201 |         vfs_exchange_release(exch);
 | 
|---|
| [61042de] | 202 |         if (orig_rc != EOK)
 | 
|---|
| [bf9dc4e2] | 203 |                 rc = orig_rc;
 | 
|---|
| [a35b458] | 204 | 
 | 
|---|
| [bf9dc4e2] | 205 | out:
 | 
|---|
 | 206 |         return rc;
 | 
|---|
 | 207 | }
 | 
|---|
| [cead2aa] | 208 | 
 | 
|---|
| [b7fd2a0] | 209 | static errno_t out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
 | 
|---|
| [61042de] | 210 |     int lflag, vfs_lookup_res_t *result)
 | 
|---|
| [5bcd5b7] | 211 | {
 | 
|---|
 | 212 |         assert(base);
 | 
|---|
 | 213 |         assert(result);
 | 
|---|
| [a35b458] | 214 | 
 | 
|---|
| [b7fd2a0] | 215 |         errno_t rc;
 | 
|---|
| [5bcd5b7] | 216 |         ipc_call_t answer;
 | 
|---|
 | 217 |         async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
 | 
|---|
| [61042de] | 218 |         aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst,
 | 
|---|
 | 219 |             (sysarg_t) *plen, (sysarg_t) base->service_id,
 | 
|---|
 | 220 |             (sysarg_t) base->index, (sysarg_t) lflag, &answer);
 | 
|---|
| [5bcd5b7] | 221 |         async_wait_for(req, &rc);
 | 
|---|
 | 222 |         vfs_exchange_release(exch);
 | 
|---|
| [a35b458] | 223 | 
 | 
|---|
| [6fb8b2c] | 224 |         if (rc != EOK)
 | 
|---|
 | 225 |                 return rc;
 | 
|---|
| [a35b458] | 226 | 
 | 
|---|
| [5bcd5b7] | 227 |         unsigned last = *pfirst + *plen;
 | 
|---|
| [51774cd] | 228 |         *pfirst = IPC_GET_ARG3(answer) & 0xffff;
 | 
|---|
| [5bcd5b7] | 229 |         *plen = last - *pfirst;
 | 
|---|
| [a35b458] | 230 | 
 | 
|---|
| [6fb8b2c] | 231 |         result->triplet.fs_handle = (fs_handle_t) IPC_GET_ARG1(answer);
 | 
|---|
 | 232 |         result->triplet.service_id = base->service_id;
 | 
|---|
| [ed903174] | 233 |         result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
 | 
|---|
| [51774cd] | 234 |         result->size = MERGE_LOUP32(IPC_GET_ARG4(answer), IPC_GET_ARG5(answer));
 | 
|---|
 | 235 |         result->type = (IPC_GET_ARG3(answer) >> 16) ?
 | 
|---|
| [61042de] | 236 |             VFS_NODE_DIRECTORY : VFS_NODE_FILE;
 | 
|---|
| [5bcd5b7] | 237 |         return EOK;
 | 
|---|
 | 238 | }
 | 
|---|
 | 239 | 
 | 
|---|
| [b7fd2a0] | 240 | static errno_t _vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
 | 
|---|
| [e4e546b] | 241 |     vfs_lookup_res_t *result, size_t len)
 | 
|---|
| [bf9dc4e2] | 242 | {
 | 
|---|
 | 243 |         size_t first;
 | 
|---|
| [b7fd2a0] | 244 |         errno_t rc;
 | 
|---|
| [e4e546b] | 245 | 
 | 
|---|
| [bf9dc4e2] | 246 |         plb_entry_t entry;
 | 
|---|
 | 247 |         rc = plb_insert_entry(&entry, path, &first, len);
 | 
|---|
| [61042de] | 248 |         if (rc != EOK)
 | 
|---|
| [5bcd5b7] | 249 |                 return rc;
 | 
|---|
| [a35b458] | 250 | 
 | 
|---|
| [5bcd5b7] | 251 |         size_t next = first;
 | 
|---|
 | 252 |         size_t nlen = len;
 | 
|---|
| [a35b458] | 253 | 
 | 
|---|
| [5bcd5b7] | 254 |         vfs_lookup_res_t res;
 | 
|---|
| [a35b458] | 255 | 
 | 
|---|
| [5bcd5b7] | 256 |         /* Resolve path as long as there are mount points to cross. */
 | 
|---|
 | 257 |         while (nlen > 0) {
 | 
|---|
| [61042de] | 258 |                 while (base->mount) {
 | 
|---|
| [5bcd5b7] | 259 |                         if (lflag & L_DISABLE_MOUNTS) {
 | 
|---|
 | 260 |                                 rc = EXDEV;
 | 
|---|
 | 261 |                                 goto out;
 | 
|---|
 | 262 |                         }
 | 
|---|
| [a35b458] | 263 | 
 | 
|---|
| [5bcd5b7] | 264 |                         base = base->mount;
 | 
|---|
 | 265 |                 }
 | 
|---|
| [a35b458] | 266 | 
 | 
|---|
| [61042de] | 267 |                 rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag,
 | 
|---|
 | 268 |                     &res);
 | 
|---|
 | 269 |                 if (rc != EOK)
 | 
|---|
| [5bcd5b7] | 270 |                         goto out;
 | 
|---|
| [a35b458] | 271 | 
 | 
|---|
| [5bcd5b7] | 272 |                 if (nlen > 0) {
 | 
|---|
 | 273 |                         base = vfs_node_peek(&res);
 | 
|---|
| [4f9ab1e] | 274 |                         if (!base) {
 | 
|---|
| [5bcd5b7] | 275 |                                 rc = ENOENT;
 | 
|---|
 | 276 |                                 goto out;
 | 
|---|
 | 277 |                         }
 | 
|---|
| [1433ecda] | 278 |                         if (!base->mount) {
 | 
|---|
| [4f9ab1e] | 279 |                                 vfs_node_put(base);
 | 
|---|
 | 280 |                                 rc = ENOENT;
 | 
|---|
 | 281 |                                 goto out;
 | 
|---|
 | 282 |                         }
 | 
|---|
 | 283 |                         vfs_node_put(base);
 | 
|---|
| [5bcd5b7] | 284 |                         if (lflag & L_DISABLE_MOUNTS) {
 | 
|---|
 | 285 |                                 rc = EXDEV;
 | 
|---|
 | 286 |                                 goto out;
 | 
|---|
 | 287 |                         }
 | 
|---|
 | 288 |                 }
 | 
|---|
| [bf9dc4e2] | 289 |         }
 | 
|---|
| [a35b458] | 290 | 
 | 
|---|
| [5bcd5b7] | 291 |         assert(nlen == 0);
 | 
|---|
 | 292 |         rc = EOK;
 | 
|---|
| [a35b458] | 293 | 
 | 
|---|
| [5bcd5b7] | 294 |         if (result != NULL) {
 | 
|---|
 | 295 |                 /* The found file may be a mount point. Try to cross it. */
 | 
|---|
| [4f9ab1e] | 296 |                 if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
 | 
|---|
| [5bcd5b7] | 297 |                         base = vfs_node_peek(&res);
 | 
|---|
| [4f9ab1e] | 298 |                         if (base && base->mount) {
 | 
|---|
 | 299 |                                 while (base->mount) {
 | 
|---|
 | 300 |                                         vfs_node_addref(base->mount);
 | 
|---|
 | 301 |                                         vfs_node_t *nbase = base->mount;
 | 
|---|
 | 302 |                                         vfs_node_put(base);
 | 
|---|
 | 303 |                                         base = nbase;
 | 
|---|
| [5bcd5b7] | 304 |                                 }
 | 
|---|
| [a35b458] | 305 | 
 | 
|---|
| [4f9ab1e] | 306 |                                 result->triplet = *((vfs_triplet_t *) base);
 | 
|---|
| [5bcd5b7] | 307 |                                 result->type = base->type;
 | 
|---|
| [4f9ab1e] | 308 |                                 result->size = base->size;
 | 
|---|
 | 309 |                                 vfs_node_put(base);
 | 
|---|
| [5bcd5b7] | 310 |                                 goto out;
 | 
|---|
 | 311 |                         }
 | 
|---|
| [4f9ab1e] | 312 |                         if (base)
 | 
|---|
 | 313 |                                 vfs_node_put(base);
 | 
|---|
| [5bcd5b7] | 314 |                 }
 | 
|---|
 | 315 | 
 | 
|---|
| [3bbd921] | 316 |                 *result = res;
 | 
|---|
| [bf9dc4e2] | 317 |         }
 | 
|---|
| [a35b458] | 318 | 
 | 
|---|
| [bf9dc4e2] | 319 | out:
 | 
|---|
| [5bcd5b7] | 320 |         plb_clear_entry(&entry, first, len);
 | 
|---|
| [bf9dc4e2] | 321 |         return rc;
 | 
|---|
| [62da45a] | 322 | }
 | 
|---|
 | 323 | 
 | 
|---|
| [e4e546b] | 324 | /** Perform a path lookup.
 | 
|---|
 | 325 |  *
 | 
|---|
 | 326 |  * @param base    The file from which to perform the lookup.
 | 
|---|
 | 327 |  * @param path    Path to be resolved; it must be a NULL-terminated
 | 
|---|
 | 328 |  *                string.
 | 
|---|
 | 329 |  * @param lflag   Flags to be used during lookup.
 | 
|---|
 | 330 |  * @param result  Empty structure where the lookup result will be stored.
 | 
|---|
 | 331 |  *                Can be NULL.
 | 
|---|
 | 332 |  *
 | 
|---|
 | 333 |  * @return EOK on success or an error code from errno.h.
 | 
|---|
 | 334 |  *
 | 
|---|
 | 335 |  */
 | 
|---|
| [b7fd2a0] | 336 | errno_t vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
 | 
|---|
| [e4e546b] | 337 |     vfs_lookup_res_t *result)
 | 
|---|
 | 338 | {
 | 
|---|
 | 339 |         assert(base != NULL);
 | 
|---|
 | 340 |         assert(path != NULL);
 | 
|---|
| [a35b458] | 341 | 
 | 
|---|
| [e4e546b] | 342 |         size_t len;
 | 
|---|
| [b7fd2a0] | 343 |         errno_t rc;
 | 
|---|
| [e4e546b] | 344 |         char *npath = canonify(path, &len);
 | 
|---|
 | 345 |         if (!npath) {
 | 
|---|
 | 346 |                 rc = EINVAL;
 | 
|---|
 | 347 |                 return rc;
 | 
|---|
 | 348 |         }
 | 
|---|
 | 349 |         path = npath;
 | 
|---|
| [a35b458] | 350 | 
 | 
|---|
| [e4e546b] | 351 |         assert(path[0] == '/');
 | 
|---|
 | 352 | 
 | 
|---|
 | 353 |         if (lflag & (L_CREATE | L_UNLINK)) {
 | 
|---|
 | 354 | 
 | 
|---|
 | 355 |                 /*
 | 
|---|
 | 356 |                  * Creation and destruction of names must be done in two
 | 
|---|
 | 357 |                  * separate steps: lookup of the parent node and the name
 | 
|---|
 | 358 |                  * link/unlink operation itself.  Otherwise the parent
 | 
|---|
 | 359 |                  * filesystem would not be able to tell when a mountpoint is
 | 
|---|
 | 360 |                  * crossed. It would attempt to perform the link/unlink in
 | 
|---|
 | 361 |                  * itself instead of letting the mounted filesystem do it,
 | 
|---|
 | 362 |                  * resulting in wrong behavior. This is the wages of server-side
 | 
|---|
 | 363 |                  * mountpoints.
 | 
|---|
 | 364 |                  */
 | 
|---|
 | 365 | 
 | 
|---|
 | 366 |                 char *slash = str_rchr(path, L'/');
 | 
|---|
 | 367 |                 vfs_node_t *parent = base;
 | 
|---|
| [a35b458] | 368 | 
 | 
|---|
| [e4e546b] | 369 |                 if (slash != path) {
 | 
|---|
 | 370 |                         int tflag = lflag;
 | 
|---|
 | 371 |                         vfs_lookup_res_t tres;
 | 
|---|
 | 372 | 
 | 
|---|
 | 373 |                         tflag &= ~(L_CREATE | L_EXCLUSIVE | L_UNLINK | L_FILE);
 | 
|---|
 | 374 |                         tflag |= L_DIRECTORY;
 | 
|---|
 | 375 |                         rc = _vfs_lookup_internal(base, path, tflag, &tres,
 | 
|---|
 | 376 |                             slash - path);
 | 
|---|
 | 377 |                         if (rc != EOK)
 | 
|---|
 | 378 |                                 return rc;
 | 
|---|
 | 379 |                         parent = vfs_node_get(&tres);
 | 
|---|
 | 380 |                         if (!parent)
 | 
|---|
 | 381 |                                 return ENOMEM;
 | 
|---|
 | 382 |                 } else
 | 
|---|
 | 383 |                         vfs_node_addref(parent);
 | 
|---|
 | 384 | 
 | 
|---|
 | 385 |                 rc = _vfs_lookup_internal(parent, slash, lflag, result,
 | 
|---|
 | 386 |                     len - (slash - path));
 | 
|---|
 | 387 | 
 | 
|---|
 | 388 |                 vfs_node_put(parent);
 | 
|---|
 | 389 | 
 | 
|---|
 | 390 |         } else {
 | 
|---|
 | 391 |                 rc = _vfs_lookup_internal(base, path, lflag, result, len);
 | 
|---|
 | 392 |         }
 | 
|---|
| [a35b458] | 393 | 
 | 
|---|
| [e4e546b] | 394 |         return rc;
 | 
|---|
 | 395 | }
 | 
|---|
 | 396 | 
 | 
|---|
| [62da45a] | 397 | /**
 | 
|---|
 | 398 |  * @}
 | 
|---|
| [9bb85f3] | 399 |  */
 | 
|---|