source: mainline/uspace/srv/vfs/vfs_lookup.c@ 61042de

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 61042de was 61042de, checked in by Jakub Jermar <jakub@…>, 8 years ago

Cstyle and clutter removal

  • Property mode set to 100644
File size: 8.2 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 int 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
140int 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 int 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 sysarg_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 int 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 sysarg_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 ((int) rc < 0)
225 return (int) rc;
226
227 unsigned last = *pfirst + *plen;
228 *pfirst = IPC_GET_ARG3(answer);
229 *plen = last - *pfirst;
230
231 result->triplet.fs_handle = (fs_handle_t) rc;
232 result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
233 result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
234 result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer);
235 result->type = IPC_GET_ARG5(answer) ?
236 VFS_NODE_DIRECTORY : VFS_NODE_FILE;
237 return EOK;
238}
239
240/** Perform a path lookup.
241 *
242 * @param base The file from which to perform the lookup.
243 * @param path Path to be resolved; it must be a NULL-terminated
244 * string.
245 * @param lflag Flags to be used during lookup.
246 * @param result Empty structure where the lookup result will be stored.
247 * Can be NULL.
248 *
249 * @return EOK on success or an error code from errno.h.
250 *
251 */
252int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag,
253 vfs_lookup_res_t *result)
254{
255 assert(base != NULL);
256 assert(path != NULL);
257
258 size_t len;
259 int rc;
260 char *npath = canonify(path, &len);
261 if (!npath) {
262 rc = EINVAL;
263 return rc;
264 }
265 path = npath;
266
267 assert(path[0] == '/');
268
269 size_t first;
270
271 plb_entry_t entry;
272 rc = plb_insert_entry(&entry, path, &first, len);
273 if (rc != EOK)
274 return rc;
275
276 size_t next = first;
277 size_t nlen = len;
278
279 vfs_lookup_res_t res;
280
281 /* Resolve path as long as there are mount points to cross. */
282 while (nlen > 0) {
283 while (base->mount) {
284 if (lflag & L_DISABLE_MOUNTS) {
285 rc = EXDEV;
286 goto out;
287 }
288
289 base = base->mount;
290 }
291
292 rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag,
293 &res);
294 if (rc != EOK)
295 goto out;
296
297 if (nlen > 0) {
298 base = vfs_node_peek(&res);
299 if (!base) {
300 rc = ENOENT;
301 goto out;
302 }
303 if (!base->mount) {
304 vfs_node_put(base);
305 rc = ENOENT;
306 goto out;
307 }
308 vfs_node_put(base);
309 if (lflag & L_DISABLE_MOUNTS) {
310 rc = EXDEV;
311 goto out;
312 }
313 }
314 }
315
316 assert(nlen == 0);
317 rc = EOK;
318
319 if (result != NULL) {
320 /* The found file may be a mount point. Try to cross it. */
321 if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
322 base = vfs_node_peek(&res);
323 if (base && base->mount) {
324 while (base->mount) {
325 vfs_node_addref(base->mount);
326 vfs_node_t *nbase = base->mount;
327 vfs_node_put(base);
328 base = nbase;
329 }
330
331 result->triplet = *((vfs_triplet_t *) base);
332 result->type = base->type;
333 result->size = base->size;
334 vfs_node_put(base);
335 goto out;
336 }
337 if (base)
338 vfs_node_put(base);
339 }
340
341 memcpy(result, &res, sizeof(vfs_lookup_res_t));
342 }
343
344out:
345 plb_clear_entry(&entry, first, len);
346 return rc;
347}
348
349/**
350 * @}
351 */
Note: See TracBrowser for help on using the repository browser.