source: mainline/uspace/lib/libfs/libfs.c@ 16d17ca

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

Add fs_handle argument to libfs_mount() needed to recognize homogenous mounts.

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