00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00037 #include "libfs.h"
00038 #include "../../srv/vfs/vfs.h"
00039 #include <macros.h>
00040 #include <errno.h>
00041 #include <async.h>
00042 #include <as.h>
00043 #include <assert.h>
00044 #include <dirent.h>
00045 #include <mem.h>
00046 #include <sys/stat.h>
00047
00048 #define on_error(rc, action) \
00049 do { \
00050 if ((rc) != EOK) \
00051 action; \
00052 } while (0)
00053
00054 #define combine_rc(rc1, rc2) \
00055 ((rc1) == EOK ? (rc2) : (rc1))
00056
00057 #define answer_and_return(rid, rc) \
00058 do { \
00059 async_answer_0((rid), (rc)); \
00060 return; \
00061 } while (0)
00062
00080 int fs_register(int vfs_phone, fs_reg_t *reg, vfs_info_t *info,
00081 async_client_conn_t conn)
00082 {
00083
00084
00085
00086
00087
00088 ipc_call_t answer;
00089 aid_t req = async_send_0(vfs_phone, VFS_IN_REGISTER, &answer);
00090
00091
00092
00093
00094 int rc = async_data_write_start(vfs_phone, info, sizeof(*info));
00095 if (rc != EOK) {
00096 async_wait_for(req, NULL);
00097 return rc;
00098 }
00099
00100
00101
00102
00103 async_connect_to_me(vfs_phone, 0, 0, 0, conn);
00104
00105
00106
00107
00108 reg->plb_ro = as_get_mappable_page(PLB_SIZE);
00109 if (!reg->plb_ro) {
00110 async_wait_for(req, NULL);
00111 return ENOMEM;
00112 }
00113
00114
00115
00116
00117 rc = async_share_in_start_0_0(vfs_phone, reg->plb_ro, PLB_SIZE);
00118 if (rc) {
00119 async_wait_for(req, NULL);
00120 return rc;
00121 }
00122
00123
00124
00125
00126 async_wait_for(req, NULL);
00127 reg->fs_handle = (int) IPC_GET_ARG1(answer);
00128
00129
00130
00131
00132
00133 async_set_client_connection(conn);
00134
00135 return IPC_GET_RETVAL(answer);
00136 }
00137
00138 void fs_node_initialize(fs_node_t *fn)
00139 {
00140 memset(fn, 0, sizeof(fs_node_t));
00141 }
00142
00143 void libfs_mount(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
00144 ipc_call_t *request)
00145 {
00146 devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00147 fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*request);
00148 fs_handle_t mr_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request);
00149 devmap_handle_t mr_devmap_handle = (devmap_handle_t) IPC_GET_ARG4(*request);
00150 int res;
00151 sysarg_t rc;
00152
00153 ipc_call_t call;
00154 ipc_callid_t callid;
00155
00156
00157 callid = async_get_call(&call);
00158 int mountee_phone = (int) IPC_GET_ARG1(call);
00159 if ((IPC_GET_IMETHOD(call) != IPC_M_CONNECTION_CLONE) ||
00160 (mountee_phone < 0)) {
00161 async_answer_0(callid, EINVAL);
00162 async_answer_0(rid, EINVAL);
00163 return;
00164 }
00165
00166
00167 async_answer_0(callid, EOK);
00168
00169 fs_node_t *fn;
00170 res = ops->node_get(&fn, mp_devmap_handle, mp_fs_index);
00171 if ((res != EOK) || (!fn)) {
00172 async_hangup(mountee_phone);
00173 async_data_write_void(combine_rc(res, ENOENT));
00174 async_answer_0(rid, combine_rc(res, ENOENT));
00175 return;
00176 }
00177
00178 if (fn->mp_data.mp_active) {
00179 async_hangup(mountee_phone);
00180 (void) ops->node_put(fn);
00181 async_data_write_void(EBUSY);
00182 async_answer_0(rid, EBUSY);
00183 return;
00184 }
00185
00186 rc = async_req_0_0(mountee_phone, IPC_M_CONNECT_ME);
00187 if (rc != EOK) {
00188 async_hangup(mountee_phone);
00189 (void) ops->node_put(fn);
00190 async_data_write_void(rc);
00191 async_answer_0(rid, rc);
00192 return;
00193 }
00194
00195 ipc_call_t answer;
00196 rc = async_data_write_forward_1_1(mountee_phone, VFS_OUT_MOUNTED,
00197 mr_devmap_handle, &answer);
00198
00199 if (rc == EOK) {
00200 fn->mp_data.mp_active = true;
00201 fn->mp_data.fs_handle = mr_fs_handle;
00202 fn->mp_data.devmap_handle = mr_devmap_handle;
00203 fn->mp_data.phone = mountee_phone;
00204 }
00205
00206
00207
00208
00209 async_answer_3(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
00210 IPC_GET_ARG3(answer));
00211 }
00212
00213 void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *request)
00214 {
00215 devmap_handle_t mp_devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00216 fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*request);
00217 fs_node_t *fn;
00218 int res;
00219
00220 res = ops->node_get(&fn, mp_devmap_handle, mp_fs_index);
00221 if ((res != EOK) || (!fn)) {
00222 async_answer_0(rid, combine_rc(res, ENOENT));
00223 return;
00224 }
00225
00226
00227
00228
00229 if (!fn->mp_data.mp_active) {
00230 (void) ops->node_put(fn);
00231 async_answer_0(rid, EINVAL);
00232 return;
00233 }
00234
00235
00236
00237
00238 res = async_req_1_0(fn->mp_data.phone, VFS_OUT_UNMOUNTED,
00239 fn->mp_data.devmap_handle);
00240
00241
00242
00243
00244 if (res == EOK) {
00245 async_hangup(fn->mp_data.phone);
00246 fn->mp_data.mp_active = false;
00247 fn->mp_data.fs_handle = 0;
00248 fn->mp_data.devmap_handle = 0;
00249 fn->mp_data.phone = 0;
00250
00251 (void) ops->node_put(fn);
00252 }
00253
00254 (void) ops->node_put(fn);
00255 async_answer_0(rid, res);
00256 }
00257
00271 void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
00272 ipc_call_t *request)
00273 {
00274 unsigned int first = IPC_GET_ARG1(*request);
00275 unsigned int last = IPC_GET_ARG2(*request);
00276 unsigned int next = first;
00277 devmap_handle_t devmap_handle = IPC_GET_ARG3(*request);
00278 int lflag = IPC_GET_ARG4(*request);
00279 fs_index_t index = IPC_GET_ARG5(*request);
00280 char component[NAME_MAX + 1];
00281 int len;
00282 int rc;
00283
00284 if (last < next)
00285 last += PLB_SIZE;
00286
00287 fs_node_t *par = NULL;
00288 fs_node_t *cur = NULL;
00289 fs_node_t *tmp = NULL;
00290
00291 rc = ops->root_get(&cur, devmap_handle);
00292 on_error(rc, goto out_with_answer);
00293
00294 if (cur->mp_data.mp_active) {
00295 async_forward_slow(rid, cur->mp_data.phone, VFS_OUT_LOOKUP,
00296 next, last, cur->mp_data.devmap_handle, lflag, index,
00297 IPC_FF_ROUTE_FROM_ME);
00298 (void) ops->node_put(cur);
00299 return;
00300 }
00301
00302
00303 if (ops->plb_get_char(next) == '/')
00304 next++;
00305
00306 while (next <= last) {
00307 bool has_children;
00308
00309 rc = ops->has_children(&has_children, cur);
00310 on_error(rc, goto out_with_answer);
00311 if (!has_children)
00312 break;
00313
00314
00315 len = 0;
00316 while ((next <= last) && (ops->plb_get_char(next) != '/')) {
00317 if (len + 1 == NAME_MAX) {
00318
00319 async_answer_0(rid, ENAMETOOLONG);
00320 goto out;
00321 }
00322 component[len++] = ops->plb_get_char(next);
00323
00324 next++;
00325 }
00326
00327 assert(len);
00328 component[len] = '\0';
00329
00330 next++;
00331
00332
00333 rc = ops->match(&tmp, cur, component);
00334 on_error(rc, goto out_with_answer);
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 if ((tmp) && (tmp->mp_data.mp_active) &&
00347 (!(lflag & L_MP) || (next <= last))) {
00348 if (next > last)
00349 next = last = first;
00350 else
00351 next--;
00352
00353 async_forward_slow(rid, tmp->mp_data.phone,
00354 VFS_OUT_LOOKUP, next, last, tmp->mp_data.devmap_handle,
00355 lflag, index, IPC_FF_ROUTE_FROM_ME);
00356 (void) ops->node_put(cur);
00357 (void) ops->node_put(tmp);
00358 if (par)
00359 (void) ops->node_put(par);
00360 return;
00361 }
00362
00363
00364 if (!tmp) {
00365 if (next <= last) {
00366
00367 async_answer_0(rid, ENOENT);
00368 goto out;
00369 }
00370
00371
00372 if (lflag & (L_CREATE | L_LINK)) {
00373
00374 if (!ops->is_directory(cur)) {
00375 async_answer_0(rid, ENOTDIR);
00376 goto out;
00377 }
00378
00379 fs_node_t *fn;
00380 if (lflag & L_CREATE)
00381 rc = ops->create(&fn, devmap_handle,
00382 lflag);
00383 else
00384 rc = ops->node_get(&fn, devmap_handle,
00385 index);
00386 on_error(rc, goto out_with_answer);
00387
00388 if (fn) {
00389 rc = ops->link(cur, fn, component);
00390 if (rc != EOK) {
00391 if (lflag & L_CREATE)
00392 (void) ops->destroy(fn);
00393 else
00394 (void) ops->node_put(fn);
00395 async_answer_0(rid, rc);
00396 } else {
00397 aoff64_t size = ops->size_get(fn);
00398 async_answer_5(rid, fs_handle,
00399 devmap_handle,
00400 ops->index_get(fn),
00401 LOWER32(size),
00402 UPPER32(size),
00403 ops->lnkcnt_get(fn));
00404 (void) ops->node_put(fn);
00405 }
00406 } else
00407 async_answer_0(rid, ENOSPC);
00408
00409 goto out;
00410 }
00411
00412 async_answer_0(rid, ENOENT);
00413 goto out;
00414 }
00415
00416 if (par) {
00417 rc = ops->node_put(par);
00418 on_error(rc, goto out_with_answer);
00419 }
00420
00421
00422 par = cur;
00423 cur = tmp;
00424 tmp = NULL;
00425 }
00426
00427
00428 if (next <= last) {
00429 bool has_children;
00430 rc = ops->has_children(&has_children, cur);
00431 on_error(rc, goto out_with_answer);
00432
00433 if (has_children)
00434 goto skip_miss;
00435
00436 if (lflag & (L_CREATE | L_LINK)) {
00437 if (!ops->is_directory(cur)) {
00438 async_answer_0(rid, ENOTDIR);
00439 goto out;
00440 }
00441
00442
00443 len = 0;
00444 while (next <= last) {
00445 if (ops->plb_get_char(next) == '/') {
00446
00447 async_answer_0(rid, ENOENT);
00448 goto out;
00449 }
00450
00451 if (len + 1 == NAME_MAX) {
00452
00453 async_answer_0(rid, ENAMETOOLONG);
00454 goto out;
00455 }
00456
00457 component[len++] = ops->plb_get_char(next);
00458
00459 next++;
00460 }
00461
00462 assert(len);
00463 component[len] = '\0';
00464
00465 fs_node_t *fn;
00466 if (lflag & L_CREATE)
00467 rc = ops->create(&fn, devmap_handle, lflag);
00468 else
00469 rc = ops->node_get(&fn, devmap_handle, index);
00470 on_error(rc, goto out_with_answer);
00471
00472 if (fn) {
00473 rc = ops->link(cur, fn, component);
00474 if (rc != EOK) {
00475 if (lflag & L_CREATE)
00476 (void) ops->destroy(fn);
00477 else
00478 (void) ops->node_put(fn);
00479 async_answer_0(rid, rc);
00480 } else {
00481 aoff64_t size = ops->size_get(fn);
00482 async_answer_5(rid, fs_handle,
00483 devmap_handle,
00484 ops->index_get(fn),
00485 LOWER32(size),
00486 UPPER32(size),
00487 ops->lnkcnt_get(fn));
00488 (void) ops->node_put(fn);
00489 }
00490 } else
00491 async_answer_0(rid, ENOSPC);
00492
00493 goto out;
00494 }
00495
00496 async_answer_0(rid, ENOENT);
00497 goto out;
00498 }
00499
00500 skip_miss:
00501
00502
00503 if (lflag & L_UNLINK) {
00504 unsigned int old_lnkcnt = ops->lnkcnt_get(cur);
00505 rc = ops->unlink(par, cur, component);
00506
00507 if (rc == EOK) {
00508 aoff64_t size = ops->size_get(cur);
00509 async_answer_5(rid, fs_handle, devmap_handle,
00510 ops->index_get(cur), LOWER32(size), UPPER32(size),
00511 old_lnkcnt);
00512 } else
00513 async_answer_0(rid, rc);
00514
00515 goto out;
00516 }
00517
00518 if (((lflag & (L_CREATE | L_EXCLUSIVE)) == (L_CREATE | L_EXCLUSIVE)) ||
00519 (lflag & L_LINK)) {
00520 async_answer_0(rid, EEXIST);
00521 goto out;
00522 }
00523
00524 if ((lflag & L_FILE) && (ops->is_directory(cur))) {
00525 async_answer_0(rid, EISDIR);
00526 goto out;
00527 }
00528
00529 if ((lflag & L_DIRECTORY) && (ops->is_file(cur))) {
00530 async_answer_0(rid, ENOTDIR);
00531 goto out;
00532 }
00533
00534 if ((lflag & L_ROOT) && par) {
00535 async_answer_0(rid, EINVAL);
00536 goto out;
00537 }
00538
00539 out_with_answer:
00540
00541 if (rc == EOK) {
00542 if (lflag & L_OPEN)
00543 rc = ops->node_open(cur);
00544
00545 if (rc == EOK) {
00546 aoff64_t size = ops->size_get(cur);
00547 async_answer_5(rid, fs_handle, devmap_handle,
00548 ops->index_get(cur), LOWER32(size), UPPER32(size),
00549 ops->lnkcnt_get(cur));
00550 } else
00551 async_answer_0(rid, rc);
00552
00553 } else
00554 async_answer_0(rid, rc);
00555
00556 out:
00557
00558 if (par)
00559 (void) ops->node_put(par);
00560
00561 if (cur)
00562 (void) ops->node_put(cur);
00563
00564 if (tmp)
00565 (void) ops->node_put(tmp);
00566 }
00567
00568 void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
00569 ipc_call_t *request)
00570 {
00571 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00572 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00573
00574 fs_node_t *fn;
00575 int rc = ops->node_get(&fn, devmap_handle, index);
00576 on_error(rc, answer_and_return(rid, rc));
00577
00578 ipc_callid_t callid;
00579 size_t size;
00580 if ((!async_data_read_receive(&callid, &size)) ||
00581 (size != sizeof(struct stat))) {
00582 ops->node_put(fn);
00583 async_answer_0(callid, EINVAL);
00584 async_answer_0(rid, EINVAL);
00585 return;
00586 }
00587
00588 struct stat stat;
00589 memset(&stat, 0, sizeof(struct stat));
00590
00591 stat.fs_handle = fs_handle;
00592 stat.devmap_handle = devmap_handle;
00593 stat.index = index;
00594 stat.lnkcnt = ops->lnkcnt_get(fn);
00595 stat.is_file = ops->is_file(fn);
00596 stat.is_directory = ops->is_directory(fn);
00597 stat.size = ops->size_get(fn);
00598 stat.device = ops->device_get(fn);
00599
00600 ops->node_put(fn);
00601
00602 async_data_read_finalize(callid, &stat, sizeof(struct stat));
00603 async_answer_0(rid, EOK);
00604 }
00605
00614 void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
00615 ipc_call_t *request)
00616 {
00617 devmap_handle_t devmap_handle = IPC_GET_ARG1(*request);
00618 fs_index_t index = IPC_GET_ARG2(*request);
00619
00620 fs_node_t *fn;
00621 int rc = ops->node_get(&fn, devmap_handle, index);
00622 on_error(rc, answer_and_return(rid, rc));
00623
00624 if (fn == NULL) {
00625 async_answer_0(rid, ENOENT);
00626 return;
00627 }
00628
00629 rc = ops->node_open(fn);
00630 aoff64_t size = ops->size_get(fn);
00631 async_answer_4(rid, rc, LOWER32(size), UPPER32(size), ops->lnkcnt_get(fn),
00632 (ops->is_file(fn) ? L_FILE : 0) | (ops->is_directory(fn) ? L_DIRECTORY : 0));
00633
00634 (void) ops->node_put(fn);
00635 }
00636