source: mainline/uspace/lib/libfs/libfs.c@ 595edf5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 595edf5 was 595edf5, checked in by Martin Decky <martin@…>, 16 years ago

add libfs_open_node() helper function
cleanup

  • Property mode set to 100644
File size: 11.8 KB
Line 
1/*
2 * Copyright (c) 2009 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 libfs
30 * @{
31 */
32/**
33 * @file
34 * Glue code which is commonod to all FS implementations.
35 */
36
37#include "libfs.h"
38#include "../../srv/vfs/vfs.h"
39#include <errno.h>
40#include <async.h>
41#include <ipc/ipc.h>
42#include <as.h>
43#include <assert.h>
44#include <dirent.h>
45#include <mem.h>
46
47/** Register file system server.
48 *
49 * This function abstracts away the tedious registration protocol from
50 * file system implementations and lets them to reuse this registration glue
51 * code.
52 *
53 * @param vfs_phone Open phone for communication with VFS.
54 * @param reg File system registration structure. It will be
55 * initialized by this function.
56 * @param info VFS info structure supplied by the file system
57 * implementation.
58 * @param conn Connection fibril for handling all calls originating in
59 * VFS.
60 *
61 * @return EOK on success or a non-zero error code on errror.
62 */
63int fs_register(int vfs_phone, fs_reg_t *reg, vfs_info_t *info,
64 async_client_conn_t conn)
65{
66 /*
67 * Tell VFS that we are here and want to get registered.
68 * We use the async framework because VFS will answer the request
69 * out-of-order, when it knows that the operation succeeded or failed.
70 */
71 ipc_call_t answer;
72 aid_t req = async_send_0(vfs_phone, VFS_REGISTER, &answer);
73
74 /*
75 * Send our VFS info structure to VFS.
76 */
77 int rc = ipc_data_write_start(vfs_phone, info, sizeof(*info));
78 if (rc != EOK) {
79 async_wait_for(req, NULL);
80 return rc;
81 }
82
83 /*
84 * Ask VFS for callback connection.
85 */
86 ipc_connect_to_me(vfs_phone, 0, 0, 0, &reg->vfs_phonehash);
87
88 /*
89 * Allocate piece of address space for PLB.
90 */
91 reg->plb_ro = as_get_mappable_page(PLB_SIZE);
92 if (!reg->plb_ro) {
93 async_wait_for(req, NULL);
94 return ENOMEM;
95 }
96
97 /*
98 * Request sharing the Path Lookup Buffer with VFS.
99 */
100 rc = ipc_share_in_start_0_0(vfs_phone, reg->plb_ro, PLB_SIZE);
101 if (rc) {
102 async_wait_for(req, NULL);
103 return rc;
104 }
105
106 /*
107 * Pick up the answer for the request to the VFS_REQUEST call.
108 */
109 async_wait_for(req, NULL);
110 reg->fs_handle = (int) IPC_GET_ARG1(answer);
111
112 /*
113 * Create a connection fibril to handle the callback connection.
114 */
115 async_new_connection(reg->vfs_phonehash, 0, NULL, conn);
116
117 /*
118 * Tell the async framework that other connections are to be handled by
119 * the same connection fibril as well.
120 */
121 async_set_client_connection(conn);
122
123 return IPC_GET_RETVAL(answer);
124}
125
126void fs_node_initialize(fs_node_t *fn)
127{
128 memset(fn, 0, sizeof(fs_node_t));
129}
130
131void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
132 ipc_call_t *request)
133{
134 dev_handle_t mp_dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
135 fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*request);
136 fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request);
137 dev_handle_t mr_dev_handle = (dev_handle_t) IPC_GET_ARG4(*request);
138 int res;
139 ipcarg_t rc;
140
141 ipc_call_t call;
142 ipc_callid_t callid;
143
144 /* accept the phone */
145 callid = async_get_call(&call);
146 int mountee_phone = (int)IPC_GET_ARG1(call);
147 if ((IPC_GET_METHOD(call) != IPC_M_CONNECTION_CLONE) ||
148 mountee_phone < 0) {
149 ipc_answer_0(callid, EINVAL);
150 ipc_answer_0(rid, EINVAL);
151 return;
152 }
153 ipc_answer_0(callid, EOK); /* acknowledge the mountee_phone */
154
155 res = ipc_data_write_receive(&callid, NULL);
156 if (!res) {
157 ipc_hangup(mountee_phone);
158 ipc_answer_0(callid, EINVAL);
159 ipc_answer_0(rid, EINVAL);
160 return;
161 }
162
163 fs_node_t *fn = ops->node_get(mp_dev_handle, mp_fs_index);
164 if (!fn) {
165 ipc_hangup(mountee_phone);
166 ipc_answer_0(callid, ENOENT);
167 ipc_answer_0(rid, ENOENT);
168 return;
169 }
170
171 if (fn->mp_data.mp_active) {
172 ipc_hangup(mountee_phone);
173 ops->node_put(fn);
174 ipc_answer_0(callid, EBUSY);
175 ipc_answer_0(rid, EBUSY);
176 return;
177 }
178
179 rc = async_req_0_0(mountee_phone, IPC_M_CONNECT_ME);
180 if (rc != 0) {
181 ipc_hangup(mountee_phone);
182 ops->node_put(fn);
183 ipc_answer_0(callid, rc);
184 ipc_answer_0(rid, rc);
185 return;
186 }
187
188 ipc_call_t answer;
189 aid_t msg = async_send_1(mountee_phone, VFS_MOUNTED, mr_dev_handle,
190 &answer);
191 ipc_forward_fast(callid, mountee_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
192 async_wait_for(msg, &rc);
193
194 if (rc == EOK) {
195 fn->mp_data.mp_active = true;
196 fn->mp_data.fs_handle = mr_fs_handle;
197 fn->mp_data.dev_handle = mr_dev_handle;
198 fn->mp_data.phone = mountee_phone;
199 }
200 /*
201 * Do not release the FS node so that it stays in memory.
202 */
203 ipc_answer_3(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
204 IPC_GET_ARG3(answer));
205}
206
207/** Lookup VFS triplet by name in the file system name space.
208 *
209 * The path passed in the PLB must be in the canonical file system path format
210 * as returned by the canonify() function.
211 *
212 * @param ops libfs operations structure with function pointers to
213 * file system implementation
214 * @param fs_handle File system handle of the file system where to perform
215 * the lookup.
216 * @param rid Request ID of the VFS_LOOKUP request.
217 * @param request VFS_LOOKUP request data itself.
218 *
219 */
220void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
221 ipc_call_t *request)
222{
223 unsigned first = IPC_GET_ARG1(*request);
224 unsigned last = IPC_GET_ARG2(*request);
225 unsigned next = first;
226 dev_handle_t dev_handle = IPC_GET_ARG3(*request);
227 int lflag = IPC_GET_ARG4(*request);
228 fs_index_t index = IPC_GET_ARG5(*request); /* when L_LINK specified */
229 char component[NAME_MAX + 1];
230 int len;
231
232 if (last < next)
233 last += PLB_SIZE;
234
235 fs_node_t *par = NULL;
236 fs_node_t *cur = ops->root_get(dev_handle);
237 fs_node_t *tmp = NULL;
238
239 if (cur->mp_data.mp_active) {
240 ipc_forward_slow(rid, cur->mp_data.phone, VFS_LOOKUP,
241 next, last, cur->mp_data.dev_handle, lflag, index,
242 IPC_FF_ROUTE_FROM_ME);
243 ops->node_put(cur);
244 return;
245 }
246
247 if (ops->plb_get_char(next) == '/')
248 next++; /* eat slash */
249
250 while (next <= last && ops->has_children(cur)) {
251 /* collect the component */
252 len = 0;
253 while ((next <= last) && (ops->plb_get_char(next) != '/')) {
254 if (len + 1 == NAME_MAX) {
255 /* component length overflow */
256 ipc_answer_0(rid, ENAMETOOLONG);
257 goto out;
258 }
259 component[len++] = ops->plb_get_char(next);
260 next++; /* process next character */
261 }
262
263 assert(len);
264 component[len] = '\0';
265 next++; /* eat slash */
266
267 /* match the component */
268 tmp = ops->match(cur, component);
269 if (tmp && tmp->mp_data.mp_active) {
270 if (next > last)
271 next = last = first;
272 else
273 next--;
274
275 ipc_forward_slow(rid, tmp->mp_data.phone, VFS_LOOKUP,
276 next, last, tmp->mp_data.dev_handle, lflag, index,
277 IPC_FF_ROUTE_FROM_ME);
278 ops->node_put(cur);
279 ops->node_put(tmp);
280 if (par)
281 ops->node_put(par);
282 return;
283 }
284
285 /* handle miss: match amongst siblings */
286 if (!tmp) {
287 if (next <= last) {
288 /* there are unprocessed components */
289 ipc_answer_0(rid, ENOENT);
290 goto out;
291 }
292 /* miss in the last component */
293 if (lflag & (L_CREATE | L_LINK)) {
294 /* request to create a new link */
295 if (!ops->is_directory(cur)) {
296 ipc_answer_0(rid, ENOTDIR);
297 goto out;
298 }
299 fs_node_t *fn;
300 if (lflag & L_CREATE)
301 fn = ops->create(dev_handle, lflag);
302 else
303 fn = ops->node_get(dev_handle,
304 index);
305 if (fn) {
306 int rc;
307
308 rc = ops->link(cur, fn, component);
309 if (rc != EOK) {
310 if (lflag & L_CREATE) {
311 (void)ops->destroy(fn);
312 }
313 ipc_answer_0(rid, rc);
314 } else {
315 ipc_answer_5(rid, EOK,
316 fs_handle, dev_handle,
317 ops->index_get(fn),
318 ops->size_get(fn),
319 ops->lnkcnt_get(fn));
320 ops->node_put(fn);
321 }
322 } else {
323 ipc_answer_0(rid, ENOSPC);
324 }
325 goto out;
326 }
327 ipc_answer_0(rid, ENOENT);
328 goto out;
329 }
330
331 if (par)
332 ops->node_put(par);
333
334 /* descend one level */
335 par = cur;
336 cur = tmp;
337 tmp = NULL;
338 }
339
340 /* handle miss: excessive components */
341 if (next <= last && !ops->has_children(cur)) {
342 if (lflag & (L_CREATE | L_LINK)) {
343 if (!ops->is_directory(cur)) {
344 ipc_answer_0(rid, ENOTDIR);
345 goto out;
346 }
347
348 /* collect next component */
349 len = 0;
350 while (next <= last) {
351 if (ops->plb_get_char(next) == '/') {
352 /* more than one component */
353 ipc_answer_0(rid, ENOENT);
354 goto out;
355 }
356 if (len + 1 == NAME_MAX) {
357 /* component length overflow */
358 ipc_answer_0(rid, ENAMETOOLONG);
359 goto out;
360 }
361 component[len++] = ops->plb_get_char(next);
362 next++; /* process next character */
363 }
364 assert(len);
365 component[len] = '\0';
366
367 fs_node_t *fn;
368 if (lflag & L_CREATE)
369 fn = ops->create(dev_handle, lflag);
370 else
371 fn = ops->node_get(dev_handle, index);
372 if (fn) {
373 int rc;
374
375 rc = ops->link(cur, fn, component);
376 if (rc != EOK) {
377 if (lflag & L_CREATE)
378 (void)ops->destroy(fn);
379 ipc_answer_0(rid, rc);
380 } else {
381 ipc_answer_5(rid, EOK,
382 fs_handle, dev_handle,
383 ops->index_get(fn),
384 ops->size_get(fn),
385 ops->lnkcnt_get(fn));
386 ops->node_put(fn);
387 }
388 } else {
389 ipc_answer_0(rid, ENOSPC);
390 }
391 goto out;
392 }
393 ipc_answer_0(rid, ENOENT);
394 goto out;
395 }
396
397 /* handle hit */
398 if (lflag & L_UNLINK) {
399 unsigned old_lnkcnt = ops->lnkcnt_get(cur);
400 int res = ops->unlink(par, cur, component);
401 ipc_answer_5(rid, (ipcarg_t)res, fs_handle, dev_handle,
402 ops->index_get(cur), ops->size_get(cur), old_lnkcnt);
403 goto out;
404 }
405 if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
406 (lflag & L_LINK)) {
407 ipc_answer_0(rid, EEXIST);
408 goto out;
409 }
410 if ((lflag & L_FILE) && (ops->is_directory(cur))) {
411 ipc_answer_0(rid, EISDIR);
412 goto out;
413 }
414 if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
415 ipc_answer_0(rid, ENOTDIR);
416 goto out;
417 }
418
419 ipc_answer_5(rid, EOK, fs_handle, dev_handle, ops->index_get(cur),
420 ops->size_get(cur), ops->lnkcnt_get(cur));
421
422out:
423 if (par)
424 ops->node_put(par);
425 if (cur)
426 ops->node_put(cur);
427 if (tmp)
428 ops->node_put(tmp);
429}
430
431/** Open VFS triplet.
432 *
433 * @param ops libfs operations structure with function pointers to
434 * file system implementation
435 * @param rid Request ID of the VFS_OPEN_NODE request.
436 * @param request VFS_OPEN_NODE request data itself.
437 *
438 */
439void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
440 ipc_call_t *request)
441{
442 dev_handle_t dev_handle = IPC_GET_ARG1(*request);
443 fs_index_t index = IPC_GET_ARG2(*request);
444
445 fs_node_t *node = ops->node_get(dev_handle, index);
446
447 if (node == NULL) {
448 ipc_answer_0(rid, ENOENT);
449 return;
450 }
451
452 ipc_answer_5(rid, EOK, fs_handle, dev_handle, index,
453 ops->size_get(node), ops->lnkcnt_get(node));
454
455 ops->node_put(node);
456}
457
458/** @}
459 */
Note: See TracBrowser for help on using the repository browser.