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

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

Get rid of custom _strrchr in favor of str_rchr

  • Property mode set to 100644
File size: 8.5 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
51#define DPRINTF(...)
52
53#define min(a, b) ((a) < (b) ? (a) : (b))
54
55FIBRIL_MUTEX_INITIALIZE(plb_mutex);
56LIST_INITIALIZE(plb_entries); /**< PLB entry ring buffer. */
57uint8_t *plb = NULL;
58
59static int plb_insert_entry(plb_entry_t *entry, char *path, size_t *start, size_t len)
60{
61 fibril_mutex_lock(&plb_mutex);
62
63 link_initialize(&entry->plb_link);
64 entry->len = len;
65
66 size_t first; /* the first free index */
67 size_t last; /* the last free index */
68
69 if (list_empty(&plb_entries)) {
70 first = 0;
71 last = PLB_SIZE - 1;
72 } else {
73 plb_entry_t *oldest = list_get_instance(
74 list_first(&plb_entries), plb_entry_t, plb_link);
75 plb_entry_t *newest = list_get_instance(
76 list_last(&plb_entries), plb_entry_t, plb_link);
77
78 first = (newest->index + newest->len) % PLB_SIZE;
79 last = (oldest->index - 1) % PLB_SIZE;
80 }
81
82 if (first <= last) {
83 if ((last - first) + 1 < len) {
84 /*
85 * The buffer cannot absorb the path.
86 */
87 fibril_mutex_unlock(&plb_mutex);
88 return ELIMIT;
89 }
90 } else {
91 if (PLB_SIZE - ((first - last) + 1) < len) {
92 /*
93 * The buffer cannot absorb the path.
94 */
95 fibril_mutex_unlock(&plb_mutex);
96 return ELIMIT;
97 }
98 }
99
100 /*
101 * We know the first free index in PLB and we also know that there is
102 * enough space in the buffer to hold our path.
103 */
104
105 entry->index = first;
106 entry->len = len;
107
108 /*
109 * Claim PLB space by inserting the entry into the PLB entry ring
110 * buffer.
111 */
112 list_append(&entry->plb_link, &plb_entries);
113
114 fibril_mutex_unlock(&plb_mutex);
115
116 /*
117 * Copy the path into PLB.
118 */
119 size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
120 size_t cnt2 = len - cnt1;
121
122 memcpy(&plb[first], path, cnt1);
123 memcpy(plb, &path[cnt1], cnt2);
124
125 *start = first;
126 return EOK;
127}
128
129static void plb_clear_entry(plb_entry_t *entry, size_t first, size_t len)
130{
131 fibril_mutex_lock(&plb_mutex);
132 list_remove(&entry->plb_link);
133 /*
134 * Erasing the path from PLB will come handy for debugging purposes.
135 */
136 size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
137 size_t cnt2 = len - cnt1;
138 memset(&plb[first], 0, cnt1);
139 memset(plb, 0, cnt2);
140 fibril_mutex_unlock(&plb_mutex);
141}
142
143int vfs_link_internal(vfs_node_t *base, char *path, vfs_triplet_t *child)
144{
145 assert(base != NULL);
146 assert(child != NULL);
147 assert(base->fs_handle);
148 assert(child->fs_handle);
149 assert(path != NULL);
150
151 vfs_lookup_res_t res;
152 char component[NAME_MAX + 1];
153 int rc;
154
155 size_t len;
156 char *npath = canonify(path, &len);
157 if (!npath) {
158 rc = EINVAL;
159 goto out;
160 }
161 path = npath;
162
163 vfs_triplet_t *triplet;
164
165 char *slash = str_rchr(path, L'/');
166 if (slash && slash != path) {
167 if (slash[1] == 0) {
168 rc = EINVAL;
169 goto out;
170 }
171
172 memcpy(component, slash + 1, str_size(slash));
173 *slash = 0;
174
175 rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
176 if (rc != EOK) {
177 goto out;
178 }
179 triplet = &res.triplet;
180
181 *slash = '/';
182 } else {
183 if (base->mount != NULL) {
184 rc = EINVAL;
185 goto out;
186 }
187
188 memcpy(component, path + 1, str_size(path));
189 triplet = (vfs_triplet_t *) base;
190 }
191
192 if (triplet->fs_handle != child->fs_handle || triplet->service_id != child->service_id) {
193 rc = EXDEV;
194 goto out;
195 }
196
197 async_exch_t *exch = vfs_exchange_grab(triplet->fs_handle);
198 aid_t req = async_send_3(exch, VFS_OUT_LINK, triplet->service_id, triplet->index, child->index, NULL);
199
200 rc = async_data_write_start(exch, component, str_size(component) + 1);
201 sysarg_t orig_rc;
202 async_wait_for(req, &orig_rc);
203 vfs_exchange_release(exch);
204 if (orig_rc != EOK) {
205 rc = orig_rc;
206 }
207
208out:
209 DPRINTF("vfs_link_internal() with path '%s' returns %d\n", path, rc);
210 return rc;
211}
212
213static int out_lookup(vfs_triplet_t *base, size_t *pfirst, size_t *plen,
214 int lflag, vfs_lookup_res_t *result)
215{
216 assert(base);
217 assert(result);
218
219 sysarg_t rc;
220 ipc_call_t answer;
221 async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
222 aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) *pfirst, (sysarg_t) *plen,
223 (sysarg_t) base->service_id, (sysarg_t) base->index, (sysarg_t) lflag, &answer);
224 async_wait_for(req, &rc);
225 vfs_exchange_release(exch);
226
227 if ((int) rc < 0) {
228 return (int) rc;
229 }
230
231 unsigned last = *pfirst + *plen;
232 *pfirst = IPC_GET_ARG3(answer);
233 *plen = last - *pfirst;
234
235 result->triplet.fs_handle = (fs_handle_t) rc;
236 result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
237 result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
238 result->size = (int64_t)(int32_t) IPC_GET_ARG4(answer);
239 result->type = IPC_GET_ARG5(answer) ? VFS_NODE_DIRECTORY : VFS_NODE_FILE;
240 return EOK;
241}
242
243/** Perform a path lookup.
244 *
245 * @param base The file from which to perform the lookup.
246 * @param path Path to be resolved; it must be a NULL-terminated
247 * string.
248 * @param lflag Flags to be used during lookup.
249 * @param result Empty structure where the lookup result will be stored.
250 * Can be NULL.
251 *
252 * @return EOK on success or an error code from errno.h.
253 *
254 */
255int vfs_lookup_internal(vfs_node_t *base, char *path, int lflag, vfs_lookup_res_t *result)
256{
257 assert(base != NULL);
258 assert(path != NULL);
259
260 size_t len;
261 int rc;
262 char *npath = canonify(path, &len);
263 if (!npath) {
264 DPRINTF("vfs_lookup_internal() can't canonify path: %s\n", path);
265 rc = EINVAL;
266 return rc;
267 }
268 path = npath;
269
270 assert(path[0] == '/');
271
272 size_t first;
273
274 plb_entry_t entry;
275 rc = plb_insert_entry(&entry, path, &first, len);
276 if (rc != EOK) {
277 DPRINTF("vfs_lookup_internal() can't insert entry into PLB: %d\n", rc);
278 return rc;
279 }
280
281 size_t next = first;
282 size_t nlen = len;
283
284 vfs_lookup_res_t res;
285
286 /* Resolve path as long as there are mount points to cross. */
287 while (nlen > 0) {
288 while (base->mount != NULL) {
289 if (lflag & L_DISABLE_MOUNTS) {
290 rc = EXDEV;
291 goto out;
292 }
293
294 base = base->mount;
295 }
296
297 rc = out_lookup((vfs_triplet_t *) base, &next, &nlen, lflag, &res);
298 if (rc != EOK) {
299 goto out;
300 }
301
302 if (nlen > 0) {
303 base = vfs_node_peek(&res);
304 if (!base) {
305 rc = ENOENT;
306 goto out;
307 }
308 if (!base->mount) {
309 vfs_node_put(base);
310 rc = ENOENT;
311 goto out;
312 }
313 vfs_node_put(base);
314 if (lflag & L_DISABLE_MOUNTS) {
315 rc = EXDEV;
316 goto out;
317 }
318 }
319 }
320
321 assert(nlen == 0);
322 rc = EOK;
323
324 if (result != NULL) {
325 /* The found file may be a mount point. Try to cross it. */
326 if (!(lflag & (L_MP | L_DISABLE_MOUNTS))) {
327 base = vfs_node_peek(&res);
328 if (base && base->mount) {
329 while (base->mount) {
330 vfs_node_addref(base->mount);
331 vfs_node_t *nbase = base->mount;
332 vfs_node_put(base);
333 base = nbase;
334 }
335
336 result->triplet = *((vfs_triplet_t *) base);
337 result->type = base->type;
338 result->size = base->size;
339 vfs_node_put(base);
340 goto out;
341 }
342 if (base)
343 vfs_node_put(base);
344 }
345
346 memcpy(result, &res, sizeof(vfs_lookup_res_t));
347 }
348
349out:
350 plb_clear_entry(&entry, first, len);
351 DPRINTF("vfs_lookup_internal() with path '%s' returns %d\n", path, rc);
352 return rc;
353}
354
355/**
356 * @}
357 */
Note: See TracBrowser for help on using the repository browser.