source: mainline/uspace/lib/libfs/libfs.c@ c544c5d

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

Stop using fixed size BLOCK_SIZE in the ramdisk task and allow each client to negotiate its own
maximum block size. Allow the individual transfers to use block sizes smaller and equal to the
negotiated maximum block size.

  • Property mode set to 100644
File size: 10.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 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 "../../srv/rd/rd.h"
40#include <errno.h>
41#include <async.h>
42#include <ipc/ipc.h>
43#include <as.h>
44#include <assert.h>
45#include <dirent.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
126/** Lookup VFS triplet by name in the file system name space.
127 *
128 * The path passed in the PLB must be in the canonical file system path format
129 * as returned by the canonify() function.
130 *
131 * @param ops libfs operations structure with function pointers to
132 * file system implementation
133 * @param fs_handle File system handle of the file system where to perform
134 * the lookup.
135 * @param rid Request ID of the VFS_LOOKUP request.
136 * @param request VFS_LOOKUP request data itself.
137 */
138void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
139 ipc_call_t *request)
140{
141 unsigned next = IPC_GET_ARG1(*request);
142 unsigned last = IPC_GET_ARG2(*request);
143 dev_handle_t dev_handle = IPC_GET_ARG3(*request);
144 int lflag = IPC_GET_ARG4(*request);
145 fs_index_t index = IPC_GET_ARG5(*request); /* when L_LINK specified */
146 char component[NAME_MAX + 1];
147 int len;
148
149 if (last < next)
150 last += PLB_SIZE;
151
152 void *par = NULL;
153 void *cur = ops->root_get(dev_handle);
154 void *tmp = NULL;
155
156 if (ops->plb_get_char(next) == '/')
157 next++; /* eat slash */
158
159 while (next <= last && ops->has_children(cur)) {
160 /* collect the component */
161 len = 0;
162 while ((next <= last) && (ops->plb_get_char(next) != '/')) {
163 if (len + 1 == NAME_MAX) {
164 /* component length overflow */
165 ipc_answer_0(rid, ENAMETOOLONG);
166 goto out;
167 }
168 component[len++] = ops->plb_get_char(next);
169 next++; /* process next character */
170 }
171
172 assert(len);
173 component[len] = '\0';
174 next++; /* eat slash */
175
176 /* match the component */
177 tmp = ops->match(cur, component);
178
179 /* handle miss: match amongst siblings */
180 if (!tmp) {
181 if (next <= last) {
182 /* there are unprocessed components */
183 ipc_answer_0(rid, ENOENT);
184 goto out;
185 }
186 /* miss in the last component */
187 if (lflag & (L_CREATE | L_LINK)) {
188 /* request to create a new link */
189 if (!ops->is_directory(cur)) {
190 ipc_answer_0(rid, ENOTDIR);
191 goto out;
192 }
193 void *nodep;
194 if (lflag & L_CREATE)
195 nodep = ops->create(lflag);
196 else
197 nodep = ops->node_get(dev_handle,
198 index);
199 if (nodep) {
200 if (!ops->link(cur, nodep, component)) {
201 if (lflag & L_CREATE) {
202 (void)ops->destroy(
203 nodep);
204 }
205 ipc_answer_0(rid, ENOSPC);
206 } else {
207 ipc_answer_5(rid, EOK,
208 fs_handle, dev_handle,
209 ops->index_get(nodep),
210 ops->size_get(nodep),
211 ops->lnkcnt_get(nodep));
212 ops->node_put(nodep);
213 }
214 } else {
215 ipc_answer_0(rid, ENOSPC);
216 }
217 goto out;
218 } else if (lflag & L_PARENT) {
219 /* return parent */
220 ipc_answer_5(rid, EOK, fs_handle, dev_handle,
221 ops->index_get(cur), ops->size_get(cur),
222 ops->lnkcnt_get(cur));
223 }
224 ipc_answer_0(rid, ENOENT);
225 goto out;
226 }
227
228 if (par)
229 ops->node_put(par);
230
231 /* descend one level */
232 par = cur;
233 cur = tmp;
234 tmp = NULL;
235 }
236
237 /* handle miss: excessive components */
238 if (next <= last && !ops->has_children(cur)) {
239 if (lflag & (L_CREATE | L_LINK)) {
240 if (!ops->is_directory(cur)) {
241 ipc_answer_0(rid, ENOTDIR);
242 goto out;
243 }
244
245 /* collect next component */
246 len = 0;
247 while (next <= last) {
248 if (ops->plb_get_char(next) == '/') {
249 /* more than one component */
250 ipc_answer_0(rid, ENOENT);
251 goto out;
252 }
253 if (len + 1 == NAME_MAX) {
254 /* component length overflow */
255 ipc_answer_0(rid, ENAMETOOLONG);
256 goto out;
257 }
258 component[len++] = ops->plb_get_char(next);
259 next++; /* process next character */
260 }
261 assert(len);
262 component[len] = '\0';
263
264 void *nodep;
265 if (lflag & L_CREATE)
266 nodep = ops->create(lflag);
267 else
268 nodep = ops->node_get(dev_handle, index);
269 if (nodep) {
270 if (!ops->link(cur, nodep, component)) {
271 if (lflag & L_CREATE)
272 (void)ops->destroy(nodep);
273 ipc_answer_0(rid, ENOSPC);
274 } else {
275 ipc_answer_5(rid, EOK,
276 fs_handle, dev_handle,
277 ops->index_get(nodep),
278 ops->size_get(nodep),
279 ops->lnkcnt_get(nodep));
280 ops->node_put(nodep);
281 }
282 } else {
283 ipc_answer_0(rid, ENOSPC);
284 }
285 goto out;
286 }
287 ipc_answer_0(rid, ENOENT);
288 goto out;
289 }
290
291 /* handle hit */
292 if (lflag & L_PARENT) {
293 ops->node_put(cur);
294 cur = par;
295 par = NULL;
296 if (!cur) {
297 ipc_answer_0(rid, ENOENT);
298 goto out;
299 }
300 }
301 if (lflag & L_UNLINK) {
302 unsigned old_lnkcnt = ops->lnkcnt_get(cur);
303 int res = ops->unlink(par, cur);
304 ipc_answer_5(rid, (ipcarg_t)res, fs_handle, dev_handle,
305 ops->index_get(cur), ops->size_get(cur), old_lnkcnt);
306 goto out;
307 }
308 if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
309 (lflag & L_LINK)) {
310 ipc_answer_0(rid, EEXIST);
311 goto out;
312 }
313 if ((lflag & L_FILE) && (ops->is_directory(cur))) {
314 ipc_answer_0(rid, EISDIR);
315 goto out;
316 }
317 if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
318 ipc_answer_0(rid, ENOTDIR);
319 goto out;
320 }
321
322 ipc_answer_5(rid, EOK, fs_handle, dev_handle, ops->index_get(cur),
323 ops->size_get(cur), ops->lnkcnt_get(cur));
324
325out:
326 if (par)
327 ops->node_put(par);
328 if (cur)
329 ops->node_put(cur);
330 if (tmp)
331 ops->node_put(tmp);
332}
333
334/** Read data from a block device.
335 *
336 * @param phone Phone to be used to communicate with the device.
337 * @param buffer Communication buffer shared with the device.
338 * @param bufpos Pointer to the first unread valid offset within the
339 * communication buffer.
340 * @param buflen Pointer to the number of unread bytes that are ready in
341 * the communication buffer.
342 * @param pos Device position to be read.
343 * @param dst Destination buffer.
344 * @param size Size of the destination buffer.
345 * @param block_size Block size to be used for the transfer.
346 *
347 * @return True on success, false on failure.
348 */
349bool libfs_blockread(int phone, void *buffer, off_t *bufpos, size_t *buflen,
350 off_t *pos, void *dst, size_t size, size_t block_size)
351{
352 off_t offset = 0;
353 size_t left = size;
354
355 while (left > 0) {
356 size_t rd;
357
358 if (*bufpos + left < *buflen)
359 rd = left;
360 else
361 rd = *buflen - *bufpos;
362
363 if (rd > 0) {
364 /*
365 * Copy the contents of the communication buffer to the
366 * destination buffer.
367 */
368 memcpy(dst + offset, buffer + *bufpos, rd);
369 offset += rd;
370 *bufpos += rd;
371 *pos += rd;
372 left -= rd;
373 }
374
375 if (*bufpos == *buflen) {
376 /* Refill the communication buffer with a new block. */
377 ipcarg_t retval;
378 int rc = async_req_2_1(phone, RD_READ_BLOCK,
379 *pos / block_size, block_size, &retval);
380 if ((rc != EOK) || (retval != EOK))
381 return false;
382
383 *bufpos = 0;
384 *buflen = block_size;
385 }
386 }
387
388 return true;
389}
390
391/** @}
392 */
Note: See TracBrowser for help on using the repository browser.