source: mainline/uspace/lib/libfs/libfs.c@ 7fe1f75

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

Move the core lookup logic from TMPFS to libfs.

  • Property mode set to 100644
File size: 7.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 <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 libfs_lookup(libfs_ops_t *ops, int fs_handle, ipc_callid_t rid,
126 ipc_call_t *request)
127{
128 unsigned next = IPC_GET_ARG1(*request);
129 unsigned last = IPC_GET_ARG2(*request);
130 int dev_handle = IPC_GET_ARG3(*request);
131 int lflag = IPC_GET_ARG4(*request);
132
133 if (last < next)
134 last += PLB_SIZE;
135
136 void *cur = ops->root_get();
137 void *tmp = ops->child_get(cur);
138
139 if (ops->plb_get_char(next) == '/')
140 next++; /* eat slash */
141
142 char component[NAME_MAX + 1];
143 int len = 0;
144 while (tmp && next <= last) {
145
146 /* collect the component */
147 if (ops->plb_get_char(next) != '/') {
148 if (len + 1 == NAME_MAX) {
149 /* comopnent length overflow */
150 ipc_answer_0(rid, ENAMETOOLONG);
151 return;
152 }
153 component[len++] = ops->plb_get_char(next);
154 next++; /* process next character */
155 if (next <= last)
156 continue;
157 }
158
159 assert(len);
160 component[len] = '\0';
161 next++; /* eat slash */
162 len = 0;
163
164 /* match the component */
165 while (tmp && !ops->match(tmp, component))
166 tmp = ops->sibling_get(tmp);
167
168 /* handle miss: match amongst siblings */
169 if (!tmp) {
170 if ((next > last) && (lflag & L_CREATE)) {
171 /* no components left and L_CREATE specified */
172 if (!ops->is_directory(cur)) {
173 ipc_answer_0(rid, ENOTDIR);
174 return;
175 }
176 void *nodep = ops->create(lflag);
177 if (nodep) {
178 if (!ops->link(cur, nodep, component)) {
179 ops->destroy(nodep);
180 ipc_answer_0(rid, ENOSPC);
181 } else {
182 ipc_answer_5(rid, EOK,
183 fs_handle, dev_handle,
184 ops->index_get(nodep), 0,
185 ops->lnkcnt_get(nodep));
186 }
187 } else {
188 ipc_answer_0(rid, ENOSPC);
189 }
190 return;
191 }
192 ipc_answer_0(rid, ENOENT);
193 return;
194 }
195
196 /* descend one level */
197 cur = tmp;
198 tmp = ops->child_get(tmp);
199 }
200
201 /* handle miss: excessive components */
202 if (!tmp && next <= last) {
203 if (lflag & L_CREATE) {
204 if (!ops->is_directory(cur)) {
205 ipc_answer_0(rid, ENOTDIR);
206 return;
207 }
208
209 /* collect next component */
210 while (next <= last) {
211 if (ops->plb_get_char(next) == '/') {
212 /* more than one component */
213 ipc_answer_0(rid, ENOENT);
214 return;
215 }
216 if (len + 1 == NAME_MAX) {
217 /* component length overflow */
218 ipc_answer_0(rid, ENAMETOOLONG);
219 return;
220 }
221 component[len++] = ops->plb_get_char(next);
222 next++; /* process next character */
223 }
224 assert(len);
225 component[len] = '\0';
226 len = 0;
227
228 void *nodep = ops->create(lflag);
229 if (nodep) {
230 if (!ops->link(cur, nodep, component)) {
231 ops->destroy(nodep);
232 ipc_answer_0(rid, ENOSPC);
233 } else {
234 ipc_answer_5(rid, EOK,
235 fs_handle, dev_handle,
236 ops->index_get(nodep), 0,
237 ops->lnkcnt_get(nodep));
238 }
239 } else {
240 ipc_answer_0(rid, ENOSPC);
241 }
242 return;
243 }
244 ipc_answer_0(rid, ENOENT);
245 return;
246 }
247
248 /* handle hit */
249 if (lflag & L_DESTROY) {
250 unsigned old_lnkcnt = ops->lnkcnt_get(cur);
251 int res = ops->unlink(cur);
252 ipc_answer_5(rid, (ipcarg_t)res, fs_handle, dev_handle,
253 ops->index_get(cur), ops->size_get(cur), old_lnkcnt);
254 return;
255 }
256 if ((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) {
257 ipc_answer_0(rid, EEXIST);
258 return;
259 }
260 if ((lflag & L_FILE) && (ops->is_directory(cur))) {
261 ipc_answer_0(rid, EISDIR);
262 return;
263 }
264 if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
265 ipc_answer_0(rid, ENOTDIR);
266 return;
267 }
268
269 ipc_answer_5(rid, EOK, fs_handle, dev_handle, ops->index_get(cur),
270 ops->size_get(cur), ops->lnkcnt_get(cur));
271}
272
273/** @}
274 */
Note: See TracBrowser for help on using the repository browser.