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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b7c62a9 was b7c62a9, checked in by Jiri Zarevucky <zarevucky.jiri@…>, 12 years ago

Make the server oblivious to the link count. It is just another source of potential problems. Also clean up some confusion with file types and node refcount.

  • Property mode set to 100644
File size: 6.9 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
143static char *_strrchr(char *path, int c)
144{
145 char *res = NULL;
146 while (*path != 0) {
147 if (*path == c) {
148 res = path;
149 }
150 path++;
151 }
152 return res;
153}
154
155int vfs_link_internal(vfs_triplet_t *base, char *path, vfs_triplet_t *child)
156{
157 assert(base != NULL);
158 assert(child != NULL);
159 assert(base->fs_handle);
160 assert(child->fs_handle);
161 assert(path != NULL);
162
163 vfs_lookup_res_t res;
164 char component[NAME_MAX + 1];
165 int rc;
166
167 size_t len;
168 char *npath = canonify(path, &len);
169 if (!npath) {
170 rc = EINVAL;
171 goto out;
172 }
173 path = npath;
174
175 char *slash = _strrchr(path, '/');
176 if (slash && slash != path) {
177 if (slash[1] == 0) {
178 rc = EINVAL;
179 goto out;
180 }
181
182 memcpy(component, slash + 1, str_size(slash));
183 *slash = 0;
184
185 rc = vfs_lookup_internal(base, path, L_DIRECTORY, &res);
186 if (rc != EOK) {
187 goto out;
188 }
189 base = &res.triplet;
190
191 *slash = '/';
192 } else {
193 memcpy(component, path + 1, str_size(path));
194 }
195
196 if (base->fs_handle != child->fs_handle || base->service_id != child->service_id) {
197 rc = EXDEV;
198 goto out;
199 }
200
201 async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
202 aid_t req = async_send_3(exch, VFS_OUT_LINK, base->service_id, base->index, child->index, NULL);
203
204 rc = async_data_write_start(exch, component, str_size(component) + 1);
205 sysarg_t orig_rc;
206 async_wait_for(req, &orig_rc);
207 vfs_exchange_release(exch);
208 if (orig_rc != EOK) {
209 rc = orig_rc;
210 }
211
212out:
213 DPRINTF("vfs_link_internal() with path '%s' returns %d\n", path, rc);
214 return rc;
215}
216
217/** Perform a path lookup.
218 *
219 * @param base The file from which to perform the lookup.
220 * @param path Path to be resolved; it must be a NULL-terminated
221 * string.
222 * @param lflag Flags to be used during lookup.
223 * @param result Empty structure where the lookup result will be stored.
224 * Can be NULL.
225 *
226 * @return EOK on success or an error code from errno.h.
227 *
228 */
229int vfs_lookup_internal(vfs_triplet_t *base, char *path, int lflag, vfs_lookup_res_t *result)
230{
231 assert(base != NULL);
232 assert(path != NULL);
233
234 sysarg_t rc;
235
236 if (!base->fs_handle) {
237 rc = ENOENT;
238 goto out;
239 }
240
241 size_t len;
242 char *npath = canonify(path, &len);
243 if (!npath) {
244 rc = EINVAL;
245 goto out;
246 }
247 path = npath;
248
249 assert(path[0] == '/');
250
251 size_t first;
252
253 plb_entry_t entry;
254 rc = plb_insert_entry(&entry, path, &first, len);
255 if (rc != EOK) {
256 goto out;
257 }
258
259 ipc_call_t answer;
260 async_exch_t *exch = vfs_exchange_grab(base->fs_handle);
261 aid_t req = async_send_5(exch, VFS_OUT_LOOKUP, (sysarg_t) first, (sysarg_t) len,
262 (sysarg_t) base->service_id, (sysarg_t) base->index, (sysarg_t) lflag, &answer);
263 async_wait_for(req, &rc);
264 vfs_exchange_release(exch);
265
266 plb_clear_entry(&entry, first, len);
267
268 if ((int) rc < 0) {
269 goto out;
270 }
271
272 if (!result) {
273 rc = EOK;
274 goto out;
275 }
276
277 result->triplet.fs_handle = (fs_handle_t) rc;
278 result->triplet.service_id = (service_id_t) IPC_GET_ARG1(answer);
279 result->triplet.index = (fs_index_t) IPC_GET_ARG2(answer);
280 result->size =
281 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(answer), IPC_GET_ARG4(answer));
282 result->type = IPC_GET_ARG5(answer);
283 rc = EOK;
284
285out:
286 DPRINTF("vfs_lookup_internal() with path '%s' returns %d\n", path, rc);
287 return rc;
288}
289
290/**
291 * @}
292 */
Note: See TracBrowser for help on using the repository browser.