source: mainline/uspace/srv/vfs/vfs_lookup.c

Last change on this file was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

  • Property mode set to 100644
File size: 9.4 KB
RevLine 
[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]51FIBRIL_MUTEX_INITIALIZE(plb_mutex);
[b72efe8]52LIST_INITIALIZE(plb_entries); /**< PLB entry ring buffer. */
[62da45a]53uint8_t *plb = NULL;
54
[b7fd2a0]55static 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
126static 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]140errno_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]205out:
206 return rc;
207}
[cead2aa]208
[b7fd2a0]209static 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;
[fafb8e5]228 *pfirst = ipc_get_arg3(&answer) & 0xffff;
[5bcd5b7]229 *plen = last - *pfirst;
[a35b458]230
[fafb8e5]231 result->triplet.fs_handle = (fs_handle_t) ipc_get_arg1(&answer);
[6fb8b2c]232 result->triplet.service_id = base->service_id;
[fafb8e5]233 result->triplet.index = (fs_index_t) ipc_get_arg2(&answer);
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]240static 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]319out:
[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]336errno_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 */
Note: See TracBrowser for help on using the repository browser.