Changeset 0d35511 in mainline for uspace/srv/vfs/vfs_ops.c
- Timestamp:
- 2017-03-08T18:27:40Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 4809715
- Parents:
- 5126f80
- git-author:
- Jiri Zarevucky <zarevucky.jiri@…> (2017-03-08 18:27:40)
- git-committer:
- Jakub Jermar <jakub@…> (2017-03-08 18:27:40)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/vfs/vfs_ops.c
r5126f80 r0d35511 68 68 FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock); 69 69 70 static int vfs_connect_internal(service_id_t service_id, unsigned flags, unsigned instance, 71 char *options, char *fsname, vfs_node_t **root) 70 static size_t shared_path(char *a, char *b) 71 { 72 size_t res = 0; 73 74 while (a[res] == b[res] && a[res] != 0) { 75 res++; 76 } 77 78 if (a[res] == b[res]) { 79 return res; 80 } 81 82 res--; 83 while (a[res] != '/') { 84 res--; 85 } 86 return res; 87 } 88 89 /* This call destroys the file if and only if there are no hard links left. */ 90 static void out_destroy(vfs_triplet_t *file) 91 { 92 async_exch_t *exch = vfs_exchange_grab(file->fs_handle); 93 async_msg_2(exch, VFS_OUT_DESTROY, 94 (sysarg_t) file->service_id, (sysarg_t) file->index); 95 vfs_exchange_release(exch); 96 } 97 98 int vfs_op_clone(int oldfd, bool desc) 99 { 100 /* Lookup the file structure corresponding to fd. */ 101 vfs_file_t *oldfile = vfs_file_get(oldfd); 102 if (oldfile == NULL) { 103 return EBADF; 104 } 105 assert(oldfile->node != NULL); 106 107 vfs_file_t *newfile; 108 int newfd = vfs_fd_alloc(&newfile, desc); 109 if (newfd >= 0) { 110 newfile->node = oldfile->node; 111 newfile->permissions = oldfile->permissions; 112 vfs_node_addref(newfile->node); 113 114 vfs_file_put(newfile); 115 } 116 vfs_file_put(oldfile); 117 118 return newfd; 119 } 120 121 int vfs_op_close(int fd) 122 { 123 return vfs_fd_free(fd); 124 } 125 126 int vfs_op_dup(int oldfd, int newfd) 127 { 128 /* If the file descriptors are the same, do nothing. */ 129 if (oldfd == newfd) { 130 return EOK; 131 } 132 133 /* Lookup the file structure corresponding to oldfd. */ 134 vfs_file_t *oldfile = vfs_file_get(oldfd); 135 if (!oldfile) { 136 return EBADF; 137 } 138 139 /* Make sure newfd is closed. */ 140 (void) vfs_fd_free(newfd); 141 142 /* Assign the old file to newfd. */ 143 int ret = vfs_fd_assign(oldfile, newfd); 144 vfs_file_put(oldfile); 145 146 return ret; 147 } 148 149 int vfs_op_fstat_forward(int fd) 150 { 151 vfs_file_t *file = vfs_file_get(fd); 152 if (!file) { 153 return EBADF; 154 } 155 assert(file->node); 156 157 ipc_callid_t callid; 158 if (!async_data_read_receive(&callid, NULL)) { 159 vfs_file_put(file); 160 async_answer_0(callid, EINVAL); 161 return EINVAL; 162 } 163 164 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle); 165 assert(exch); 166 167 aid_t msg; 168 msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id, 169 file->node->index, true, NULL); 170 assert(msg); 171 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 172 173 vfs_exchange_release(exch); 174 175 sysarg_t rc; 176 async_wait_for(msg, &rc); 177 178 vfs_file_put(file); 179 return rc; 180 } 181 182 static int vfs_connect_internal(service_id_t service_id, unsigned flags, 183 unsigned instance, const char *options, const char *fsname, 184 vfs_node_t **root) 72 185 { 73 186 fs_handle_t fs_handle = 0; … … 92 205 ipc_call_t answer; 93 206 async_exch_t *exch = vfs_exchange_grab(fs_handle); 94 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, &answer); 207 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, 208 &answer); 95 209 /* Send the mount options */ 96 210 sysarg_t rc = async_data_write_start(exch, options, str_size(options)); … … 111 225 res.triplet.service_id = service_id; 112 226 res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer); 113 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer)); 227 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), 228 IPC_GET_ARG3(answer)); 114 229 res.type = VFS_NODE_DIRECTORY; 115 230 … … 121 236 } 122 237 123 void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request) 124 { 125 int mpfd = IPC_GET_ARG1(*request); 126 127 /* 128 * We expect the library to do the device-name to device-handle 129 * translation for us, thus the device handle will arrive as ARG1 130 * in the request. 131 */ 132 service_id_t service_id = (service_id_t) IPC_GET_ARG2(*request); 133 134 /* 135 * Mount flags are passed as ARG2. 136 */ 137 unsigned int flags = (unsigned int) IPC_GET_ARG3(*request); 138 139 /* 140 * Instance number is passed as ARG3. 141 */ 142 unsigned int instance = IPC_GET_ARG4(*request); 143 144 char *opts = NULL; 145 char *fs_name = NULL; 238 int vfs_op_mount(int mpfd, unsigned service_id, unsigned flags, 239 unsigned instance, const char *opts, const char *fs_name, int *outfd) 240 { 241 int rc; 146 242 vfs_file_t *mp = NULL; 147 243 vfs_file_t *file = NULL; 148 244 int fd = -1; 149 245 mtab_ent_t *mtab_ent = NULL; 150 151 /* Now we expect to receive the mount options. */152 int rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,153 0, NULL);154 if (rc != EOK) {155 async_data_write_void(rc);156 goto out;157 }158 159 /*160 * Now, we expect the client to send us data with the name of the file161 * system.162 */163 rc = async_data_write_accept((void **) &fs_name, true, 0,164 FS_NAME_MAXLEN, 0, NULL);165 if (rc != EOK) {166 goto out;167 }168 246 169 247 if (!(flags & VFS_MOUNT_CONNECT_ONLY)) { … … 209 287 fibril_rwlock_write_lock(&namespace_rwlock); 210 288 211 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, &root); 289 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, 290 &root); 212 291 if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) { 213 292 vfs_node_addref(mp->node); … … 235 314 236 315 /* Add the filesystem info to the list of mounted filesystems */ 237 if (rc == EOK) { 238 str_cpy(mtab_ent->mp, MAX_PATH_LEN, "fixme"); 239 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name); 240 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts); 241 mtab_ent->instance = instance; 242 mtab_ent->service_id = service_id; 243 244 link_initialize(&mtab_ent->link); 245 246 fibril_mutex_lock(&mtab_list_lock); 247 list_append(&mtab_ent->link, &mtab_list); 248 mtab_size++; 249 fibril_mutex_unlock(&mtab_list_lock); 250 } 251 252 rc = EOK; 316 str_cpy(mtab_ent->mp, MAX_PATH_LEN, "fixme"); 317 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name); 318 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts); 319 mtab_ent->instance = instance; 320 mtab_ent->service_id = service_id; 321 322 link_initialize(&mtab_ent->link); 323 324 fibril_mutex_lock(&mtab_list_lock); 325 list_append(&mtab_ent->link, &mtab_list); 326 mtab_size++; 327 fibril_mutex_unlock(&mtab_list_lock); 253 328 254 329 out: 255 async_answer_1(rid, rc, rc == EOK ? fd : 0);256 257 if (opts) {258 free(opts);259 }260 if (fs_name) {261 free(fs_name);262 }263 330 if (mp) { 264 331 vfs_file_put(mp); … … 269 336 if (rc != EOK && fd >= 0) { 270 337 vfs_fd_free(fd); 271 } 272 } 273 274 void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request) 275 { 276 int mpfd = IPC_GET_ARG1(*request); 277 278 vfs_file_t *mp = vfs_file_get(mpfd); 279 if (mp == NULL) { 280 async_answer_0(rid, EBADF); 281 return; 282 } 283 284 if (mp->node->mount == NULL) { 285 async_answer_0(rid, ENOENT); 286 vfs_file_put(mp); 287 return; 288 } 289 290 fibril_rwlock_write_lock(&namespace_rwlock); 291 292 /* 293 * Count the total number of references for the mounted file system. We 294 * are expecting at least one, which is held by the mount point. 295 * If we find more, it means that 296 * the file system cannot be gracefully unmounted at the moment because 297 * someone is working with it. 298 */ 299 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle, mp->node->mount->service_id) != 1) { 300 async_answer_0(rid, EBUSY); 301 vfs_file_put(mp); 302 fibril_rwlock_write_unlock(&namespace_rwlock); 303 return; 304 } 305 306 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle); 307 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, mp->node->mount->service_id); 308 vfs_exchange_release(exch); 309 310 if (rc != EOK) { 311 async_answer_0(rid, rc); 312 vfs_file_put(mp); 313 fibril_rwlock_write_unlock(&namespace_rwlock); 314 return; 315 } 316 317 vfs_node_forget(mp->node->mount); 318 vfs_node_put(mp->node); 319 mp->node->mount = NULL; 320 321 fibril_rwlock_write_unlock(&namespace_rwlock); 322 338 fd = 0; 339 } 340 341 *outfd = fd; 342 return rc; 343 } 344 345 int vfs_op_mtab_get(void) 346 { 347 ipc_callid_t callid; 348 ipc_call_t data; 349 sysarg_t rc = EOK; 350 size_t len; 351 323 352 fibril_mutex_lock(&mtab_list_lock); 324 int found = 0; 353 354 /* Send to the caller the number of mounted filesystems */ 355 callid = async_get_call(&data); 356 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 357 rc = ENOTSUP; 358 async_answer_0(callid, rc); 359 goto exit; 360 } 361 async_answer_1(callid, EOK, mtab_size); 325 362 326 363 list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) { 327 // FIXME: mp name 328 if (str_cmp(mtab_ent->mp, "fixme") == 0) { 329 list_remove(&mtab_ent->link); 330 mtab_size--; 331 free(mtab_ent); 332 found = 1; 333 break; 334 } 335 } 336 assert(found); 364 rc = ENOTSUP; 365 366 if (!async_data_read_receive(&callid, &len)) { 367 async_answer_0(callid, rc); 368 goto exit; 369 } 370 371 (void) async_data_read_finalize(callid, mtab_ent->mp, 372 str_size(mtab_ent->mp)); 373 374 if (!async_data_read_receive(&callid, &len)) { 375 async_answer_0(callid, rc); 376 goto exit; 377 } 378 379 (void) async_data_read_finalize(callid, mtab_ent->opts, 380 str_size(mtab_ent->opts)); 381 382 if (!async_data_read_receive(&callid, &len)) { 383 async_answer_0(callid, rc); 384 goto exit; 385 } 386 387 (void) async_data_read_finalize(callid, mtab_ent->fs_name, 388 str_size(mtab_ent->fs_name)); 389 390 callid = async_get_call(&data); 391 392 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 393 async_answer_0(callid, rc); 394 goto exit; 395 } 396 397 rc = EOK; 398 async_answer_2(callid, rc, mtab_ent->instance, 399 mtab_ent->service_id); 400 } 401 402 exit: 337 403 fibril_mutex_unlock(&mtab_list_lock); 338 339 vfs_file_put(mp); 340 async_answer_0(rid, EOK); 341 } 342 343 static inline bool walk_flags_valid(int flags) 344 { 345 if ((flags&~WALK_ALL_FLAGS) != 0) { 346 return false; 347 } 348 if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) { 349 return false; 350 } 351 if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) { 352 return false; 353 } 354 if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) { 355 if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) { 356 return false; 357 } 358 } 359 return true; 360 } 361 362 static inline int walk_lookup_flags(int flags) 363 { 364 int lflags = 0; 365 if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) { 366 lflags |= L_CREATE; 367 } 368 if (flags&WALK_MUST_CREATE) { 369 lflags |= L_EXCLUSIVE; 370 } 371 if (flags&WALK_REGULAR) { 372 lflags |= L_FILE; 373 } 374 if (flags&WALK_DIRECTORY) { 375 lflags |= L_DIRECTORY; 376 } 377 if (flags&WALK_MOUNT_POINT) { 378 lflags |= L_MP; 379 } 380 return lflags; 381 } 382 383 void vfs_walk(ipc_callid_t rid, ipc_call_t *request) 384 { 385 /* 386 * Parent is our relative root for file lookup. 387 * For defined flags, see <ipc/vfs.h>. 388 */ 389 int parentfd = IPC_GET_ARG1(*request); 390 int flags = IPC_GET_ARG2(*request); 391 392 if (!walk_flags_valid(flags)) { 393 async_answer_0(rid, EINVAL); 394 return; 395 } 396 397 char *path; 398 int rc = async_data_write_accept((void **)&path, true, 0, 0, 0, NULL); 399 400 /* Lookup the file structure corresponding to the file descriptor. */ 401 vfs_file_t *parent = vfs_file_get(parentfd); 402 if (!parent) { 403 free(path); 404 async_answer_0(rid, EBADF); 405 return; 406 } 407 408 fibril_rwlock_read_lock(&namespace_rwlock); 409 410 vfs_lookup_res_t lr; 411 rc = vfs_lookup_internal(parent->node, path, walk_lookup_flags(flags), &lr); 412 free(path); 413 414 if (rc != EOK) { 415 fibril_rwlock_read_unlock(&namespace_rwlock); 416 if (parent) { 417 vfs_file_put(parent); 418 } 419 async_answer_0(rid, rc); 420 return; 421 } 422 423 vfs_node_t *node = vfs_node_get(&lr); 424 425 vfs_file_t *file; 426 int fd = vfs_fd_alloc(&file, false); 427 if (fd < 0) { 428 vfs_node_put(node); 429 if (parent) { 430 vfs_file_put(parent); 431 } 432 async_answer_0(rid, fd); 433 return; 434 } 435 assert(file != NULL); 436 437 file->node = node; 438 if (parent) { 439 file->permissions = parent->permissions; 440 } else { 441 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND; 442 } 443 file->open_read = false; 444 file->open_write = false; 445 446 vfs_file_put(file); 447 if (parent) { 448 vfs_file_put(parent); 449 } 450 451 fibril_rwlock_read_unlock(&namespace_rwlock); 452 453 async_answer_1(rid, EOK, fd); 454 } 455 456 void vfs_open2(ipc_callid_t rid, ipc_call_t *request) 457 { 458 int fd = IPC_GET_ARG1(*request); 459 int flags = IPC_GET_ARG2(*request); 460 404 return rc; 405 } 406 407 int vfs_op_open2(int fd, int flags) 408 { 461 409 if (flags == 0) { 462 async_answer_0(rid, EINVAL); 463 return; 410 return EINVAL; 464 411 } 465 412 466 413 vfs_file_t *file = vfs_file_get(fd); 467 414 if (!file) { 468 async_answer_0(rid, EBADF); 469 return; 415 return EBADF; 470 416 } 471 417 472 418 if ((flags & ~file->permissions) != 0) { 473 419 vfs_file_put(file); 474 async_answer_0(rid, EPERM); 475 return; 420 return EPERM; 421 } 422 423 if (file->open_read || file->open_write) { 424 vfs_file_put(file); 425 return EBUSY; 476 426 } 477 427 … … 482 432 if (!file->open_read && !file->open_write) { 483 433 vfs_file_put(file); 484 async_answer_0(rid, EINVAL); 485 return; 434 return EINVAL; 486 435 } 487 436 … … 489 438 file->open_read = file->open_write = false; 490 439 vfs_file_put(file); 491 async_answer_0(rid, EINVAL); 492 return; 440 return EINVAL; 493 441 } 494 442 … … 497 445 file->open_read = file->open_write = false; 498 446 vfs_file_put(file); 499 async_answer_0(rid, rc); 500 return; 447 return rc; 501 448 } 502 449 503 450 vfs_file_put(file); 504 async_answer_0(rid, EOK); 505 } 506 507 void vfs_sync(ipc_callid_t rid, ipc_call_t *request) 508 { 509 int fd = IPC_GET_ARG1(*request); 510 511 /* Lookup the file structure corresponding to the file descriptor. */ 512 vfs_file_t *file = vfs_file_get(fd); 513 if (!file) { 514 async_answer_0(rid, ENOENT); 515 return; 516 } 517 518 /* 519 * Lock the open file structure so that no other thread can manipulate 520 * the same open file at a time. 521 */ 522 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle); 523 524 /* Make a VFS_OUT_SYMC request at the destination FS server. */ 525 aid_t msg; 526 ipc_call_t answer; 527 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id, 528 file->node->index, &answer); 529 530 vfs_exchange_release(fs_exch); 531 532 /* Wait for reply from the FS server. */ 533 sysarg_t rc; 534 async_wait_for(msg, &rc); 535 536 vfs_file_put(file); 537 async_answer_0(rid, rc); 538 } 539 540 void vfs_close(ipc_callid_t rid, ipc_call_t *request) 541 { 542 int fd = IPC_GET_ARG1(*request); 543 int ret = vfs_fd_free(fd); 544 async_answer_0(rid, ret); 451 return EOK; 545 452 } 546 453 … … 629 536 assert(fs_info); 630 537 631 bool rlock = read || ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)); 538 bool rlock = read || 539 (fs_info->concurrent_read_write && fs_info->write_retains_size); 632 540 633 541 /* … … 650 558 if (!read) { 651 559 if (rlock) { 652 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 560 fibril_rwlock_read_unlock( 561 &file->node->contents_rwlock); 653 562 } else { 654 fibril_rwlock_write_unlock(&file->node->contents_rwlock); 563 fibril_rwlock_write_unlock( 564 &file->node->contents_rwlock); 655 565 } 656 566 vfs_file_put(file); … … 700 610 return rc; 701 611 } 702 703 static void vfs_rdwr_client(ipc_callid_t rid, ipc_call_t *request, bool read)704 {705 size_t bytes = 0;706 int rc = vfs_rdwr(IPC_GET_ARG1(*request), read, rdwr_ipc_client,707 &bytes);708 async_answer_1(rid, rc, bytes);709 }710 612 711 613 int vfs_rdwr_internal(int fd, bool read, rdwr_io_chunk_t *chunk) … … 714 616 } 715 617 716 void vfs_read(ipc_callid_t rid, ipc_call_t *request) 717 { 718 vfs_rdwr_client(rid, request, true); 719 } 720 721 void vfs_write(ipc_callid_t rid, ipc_call_t *request) 722 { 723 vfs_rdwr_client(rid, request, false); 724 } 725 726 void vfs_seek(ipc_callid_t rid, ipc_call_t *request) 727 { 728 int fd = (int) IPC_GET_ARG1(*request); 729 off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request), 730 IPC_GET_ARG3(*request)); 731 int whence = (int) IPC_GET_ARG4(*request); 732 733 /* Lookup the file structure corresponding to the file descriptor. */ 734 vfs_file_t *file = vfs_file_get(fd); 735 if (!file) { 736 async_answer_0(rid, ENOENT); 737 return; 738 } 739 740 off64_t newoff; 741 switch (whence) { 742 case SEEK_SET: 743 if (off >= 0) { 744 file->pos = (aoff64_t) off; 745 vfs_file_put(file); 746 async_answer_1(rid, EOK, off); 747 return; 748 } 749 break; 750 case SEEK_CUR: 751 if ((off >= 0) && (file->pos + off < file->pos)) { 752 vfs_file_put(file); 753 async_answer_0(rid, EOVERFLOW); 754 return; 755 } 756 757 if ((off < 0) && (file->pos < (aoff64_t) -off)) { 758 vfs_file_put(file); 759 async_answer_0(rid, EOVERFLOW); 760 return; 761 } 762 763 file->pos += off; 764 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos; 765 766 vfs_file_put(file); 767 async_answer_2(rid, EOK, LOWER32(newoff), 768 UPPER32(newoff)); 769 return; 770 case SEEK_END: 771 fibril_rwlock_read_lock(&file->node->contents_rwlock); 772 aoff64_t size = vfs_node_get_size(file->node); 773 774 if ((off >= 0) && (size + off < size)) { 775 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 776 vfs_file_put(file); 777 async_answer_0(rid, EOVERFLOW); 778 return; 779 } 780 781 if ((off < 0) && (size < (aoff64_t) -off)) { 782 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 783 vfs_file_put(file); 784 async_answer_0(rid, EOVERFLOW); 785 return; 786 } 787 788 file->pos = size + off; 789 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos; 790 791 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 792 vfs_file_put(file); 793 async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff)); 794 return; 795 } 796 797 vfs_file_put(file); 798 async_answer_0(rid, EINVAL); 799 } 800 801 int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id, 802 fs_index_t index, aoff64_t size) 803 { 804 async_exch_t *exch = vfs_exchange_grab(fs_handle); 805 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE, 806 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size), 807 UPPER32(size)); 808 vfs_exchange_release(exch); 809 810 return (int) rc; 811 } 812 813 void vfs_truncate(ipc_callid_t rid, ipc_call_t *request) 814 { 815 int fd = IPC_GET_ARG1(*request); 816 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request), 817 IPC_GET_ARG3(*request)); 818 int rc; 819 820 vfs_file_t *file = vfs_file_get(fd); 821 if (!file) { 822 async_answer_0(rid, ENOENT); 823 return; 824 } 825 826 fibril_rwlock_write_lock(&file->node->contents_rwlock); 827 rc = vfs_truncate_internal(file->node->fs_handle, 828 file->node->service_id, file->node->index, size); 829 if (rc == EOK) 830 file->node->size = size; 831 fibril_rwlock_write_unlock(&file->node->contents_rwlock); 832 833 vfs_file_put(file); 834 async_answer_0(rid, (sysarg_t)rc); 835 } 836 837 void vfs_fstat(ipc_callid_t rid, ipc_call_t *request) 838 { 839 int fd = IPC_GET_ARG1(*request); 840 sysarg_t rc; 841 842 vfs_file_t *file = vfs_file_get(fd); 843 if (!file) { 844 async_answer_0(rid, ENOENT); 845 return; 846 } 847 assert(file->node); 848 849 ipc_callid_t callid; 850 if (!async_data_read_receive(&callid, NULL)) { 851 vfs_file_put(file); 852 async_answer_0(callid, EINVAL); 853 async_answer_0(rid, EINVAL); 854 return; 855 } 856 857 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle); 858 assert(exch); 859 860 aid_t msg; 861 msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id, 862 file->node->index, true, NULL); 863 assert(msg); 864 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 865 866 vfs_exchange_release(exch); 867 868 async_wait_for(msg, &rc); 869 870 vfs_file_put(file); 871 async_answer_0(rid, rc); 872 } 873 874 static void out_destroy(vfs_triplet_t *file) 875 { 876 async_exch_t *exch = vfs_exchange_grab(file->fs_handle); 877 async_msg_2(exch, VFS_OUT_DESTROY, 878 (sysarg_t) file->service_id, (sysarg_t) file->index); 879 vfs_exchange_release(exch); 880 } 881 882 void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request) 883 { 884 int rc; 885 char *path; 886 vfs_file_t *parent = NULL; 887 vfs_file_t *expect = NULL; 888 889 int parentfd = IPC_GET_ARG1(*request); 890 int expectfd = IPC_GET_ARG2(*request); 891 int wflag = IPC_GET_ARG3(*request); 892 893 rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL); 894 if (rc != EOK) { 895 async_answer_0(rid, rc); 896 return; 897 } 898 if (parentfd == expectfd) { 899 async_answer_0(rid, EINVAL); 900 return; 901 } 902 903 fibril_rwlock_write_lock(&namespace_rwlock); 904 905 int lflag = (wflag&WALK_DIRECTORY) ? L_DIRECTORY: 0; 906 907 /* Files are retrieved in order of file descriptors, to prevent deadlock. */ 908 if (parentfd < expectfd) { 909 parent = vfs_file_get(parentfd); 910 if (!parent) { 911 rc = EBADF; 912 goto exit; 913 } 914 } 915 916 if (expectfd >= 0) { 917 expect = vfs_file_get(expectfd); 918 if (!expect) { 919 rc = ENOENT; 920 goto exit; 921 } 922 } 923 924 if (parentfd > expectfd) { 925 parent = vfs_file_get(parentfd); 926 if (!parent) { 927 rc = EBADF; 928 goto exit; 929 } 930 } 931 932 assert(parent != NULL); 933 934 if (expectfd >= 0) { 935 vfs_lookup_res_t lr; 936 rc = vfs_lookup_internal(parent->node, path, lflag, &lr); 937 if (rc != EOK) { 938 goto exit; 939 } 940 941 vfs_node_t *found_node = vfs_node_peek(&lr); 942 if (expect->node != found_node) { 943 rc = ENOENT; 944 goto exit; 945 } 946 947 vfs_file_put(expect); 948 expect = NULL; 949 } 950 951 vfs_lookup_res_t lr; 952 rc = vfs_lookup_internal(parent->node, path, lflag | L_UNLINK, &lr); 953 if (rc != EOK) { 954 goto exit; 955 } 956 957 /* If the node is not held by anyone, try to destroy it. */ 958 if (vfs_node_peek(&lr) == NULL) { 959 out_destroy(&lr.triplet); 960 } 961 962 exit: 963 if (path) { 964 free(path); 965 } 966 if (parent) { 967 vfs_file_put(parent); 968 } 969 if (expect) { 970 vfs_file_put(expect); 971 } 972 fibril_rwlock_write_unlock(&namespace_rwlock); 973 async_answer_0(rid, rc); 974 } 975 976 static size_t shared_path(char *a, char *b) 977 { 978 size_t res = 0; 979 980 while (a[res] == b[res] && a[res] != 0) { 981 res++; 982 } 983 984 if (a[res] == b[res]) { 985 return res; 986 } 987 988 res--; 989 while (a[res] != '/') { 990 res--; 991 } 992 return res; 993 } 994 995 static int vfs_rename_internal(vfs_node_t *base, char *old, char *new) 996 { 997 assert(base != NULL); 998 assert(old != NULL); 999 assert(new != NULL); 618 int vfs_op_read(int fd, size_t *out_bytes) 619 { 620 return vfs_rdwr(fd, true, rdwr_ipc_client, out_bytes); 621 } 622 623 int vfs_op_rename(int basefd, char *old, char *new) 624 { 625 vfs_file_t *base_file = vfs_file_get(basefd); 626 if (!base_file) { 627 return EBADF; 628 } 629 vfs_node_t *base = base_file->node; 630 vfs_node_addref(base); 631 vfs_file_put(base_file); 1000 632 1001 633 vfs_lookup_res_t base_lr; … … 1026 658 } 1027 659 660 vfs_node_put(base); 1028 661 base = vfs_node_get(&base_lr); 1029 662 old[shared] = '/'; 1030 663 old += shared; 1031 664 new += shared; 1032 } else { 1033 vfs_node_addref(base); 1034 } 1035 1036 1037 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, &new_lr_orig); 665 } 666 667 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, 668 &new_lr_orig); 1038 669 if (rc == EOK) { 1039 670 orig_unlinked = true; … … 1044 675 } 1045 676 1046 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, &old_lr); 677 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, 678 &old_lr); 1047 679 if (rc != EOK) { 1048 680 if (orig_unlinked) { … … 1075 707 } 1076 708 1077 void vfs_rename(ipc_callid_t rid, ipc_call_t *request) 1078 { 1079 /* The common base directory. */ 1080 int basefd; 1081 char *old = NULL; 1082 char *new = NULL; 1083 vfs_file_t *base = NULL; 1084 int rc; 1085 1086 basefd = IPC_GET_ARG1(*request); 1087 1088 /* Retrieve the old path. */ 1089 rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL); 1090 if (rc != EOK) { 1091 goto out; 1092 } 1093 1094 /* Retrieve the new path. */ 1095 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL); 1096 if (rc != EOK) { 1097 goto out; 1098 } 1099 1100 size_t olen; 1101 size_t nlen; 1102 char *oldc = canonify(old, &olen); 1103 char *newc = canonify(new, &nlen); 1104 1105 if ((!oldc) || (!newc)) { 1106 rc = EINVAL; 1107 goto out; 1108 } 1109 1110 assert(oldc[olen] == '\0'); 1111 assert(newc[nlen] == '\0'); 1112 1113 /* Lookup the file structure corresponding to the file descriptor. */ 1114 base = vfs_file_get(basefd); 1115 if (!base) { 1116 rc = EBADF; 1117 goto out; 1118 } 1119 1120 rc = vfs_rename_internal(base->node, oldc, newc); 1121 1122 out: 1123 async_answer_0(rid, rc); 1124 1125 if (old) { 1126 free(old); 1127 } 1128 if (new) { 1129 free(new); 1130 } 1131 if (base) { 1132 vfs_file_put(base); 1133 } 1134 } 1135 1136 void vfs_dup(ipc_callid_t rid, ipc_call_t *request) 1137 { 1138 int oldfd = IPC_GET_ARG1(*request); 1139 int newfd = IPC_GET_ARG2(*request); 1140 1141 /* If the file descriptors are the same, do nothing. */ 1142 if (oldfd == newfd) { 1143 async_answer_1(rid, EOK, newfd); 1144 return; 1145 } 1146 1147 /* Lookup the file structure corresponding to oldfd. */ 1148 vfs_file_t *oldfile = vfs_file_get(oldfd); 1149 if (!oldfile) { 1150 async_answer_0(rid, EBADF); 1151 return; 1152 } 1153 1154 /* Make sure newfd is closed. */ 1155 (void) vfs_fd_free(newfd); 1156 1157 /* Assign the old file to newfd. */ 1158 int ret = vfs_fd_assign(oldfile, newfd); 1159 vfs_file_put(oldfile); 1160 1161 if (ret != EOK) 1162 async_answer_0(rid, ret); 1163 else 1164 async_answer_1(rid, EOK, newfd); 1165 } 1166 1167 void vfs_wait_handle(ipc_callid_t rid, ipc_call_t *request) 1168 { 1169 bool high_fd = IPC_GET_ARG1(*request); 1170 int fd = vfs_wait_handle_internal(high_fd); 1171 async_answer_1(rid, EOK, fd); 1172 } 1173 1174 void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request) 709 int vfs_op_seek(int fd, int64_t offset, int whence, int64_t *out_offset) 710 { 711 vfs_file_t *file = vfs_file_get(fd); 712 if (!file) { 713 return EBADF; 714 } 715 716 switch (whence) { 717 case SEEK_SET: 718 if (offset < 0) { 719 vfs_file_put(file); 720 return EINVAL; 721 } 722 file->pos = offset; 723 *out_offset = offset; 724 vfs_file_put(file); 725 return EOK; 726 case SEEK_CUR: 727 if (offset > 0 && file->pos > (INT64_MAX - offset)) { 728 vfs_file_put(file); 729 return EOVERFLOW; 730 } 731 732 if (offset < 0 && -file->pos > offset) { 733 vfs_file_put(file); 734 return EOVERFLOW; 735 } 736 737 file->pos += offset; 738 *out_offset = file->pos; 739 vfs_file_put(file); 740 return EOK; 741 case SEEK_END: 742 fibril_rwlock_read_lock(&file->node->contents_rwlock); 743 int64_t size = vfs_node_get_size(file->node); 744 fibril_rwlock_read_unlock(&file->node->contents_rwlock); 745 746 if (offset > 0 && size > (INT64_MAX - offset)) { 747 vfs_file_put(file); 748 return EOVERFLOW; 749 } 750 751 if (offset < 0 && -size > offset) { 752 vfs_file_put(file); 753 return EOVERFLOW; 754 } 755 756 file->pos = size + offset; 757 *out_offset = file->pos; 758 vfs_file_put(file); 759 return EOK; 760 } 761 762 vfs_file_put(file); 763 return EINVAL; 764 } 765 766 int vfs_op_statfs(int fd) 1175 767 { 1176 768 ipc_callid_t callid; 1177 ipc_call_t data; 1178 sysarg_t rc = EOK; 1179 size_t len; 1180 1181 fibril_mutex_lock(&mtab_list_lock); 1182 1183 /* Send to the caller the number of mounted filesystems */ 1184 callid = async_get_call(&data); 1185 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 1186 rc = ENOTSUP; 1187 async_answer_0(callid, rc); 1188 goto exit; 1189 } 1190 async_answer_1(callid, EOK, mtab_size); 1191 1192 list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) { 1193 rc = ENOTSUP; 1194 1195 if (!async_data_read_receive(&callid, &len)) { 1196 async_answer_0(callid, rc); 1197 goto exit; 1198 } 1199 1200 (void) async_data_read_finalize(callid, mtab_ent->mp, 1201 str_size(mtab_ent->mp)); 1202 1203 if (!async_data_read_receive(&callid, &len)) { 1204 async_answer_0(callid, rc); 1205 goto exit; 1206 } 1207 1208 (void) async_data_read_finalize(callid, mtab_ent->opts, 1209 str_size(mtab_ent->opts)); 1210 1211 if (!async_data_read_receive(&callid, &len)) { 1212 async_answer_0(callid, rc); 1213 goto exit; 1214 } 1215 1216 (void) async_data_read_finalize(callid, mtab_ent->fs_name, 1217 str_size(mtab_ent->fs_name)); 1218 1219 callid = async_get_call(&data); 1220 1221 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) { 1222 async_answer_0(callid, rc); 1223 goto exit; 1224 } 1225 1226 rc = EOK; 1227 async_answer_2(callid, rc, mtab_ent->instance, 1228 mtab_ent->service_id); 1229 } 1230 1231 exit: 1232 fibril_mutex_unlock(&mtab_list_lock); 1233 async_answer_0(rid, rc); 1234 } 1235 1236 void vfs_statfs(ipc_callid_t rid, ipc_call_t *request) 1237 { 1238 int fd = IPC_GET_ARG1(*request); 1239 1240 ipc_callid_t callid; 769 1241 770 if (!async_data_read_receive(&callid, NULL)) { 1242 771 async_answer_0(callid, EINVAL); 1243 async_answer_0(rid, EINVAL); 1244 return; 772 return EINVAL; 1245 773 } 1246 774 … … 1248 776 if (!file) { 1249 777 async_answer_0(callid, EBADF); 1250 async_answer_0(rid, EBADF);778 return EBADF; 1251 779 } 1252 780 … … 1254 782 1255 783 async_exch_t *exch = vfs_exchange_grab(node->fs_handle); 1256 784 1257 785 aid_t msg; 1258 786 msg = async_send_3(exch, VFS_OUT_STATFS, node->service_id, 1259 787 node->index, false, NULL); 1260 788 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME); 1261 789 1262 790 vfs_exchange_release(exch); 1263 791 1264 792 sysarg_t rv; 1265 793 async_wait_for(msg, &rv); 1266 794 1267 795 vfs_file_put(file); 1268 1269 async_answer_0(rid, rv); 1270 } 1271 1272 void vfs_op_clone(ipc_callid_t rid, ipc_call_t *request) 1273 { 1274 int oldfd = IPC_GET_ARG1(*request); 1275 bool desc = IPC_GET_ARG2(*request); 1276 1277 /* Lookup the file structure corresponding to fd. */ 1278 vfs_file_t *oldfile = vfs_file_get(oldfd); 1279 if (oldfile == NULL) { 1280 async_answer_0(rid, EBADF); 1281 return; 1282 } 1283 1284 vfs_file_t *newfile; 1285 int newfd = vfs_fd_alloc(&newfile, desc); 1286 async_answer_0(rid, newfd); 1287 1288 if (newfd < 0) { 1289 vfs_file_put(oldfile); 1290 return; 1291 } 1292 1293 assert(oldfile->node != NULL); 1294 1295 newfile->node = oldfile->node; 1296 newfile->permissions = oldfile->permissions; 1297 vfs_node_addref(newfile->node); 1298 1299 vfs_file_put(oldfile); 1300 vfs_file_put(newfile); 796 return rv; 797 } 798 799 int vfs_op_sync(int fd) 800 { 801 vfs_file_t *file = vfs_file_get(fd); 802 if (!file) { 803 return EBADF; 804 } 805 806 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle); 807 808 aid_t msg; 809 ipc_call_t answer; 810 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id, 811 file->node->index, &answer); 812 813 vfs_exchange_release(fs_exch); 814 815 sysarg_t rc; 816 async_wait_for(msg, &rc); 817 818 vfs_file_put(file); 819 return rc; 820 821 } 822 823 static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id, 824 fs_index_t index, aoff64_t size) 825 { 826 async_exch_t *exch = vfs_exchange_grab(fs_handle); 827 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE, 828 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size), 829 UPPER32(size)); 830 vfs_exchange_release(exch); 831 832 return (int) rc; 833 } 834 835 int vfs_op_truncate(int fd, int64_t size) 836 { 837 vfs_file_t *file = vfs_file_get(fd); 838 if (!file) { 839 return EBADF; 840 } 841 842 fibril_rwlock_write_lock(&file->node->contents_rwlock); 843 844 int rc = vfs_truncate_internal(file->node->fs_handle, 845 file->node->service_id, file->node->index, size); 846 if (rc == EOK) { 847 file->node->size = size; 848 } 849 850 fibril_rwlock_write_unlock(&file->node->contents_rwlock); 851 vfs_file_put(file); 852 return rc; 853 } 854 855 int vfs_op_unlink2(int parentfd, int expectfd, int wflag, char *path) 856 { 857 int rc = EOK; 858 vfs_file_t *parent = NULL; 859 vfs_file_t *expect = NULL; 860 861 if (parentfd == expectfd) { 862 return EINVAL; 863 } 864 865 fibril_rwlock_write_lock(&namespace_rwlock); 866 867 int lflag = (wflag&WALK_DIRECTORY) ? L_DIRECTORY: 0; 868 869 /* 870 * Files are retrieved in order of file descriptors, to prevent 871 * deadlock. 872 */ 873 if (parentfd < expectfd) { 874 parent = vfs_file_get(parentfd); 875 if (!parent) { 876 rc = EBADF; 877 goto exit; 878 } 879 } 880 881 if (expectfd >= 0) { 882 expect = vfs_file_get(expectfd); 883 if (!expect) { 884 rc = EBADF; 885 goto exit; 886 } 887 } 888 889 if (parentfd > expectfd) { 890 parent = vfs_file_get(parentfd); 891 if (!parent) { 892 rc = EBADF; 893 goto exit; 894 } 895 } 896 897 assert(parent != NULL); 898 899 if (expectfd >= 0) { 900 vfs_lookup_res_t lr; 901 rc = vfs_lookup_internal(parent->node, path, lflag, &lr); 902 if (rc != EOK) { 903 goto exit; 904 } 905 906 vfs_node_t *found_node = vfs_node_peek(&lr); 907 if (expect->node != found_node) { 908 rc = ENOENT; 909 goto exit; 910 } 911 912 vfs_file_put(expect); 913 expect = NULL; 914 } 915 916 vfs_lookup_res_t lr; 917 rc = vfs_lookup_internal(parent->node, path, lflag | L_UNLINK, &lr); 918 if (rc != EOK) { 919 goto exit; 920 } 921 922 /* If the node is not held by anyone, try to destroy it. */ 923 if (vfs_node_peek(&lr) == NULL) { 924 out_destroy(&lr.triplet); 925 } 926 927 exit: 928 if (path) { 929 free(path); 930 } 931 if (parent) { 932 vfs_file_put(parent); 933 } 934 if (expect) { 935 vfs_file_put(expect); 936 } 937 fibril_rwlock_write_unlock(&namespace_rwlock); 938 return rc; 939 } 940 941 int vfs_op_unmount(int mpfd) 942 { 943 vfs_file_t *mp = vfs_file_get(mpfd); 944 if (mp == NULL) { 945 return EBADF; 946 } 947 948 if (mp->node->mount == NULL) { 949 vfs_file_put(mp); 950 return ENOENT; 951 } 952 953 fibril_rwlock_write_lock(&namespace_rwlock); 954 955 /* 956 * Count the total number of references for the mounted file system. We 957 * are expecting at least one, which is held by the mount point. 958 * If we find more, it means that 959 * the file system cannot be gracefully unmounted at the moment because 960 * someone is working with it. 961 */ 962 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle, 963 mp->node->mount->service_id) != 1) { 964 vfs_file_put(mp); 965 fibril_rwlock_write_unlock(&namespace_rwlock); 966 return EBUSY; 967 } 968 969 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle); 970 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, 971 mp->node->mount->service_id); 972 vfs_exchange_release(exch); 973 974 if (rc != EOK) { 975 vfs_file_put(mp); 976 fibril_rwlock_write_unlock(&namespace_rwlock); 977 return rc; 978 } 979 980 vfs_node_forget(mp->node->mount); 981 vfs_node_put(mp->node); 982 mp->node->mount = NULL; 983 984 fibril_rwlock_write_unlock(&namespace_rwlock); 985 986 fibril_mutex_lock(&mtab_list_lock); 987 int found = 0; 988 989 list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) { 990 // FIXME: mp name 991 if (str_cmp(mtab_ent->mp, "fixme") == 0) { 992 list_remove(&mtab_ent->link); 993 mtab_size--; 994 free(mtab_ent); 995 found = 1; 996 break; 997 } 998 } 999 assert(found); 1000 fibril_mutex_unlock(&mtab_list_lock); 1001 1002 vfs_file_put(mp); 1003 return EOK; 1004 } 1005 1006 int vfs_op_wait_handle(bool high_fd) 1007 { 1008 return vfs_wait_handle_internal(high_fd); 1009 } 1010 1011 static inline bool walk_flags_valid(int flags) 1012 { 1013 if ((flags&~WALK_ALL_FLAGS) != 0) { 1014 return false; 1015 } 1016 if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) { 1017 return false; 1018 } 1019 if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) { 1020 return false; 1021 } 1022 if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) { 1023 if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) { 1024 return false; 1025 } 1026 } 1027 return true; 1028 } 1029 1030 static inline int walk_lookup_flags(int flags) 1031 { 1032 int lflags = 0; 1033 if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) { 1034 lflags |= L_CREATE; 1035 } 1036 if (flags&WALK_MUST_CREATE) { 1037 lflags |= L_EXCLUSIVE; 1038 } 1039 if (flags&WALK_REGULAR) { 1040 lflags |= L_FILE; 1041 } 1042 if (flags&WALK_DIRECTORY) { 1043 lflags |= L_DIRECTORY; 1044 } 1045 if (flags&WALK_MOUNT_POINT) { 1046 lflags |= L_MP; 1047 } 1048 return lflags; 1049 } 1050 1051 int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd) 1052 { 1053 if (!walk_flags_valid(flags)) { 1054 return EINVAL; 1055 } 1056 1057 vfs_file_t *parent = vfs_file_get(parentfd); 1058 if (!parent) { 1059 return EBADF; 1060 } 1061 1062 fibril_rwlock_read_lock(&namespace_rwlock); 1063 1064 vfs_lookup_res_t lr; 1065 int rc = vfs_lookup_internal(parent->node, path, 1066 walk_lookup_flags(flags), &lr); 1067 1068 if (rc != EOK) { 1069 fibril_rwlock_read_unlock(&namespace_rwlock); 1070 vfs_file_put(parent); 1071 return rc; 1072 } 1073 1074 vfs_node_t *node = vfs_node_get(&lr); 1075 1076 vfs_file_t *file; 1077 int fd = vfs_fd_alloc(&file, false); 1078 if (fd < 0) { 1079 vfs_node_put(node); 1080 vfs_file_put(parent); 1081 return fd; 1082 } 1083 assert(file != NULL); 1084 1085 file->node = node; 1086 file->permissions = parent->permissions; 1087 file->open_read = false; 1088 file->open_write = false; 1089 1090 vfs_file_put(file); 1091 vfs_file_put(parent); 1092 1093 fibril_rwlock_read_unlock(&namespace_rwlock); 1094 1095 *out_fd = fd; 1096 return EOK; 1097 } 1098 1099 int vfs_op_write(int fd, size_t *out_bytes) 1100 { 1101 return vfs_rdwr(fd, false, rdwr_ipc_client, out_bytes); 1301 1102 } 1302 1103
Note:
See TracChangeset
for help on using the changeset viewer.