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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.4 KB
Line 
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_lookup.c
35 * @brief
36 */
37
38#include "vfs.h"
39#include <macros.h>
40#include <async.h>
41#include <errno.h>
42#include <str.h>
43#include <stdarg.h>
44#include <stdbool.h>
45#include <fibril_synch.h>
46#include <adt/list.h>
47#include <vfs/canonify.h>
48#include <dirent.h>
49#include <assert.h>
50
51FIBRIL_MUTEX_INITIALIZE(plb_mutex);
52LIST_INITIALIZE(plb_entries); /**< PLB entry ring buffer. */
53uint8_t *plb = NULL;
54
55static errno_t plb_insert_entry(plb_entry_t *entry, char *path, size_t *start,
56 size_t len)
57{
58 fibril_mutex_lock(&plb_mutex);
59
60 link_initialize(&entry->plb_link);
61 entry->len = len;
62
63 size_t first; /* the first free index */
64 size_t last; /* the last free index */
65
66 if (list_empty(&plb_entries)) {
67 first = 0;
68 last = PLB_SIZE - 1;
69 } else {
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);
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 */
84 fibril_mutex_unlock(&plb_mutex);
85 return ELIMIT;
86 }
87 } else {
88 if (PLB_SIZE - ((first - last) + 1) < len) {
89 /*
90 * The buffer cannot absorb the path.
91 */
92 fibril_mutex_unlock(&plb_mutex);
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
102 entry->index = first;
103 entry->len = len;
104
105 /*
106 * Claim PLB space by inserting the entry into the PLB entry ring
107 * buffer.
108 */
109 list_append(&entry->plb_link, &plb_entries);
110
111 fibril_mutex_unlock(&plb_mutex);
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;
118
119 memcpy(&plb[first], path, cnt1);
120 memcpy(plb, &path[cnt1], cnt2);
121
122 *start = first;
123 return EOK;
124}
125
126static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
127{
128 fibril_mutex_lock(&plb_mutex);
129 list_remove(&entry->plb_link);
130 /*
131 * Erasing the path from PLB will come handy for debugging purposes.
132 */
133 size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
134 size_t cnt2 = len - cnt1;
135 memset(&plb[first], 0, cnt1);
136 memset(plb, 0, cnt2);
137 fibril_mutex_unlock(&plb_mutex);
138}
139
140errno_t vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
141{
142 assert(base != NULL);
143 assert(child != NULL);
144 assert(base->fs_handle);
145 assert(child->fs_handle);
146 assert(path != NULL);
147
148 vfs_lookup_res_t res;
149 char component[NAME_MAX + 1];
150 errno_t rc;
151
152 size_t len;
153 char *npath = canonify(path, &len);
154 if (!npath) {
155 rc = EINVAL;
156 goto out;
157 }
158 path = npath;
159
160 vfs_triplet_t *triplet;
161
162 char *slash = str_rchr(path, L'/');
163 if (slash && slash != path) {
164 if (slash[1] == 0) {
165 rc = EINVAL;
166 goto out;
167 }
168
169 memcpy(component, slash + 1, str_size(slash));
170 *slash = 0;
171
172 rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
173 if (rc != EOK)
174 goto out;
175 triplet = &res.triplet;
176
177 *slash = '/';
178 } else {
179 if (base->mount != NULL) {
180 rc = EINVAL;
181 goto out;
182 }
183
184 memcpy(component, path + 1, str_size(path));
185 triplet = (vfs_triplet_t *) base;
186 }
187
188 if (triplet->fs_handle != child->fs_handle ||
189 triplet->service_id != child->service_id) {
190 rc = EXDEV;
191 goto out;
192 }
193
194 async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
195 aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id,
196 triplet->index, child->index, NULL);
197
198 rc = async_data_write_start(exch, component, str_size(component) + 1);
199 errno_t orig_rc;
200 async_wait_for(req, &orig_rc);
201 vfs_exchange_release(exch);
202 if (orig_rc != EOK)
203 rc = orig_rc;
204
205out:
206 return rc;
207}
208
209static errno_t out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
210 int lflag, vfs_lookup_res_t *result)
211{
212 assert(base);
213 assert(result);
214
215 errno_t rc;
216 ipc_call_t answer;
217 async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
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);
221 async_wait_for(req, &rc);
222 vfs_exchange_release(exch);
223
224 if (rc != EOK)
225 return rc;
226
227 unsigned last = *pfirst + *plen;
228 *pfirst = IPC_GET_ARG3(answer) & 0xffff;
229 *plen = last - *pfirst;
230
231 result->triplet.fs_handle = (fs_handle_t) IPC_GET_ARG1(answer);
232 result->triplet.service_id = base->service_id;
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) ?
236 VFS_NODE_DIRECTORY : VFS_NODE_FILE;
237 return EOK;
238}
239
240static errno_t _vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
241 vfs_lookup_res_t *result, size_t len)
242{
243 size_t first;
244 errno_t rc;
245
246 plb_entry_t entry;
247 rc = plb_insert_entry(&entry, path, &first, len);
248 if (rc != EOK)
249 return rc;
250
251 size_t next = first;
252 size_t nlen = len;
253
254 vfs_lookup_res_t res;
255
256 /* Resolve path as long as there are mount points to cross. */
257 while (nlen > 0) {
258 while (base->mount) {
259 if (lflag & L_DISABLE_MOUNTS) {
260 rc = EXDEV;
261 goto out;
262 }
263
264 base = base->mount;
265 }
266
267 rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag,
268 &res);
269 if (rc != EOK)
270 goto out;
271
272 if (nlen > 0) {
273 base = vfs_node_peek(&res);
274 if (!base) {
275 rc = ENOENT;
276 goto out;
277 }
278 if (!base->mount) {
279 vfs_node_put(base);
280 rc = ENOENT;
281 goto out;
282 }
283 vfs_node_put(base);
284 if (lflag & L_DISABLE_MOUNTS) {
285 rc = EXDEV;
286 goto out;
287 }
288 }
289 }
290
291 assert(nlen == 0);
292 rc = EOK;
293
294 if (result != NULL) {
295 /* The found file may be a mount point. Try to cross it. */
296 if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
297 base = vfs_node_peek(&res);
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;
304 }
305
306 result->triplet = *((vfs_triplet_t *) base);
307 result->type = base->type;
308 result->size = base->size;
309 vfs_node_put(base);
310 goto out;
311 }
312 if (base)
313 vfs_node_put(base);
314 }
315
316 *result = res;
317 }
318
319out:
320 plb_clear_entry(&entry, first, len);
321 return rc;
322}
323
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 */
336errno_t vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
337 vfs_lookup_res_t *result)
338{
339 assert(base != NULL);
340 assert(path != NULL);
341
342 size_t len;
343 errno_t rc;
344 char *npath = canonify(path, &len);
345 if (!npath) {
346 rc = EINVAL;
347 return rc;
348 }
349 path = npath;
350
351 assert(path[0] == '/');
352
353
354 if (lflag & (L_CREATE | L_UNLINK)) {
355
356 /*
357 * Creation and destruction of names must be done in two
358 * separate steps: lookup of the parent node and the name
359 * link/unlink operation itself. Otherwise the parent
360 * filesystem would not be able to tell when a mountpoint is
361 * crossed. It would attempt to perform the link/unlink in
362 * itself instead of letting the mounted filesystem do it,
363 * resulting in wrong behavior. This is the wages of server-side
364 * mountpoints.
365 */
366
367 char *slash = str_rchr(path, L'/');
368 vfs_node_t *parent = base;
369
370 if (slash != path) {
371 int tflag = lflag;
372 vfs_lookup_res_t tres;
373
374 tflag &= ~(L_CREATE | L_EXCLUSIVE | L_UNLINK | L_FILE);
375 tflag |= L_DIRECTORY;
376 rc = _vfs_lookup_internal(base, path, tflag, &tres,
377 slash - path);
378 if (rc != EOK)
379 return rc;
380 parent = vfs_node_get(&tres);
381 if (!parent)
382 return ENOMEM;
383 } else
384 vfs_node_addref(parent);
385
386 rc = _vfs_lookup_internal(parent, slash, lflag, result,
387 len - (slash - path));
388
389 vfs_node_put(parent);
390
391 } else {
392 rc = _vfs_lookup_internal(base, path, lflag, result, len);
393 }
394
395 return rc;
396}
397
398/**
399 * @}
400 */
Note: See TracBrowser for help on using the repository browser.