Changeset 3ba431a in mainline
- Timestamp:
- 2017-04-03T20:39:12Z (8 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 2c40637
- Parents:
- ca7506f
- Location:
- uspace/lib/c
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/vfs/vfs.c
rca7506f r3ba431a 126 126 static int root_fd = -1; 127 127 128 /** Return a new file handle representing the local root 129 * 130 * @return A clone of the local root file handle or a negative error code 131 */ 132 int vfs_root(void) 133 { 134 fibril_mutex_lock(&root_mutex); 135 int r; 136 if (root_fd < 0) 137 r = ENOENT; 138 else 139 r = vfs_clone(root_fd, -1, true); 140 fibril_mutex_unlock(&root_mutex); 141 return r; 142 } 143 144 /** Set a new local root 145 * 146 * Note that it is still possible to have file handles for other roots and pass 147 * them to the API functions. Functions like vfs_root() and vfs_lookup() will 148 * however consider the file set by this function to be the root. 149 * 150 * @param nroot The new local root file handle 151 */ 152 153 void vfs_root_set(int nroot) 154 { 155 fibril_mutex_lock(&root_mutex); 156 if (root_fd >= 0) 157 vfs_put(root_fd); 158 root_fd = vfs_clone(nroot, -1, true); 159 fibril_mutex_unlock(&root_mutex); 160 } 161 162 /** Start an async exchange on the VFS session 163 * 164 * @return New exchange 165 */ 166 async_exch_t *vfs_exchange_begin(void) 167 { 168 fibril_mutex_lock(&vfs_mutex); 169 170 while (vfs_sess == NULL) { 171 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS, 172 0); 173 } 174 175 fibril_mutex_unlock(&vfs_mutex); 176 177 return async_exchange_begin(vfs_sess); 178 } 179 180 /** Finish an async exchange on the VFS session 181 * 182 * @param exch Exchange to be finished 183 */ 184 void vfs_exchange_end(async_exch_t *exch) 185 { 186 async_exchange_end(exch); 187 } 188 189 /** Walk a path starting in a parent node 190 * 191 * @param parent File handle of the parent node where the walk starts 192 * @param path Parent-relative path to be walked 193 * @param flags Flags influencing the walk 194 * 195 * @retrun File handle representing the result on success or 196 * a negative error code on error 197 */ 198 int vfs_walk(int parent, const char *path, int flags) 199 { 200 async_exch_t *exch = vfs_exchange_begin(); 201 202 ipc_call_t answer; 203 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer); 204 sysarg_t rc = async_data_write_start(exch, path, str_size(path)); 205 vfs_exchange_end(exch); 206 207 sysarg_t rc_orig; 208 async_wait_for(req, &rc_orig); 209 210 if (rc_orig != EOK) 211 return (int) rc_orig; 212 213 if (rc != EOK) 214 return (int) rc; 215 216 return (int) IPC_GET_ARG1(answer); 217 } 218 219 /** Lookup a path relative to the local root 220 * 221 * @param path Path to be looked up 222 * @param flags Walk flags 223 * 224 * @return File handle representing the result on success or a negative 225 * error code on error 226 */ 227 int vfs_lookup(const char *path, int flags) 128 static int get_parent_and_child(const char *path, char **child) 228 129 { 229 130 size_t size; 230 char * p= vfs_absolutize(path, &size);231 if (! p)131 char *apath = vfs_absolutize(path, &size); 132 if (!apath) 232 133 return ENOMEM; 233 int root = vfs_root(); 234 if (root < 0) { 235 free(p); 236 return ENOENT; 237 } 238 int rc = vfs_walk(root, p, flags); 239 vfs_put(root); 240 free(p); 241 return rc; 242 } 243 244 /** Open a file handle for I/O 245 * 246 * @param file File handle to enable I/O on 247 * @param mode Mode in which to open file in 248 * 249 * @return EOK on success or a negative error code 250 */ 251 int vfs_open(int file, int mode) 252 { 253 async_exch_t *exch = vfs_exchange_begin(); 254 int rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode); 255 vfs_exchange_end(exch); 256 257 return rc; 258 } 259 260 /** Lookup a path relative to the local root and open the result 261 * 262 * This function is a convenience combo for vfs_lookup() and vfs_open(). 263 * 264 * @param path Path to be looked up 265 * @param flags Walk flags 266 * @param mode Mode in which to open file in 267 * 268 * @return EOK on success or a negative error code 269 */ 270 int vfs_lookup_open(const char *path, int flags, int mode) 271 { 272 int file = vfs_lookup(path, flags); 273 if (file < 0) 274 return file; 275 276 int rc = vfs_open(file, mode); 277 if (rc != EOK) { 278 vfs_put(file); 279 return rc; 280 } 281 282 return file; 134 135 char *slash = str_rchr(apath, L'/'); 136 int parent; 137 if (slash == apath) { 138 parent = vfs_root(); 139 *child = apath; 140 } else { 141 *slash = '\0'; 142 parent = vfs_lookup(apath, WALK_DIRECTORY); 143 if (parent < 0) { 144 free(apath); 145 return parent; 146 } 147 *slash = '/'; 148 *child = str_dup(slash); 149 free(apath); 150 if (!*child) { 151 vfs_put(parent); 152 return ENOMEM; 153 } 154 } 155 156 return parent; 283 157 } 284 158 … … 344 218 } 345 219 220 /** Clone a file handle 221 * 222 * The caller can choose whether to clone an existing file handle into another 223 * already existing file handle (in which case it is first closed) or to a new 224 * file handle allocated either from low or high indices. 225 * 226 * @param file_from Source file handle 227 * @param file_to Destination file handle or -1 228 * @param high If file_to is -1, high controls whether the new file 229 * handle will be allocated from high indices 230 * 231 * @return New file handle on success or a negative error code 232 */ 233 int vfs_clone(int file_from, int file_to, bool high) 234 { 235 async_exch_t *vfs_exch = vfs_exchange_begin(); 236 int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from, 237 (sysarg_t) file_to, (sysarg_t) high); 238 vfs_exchange_end(vfs_exch); 239 return rc; 240 } 241 242 /** Get current working directory path 243 * 244 * @param[out] buf Buffer 245 * @param size Size of @a buf 246 * 247 * @return EOK on success or a non-negative error code 248 */ 249 int vfs_cwd_get(char *buf, size_t size) 250 { 251 fibril_mutex_lock(&cwd_mutex); 252 253 if ((cwd_size == 0) || (size < cwd_size + 1)) { 254 fibril_mutex_unlock(&cwd_mutex); 255 return ERANGE; 256 } 257 258 str_cpy(buf, size, cwd_path); 259 fibril_mutex_unlock(&cwd_mutex); 260 261 return EOK; 262 } 263 264 /** Change working directory 265 * 266 * @param path Path of the new working directory 267 * 268 * @return EOK on success or a negative error code 269 */ 270 int vfs_cwd_set(const char *path) 271 { 272 size_t abs_size; 273 char *abs = vfs_absolutize(path, &abs_size); 274 if (!abs) 275 return ENOMEM; 276 277 int fd = vfs_lookup(abs, WALK_DIRECTORY); 278 if (fd < 0) { 279 free(abs); 280 return fd; 281 } 282 283 fibril_mutex_lock(&cwd_mutex); 284 285 if (cwd_fd >= 0) 286 vfs_put(cwd_fd); 287 288 if (cwd_path) 289 free(cwd_path); 290 291 cwd_fd = fd; 292 cwd_path = abs; 293 cwd_size = abs_size; 294 295 fibril_mutex_unlock(&cwd_mutex); 296 return EOK; 297 } 298 299 /** Start an async exchange on the VFS session 300 * 301 * @return New exchange 302 */ 303 async_exch_t *vfs_exchange_begin(void) 304 { 305 fibril_mutex_lock(&vfs_mutex); 306 307 while (vfs_sess == NULL) { 308 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS, 309 0); 310 } 311 312 fibril_mutex_unlock(&vfs_mutex); 313 314 return async_exchange_begin(vfs_sess); 315 } 316 317 /** Finish an async exchange on the VFS session 318 * 319 * @param exch Exchange to be finished 320 */ 321 void vfs_exchange_end(async_exch_t *exch) 322 { 323 async_exchange_end(exch); 324 } 325 326 /** Open session to service represented by a special file 327 * 328 * Given that the file referred to by @a file represents a service, 329 * open a session to that service. 330 * 331 * @param file File handle representing a service 332 * @param iface Interface to connect to (XXX Should be automatic) 333 * 334 * @return Session pointer on success. 335 * @return @c NULL or error. 336 */ 337 async_sess_t *vfs_fd_session(int file, iface_t iface) 338 { 339 struct stat stat; 340 int rc = vfs_stat(file, &stat); 341 if (rc != 0) 342 return NULL; 343 344 if (stat.service == 0) 345 return NULL; 346 347 return loc_service_connect(stat.service, iface, 0); 348 } 349 350 /** Link a file or directory 351 * 352 * Create a new name and an empty file or an empty directory in a parent 353 * directory. If child with the same name already exists, the function returns 354 * a failure, the existing file remains untouched and no file system object 355 * is created. 356 * 357 * @param parent File handle of the parent directory node 358 * @param child New name to be linked 359 * @param kind Kind of the object to be created: KIND_FILE or 360 * KIND_DIRECTORY 361 * @return EOK on success or a negative error code 362 */ 363 int vfs_link(int parent, const char *child, vfs_file_kind_t kind) 364 { 365 int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR; 366 int file = vfs_walk(parent, child, WALK_MUST_CREATE | flags); 367 368 if (file < 0) 369 return file; 370 371 vfs_put(file); 372 373 return EOK; 374 } 375 376 /** Link a file or directory 377 * 378 * Create a new name and an empty file or an empty directory at given path. 379 * If a link with the same name already exists, the function returns 380 * a failure, the existing file remains untouched and no file system object 381 * is created. 382 * 383 * @param path New path to be linked 384 * @param kind Kind of the object to be created: KIND_FILE or 385 * KIND_DIRECTORY 386 * @return EOK on success or a negative error code 387 */ 388 int vfs_link_path(const char *path, vfs_file_kind_t kind) 389 { 390 char *child; 391 int parent = get_parent_and_child(path, &child); 392 if (parent < 0) 393 return parent; 394 395 int rc = vfs_link(parent, child, kind); 396 397 free(child); 398 vfs_put(parent); 399 return rc; 400 } 401 402 /** Lookup a path relative to the local root 403 * 404 * @param path Path to be looked up 405 * @param flags Walk flags 406 * 407 * @return File handle representing the result on success or a negative 408 * error code on error 409 */ 410 int vfs_lookup(const char *path, int flags) 411 { 412 size_t size; 413 char *p = vfs_absolutize(path, &size); 414 if (!p) 415 return ENOMEM; 416 int root = vfs_root(); 417 if (root < 0) { 418 free(p); 419 return ENOENT; 420 } 421 int rc = vfs_walk(root, p, flags); 422 vfs_put(root); 423 free(p); 424 return rc; 425 } 426 427 /** Lookup a path relative to the local root and open the result 428 * 429 * This function is a convenience combo for vfs_lookup() and vfs_open(). 430 * 431 * @param path Path to be looked up 432 * @param flags Walk flags 433 * @param mode Mode in which to open file in 434 * 435 * @return EOK on success or a negative error code 436 */ 437 int vfs_lookup_open(const char *path, int flags, int mode) 438 { 439 int file = vfs_lookup(path, flags); 440 if (file < 0) 441 return file; 442 443 int rc = vfs_open(file, mode); 444 if (rc != EOK) { 445 vfs_put(file); 446 return rc; 447 } 448 449 return file; 450 } 451 346 452 /** Mount a file system 347 453 * … … 387 493 return rc; 388 494 return rc1; 389 }390 391 /** Unmount a file system392 *393 * @param mp File handle representing the mount-point394 *395 * @return EOK on success or a negative error code396 */397 int vfs_unmount(int mp)398 {399 async_exch_t *exch = vfs_exchange_begin();400 int rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp);401 vfs_exchange_end(exch);402 return rc;403 495 } 404 496 … … 501 593 } 502 594 503 /** Unmount a file system 504 * 505 * @param mpp Mount-point path 595 596 /** Open a file handle for I/O 597 * 598 * @param file File handle to enable I/O on 599 * @param mode Mode in which to open file in 506 600 * 507 601 * @return EOK on success or a negative error code 508 602 */ 509 int vfs_unmount_path(const char *mpp) 510 { 511 int mp = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY); 512 if (mp < 0) 513 return mp; 514 515 int rc = vfs_unmount(mp); 516 vfs_put(mp); 517 return rc; 603 int vfs_open(int file, int mode) 604 { 605 async_exch_t *exch = vfs_exchange_begin(); 606 int rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode); 607 vfs_exchange_end(exch); 608 609 return rc; 610 } 611 612 /** Pass a file handle to another VFS client 613 * 614 * @param vfs_exch Donor's VFS exchange 615 * @param file Donor's file handle to pass 616 * @param exch Exchange to the acceptor 617 * 618 * @return EOK on success or a negative error code 619 */ 620 int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch) 621 { 622 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file, 623 0, vfs_exch); 518 624 } 519 625 … … 533 639 } 534 640 535 /** Read bytes from a file 536 * 537 * Read up to @a nbyte bytes from file. The actual number of bytes read 538 * may be lower, but greater than zero if there are any bytes available. 539 * If there are no bytes available for reading, then the function will 540 * return success with zero bytes read. 541 * 542 * @param file File handle to read from 543 * @param[in] pos Position to read from 544 * @param buf Buffer to read from 545 * @param nbyte Maximum number of bytes to read 546 * @param[out] nread Actual number of bytes read (0 or more) 547 * 548 * @return EOK on success or a negative error code 549 */ 550 int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte, 551 ssize_t *nread) 552 { 553 sysarg_t rc; 554 ipc_call_t answer; 555 aid_t req; 556 557 if (nbyte > DATA_XFER_LIMIT) 558 nbyte = DATA_XFER_LIMIT; 559 560 async_exch_t *exch = vfs_exchange_begin(); 561 562 req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos), 563 UPPER32(pos), &answer); 564 rc = async_data_read_start(exch, (void *) buf, nbyte); 565 566 vfs_exchange_end(exch); 567 568 if (rc == EOK) 569 async_wait_for(req, &rc); 570 else 571 async_forget(req); 572 641 /** Receive a file handle from another VFS client 642 * 643 * @param high If true, the received file handle will be allocated from high 644 * indices 645 * 646 * @return EOK on success or a negative error code 647 */ 648 int vfs_receive_handle(bool high) 649 { 650 ipc_callid_t callid; 651 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) { 652 async_answer_0(callid, EINVAL); 653 return EINVAL; 654 } 655 656 async_exch_t *vfs_exch = vfs_exchange_begin(); 657 658 async_state_change_finalize(callid, vfs_exch); 659 660 sysarg_t ret; 661 sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret); 662 663 async_exchange_end(vfs_exch); 664 573 665 if (rc != EOK) 574 666 return rc; 575 576 *nread = (ssize_t) IPC_GET_ARG1(answer); 577 return EOK; 578 } 579 580 /** Write bytes to a file 581 * 582 * Write up to @a nbyte bytes from file. The actual number of bytes written 583 * may be lower, but greater than zero. 584 * 585 * @param file File handle to write to 586 * @param[in] pos Position to write to 587 * @param buf Buffer to write to 588 * @param nbyte Maximum number of bytes to write 589 * @param[out] nread Actual number of bytes written (0 or more) 590 * 591 * @return EOK on success or a negative error code 592 */ 593 int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte, 594 ssize_t *nwritten) 595 { 596 sysarg_t rc; 597 ipc_call_t answer; 598 aid_t req; 599 600 if (nbyte > DATA_XFER_LIMIT) 601 nbyte = DATA_XFER_LIMIT; 602 603 async_exch_t *exch = vfs_exchange_begin(); 604 605 req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos), 606 UPPER32(pos), &answer); 607 rc = async_data_write_start(exch, (void *) buf, nbyte); 608 609 vfs_exchange_end(exch); 610 611 if (rc == EOK) 612 async_wait_for(req, &rc); 613 else 614 async_forget(req); 615 616 if (rc != EOK) 617 return rc; 618 619 *nwritten = (ssize_t) IPC_GET_ARG1(answer); 620 return EOK; 667 return ret; 621 668 } 622 669 … … 655 702 } 656 703 657 /** Write data 658 * 659 * This function fails if it cannot write exactly @a len bytes to the file. 660 * 661 * @param file File handle to write to 662 * @param[inout] pos Position to write to, updated by the actual bytes 663 * written 664 * @param buf Data, @a nbytes bytes long 665 * @param nbytes Number of bytes to write 666 * 667 * @return On success, non-negative number of bytes written 668 * @return On failure, a negative error code 669 */ 670 ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte) 671 { 672 ssize_t cnt = 0; 673 ssize_t nwritten = 0; 674 const uint8_t *bp = (uint8_t *) buf; 675 int rc; 676 677 do { 678 bp += cnt; 679 nwritten += cnt; 680 *pos += cnt; 681 rc = vfs_write_short(file, *pos, bp, nbyte - nwritten, &cnt); 682 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0); 683 704 /** Read bytes from a file 705 * 706 * Read up to @a nbyte bytes from file. The actual number of bytes read 707 * may be lower, but greater than zero if there are any bytes available. 708 * If there are no bytes available for reading, then the function will 709 * return success with zero bytes read. 710 * 711 * @param file File handle to read from 712 * @param[in] pos Position to read from 713 * @param buf Buffer to read from 714 * @param nbyte Maximum number of bytes to read 715 * @param[out] nread Actual number of bytes read (0 or more) 716 * 717 * @return EOK on success or a negative error code 718 */ 719 int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte, 720 ssize_t *nread) 721 { 722 sysarg_t rc; 723 ipc_call_t answer; 724 aid_t req; 725 726 if (nbyte > DATA_XFER_LIMIT) 727 nbyte = DATA_XFER_LIMIT; 728 729 async_exch_t *exch = vfs_exchange_begin(); 730 731 req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos), 732 UPPER32(pos), &answer); 733 rc = async_data_read_start(exch, (void *) buf, nbyte); 734 735 vfs_exchange_end(exch); 736 737 if (rc == EOK) 738 async_wait_for(req, &rc); 739 else 740 async_forget(req); 741 684 742 if (rc != EOK) 685 743 return rc; 686 687 *pos += cnt; 688 return nbyte; 689 } 690 691 /** Synchronize file 692 * 693 * @param file File handle to synchronize 744 745 *nread = (ssize_t) IPC_GET_ARG1(answer); 746 return EOK; 747 } 748 749 /** Rename a file or directory 750 * 751 * There is no file-handle-based variant to disallow attempts to introduce loops 752 * and breakage in the directory tree when relinking eg. a node under its own 753 * descendant. The path-based variant is not susceptible because the VFS can 754 * prevent this lexically by comparing the paths. 755 * 756 * @param old Old path 757 * @param new New path 694 758 * 695 759 * @return EOK on success or a negative error code 696 760 */ 697 int vfs_sync(int file) 698 { 699 async_exch_t *exch = vfs_exchange_begin(); 700 int rc = async_req_1_0(exch, VFS_IN_SYNC, file); 701 vfs_exchange_end(exch); 702 761 int vfs_rename_path(const char *old, const char *new) 762 { 763 sysarg_t rc; 764 sysarg_t rc_orig; 765 aid_t req; 766 767 size_t olda_size; 768 char *olda = vfs_absolutize(old, &olda_size); 769 if (olda == NULL) 770 return ENOMEM; 771 772 size_t newa_size; 773 char *newa = vfs_absolutize(new, &newa_size); 774 if (newa == NULL) { 775 free(olda); 776 return ENOMEM; 777 } 778 779 async_exch_t *exch = vfs_exchange_begin(); 780 int root = vfs_root(); 781 if (root < 0) { 782 free(olda); 783 free(newa); 784 return ENOENT; 785 } 786 787 req = async_send_1(exch, VFS_IN_RENAME, root, NULL); 788 rc = async_data_write_start(exch, olda, olda_size); 789 if (rc != EOK) { 790 vfs_exchange_end(exch); 791 free(olda); 792 free(newa); 793 vfs_put(root); 794 async_wait_for(req, &rc_orig); 795 if (rc_orig != EOK) 796 rc = rc_orig; 797 return rc; 798 } 799 rc = async_data_write_start(exch, newa, newa_size); 800 if (rc != EOK) { 801 vfs_exchange_end(exch); 802 free(olda); 803 free(newa); 804 vfs_put(root); 805 async_wait_for(req, &rc_orig); 806 if (rc_orig != EOK) 807 rc = rc_orig; 808 return rc; 809 } 810 vfs_exchange_end(exch); 811 free(olda); 812 free(newa); 813 vfs_put(root); 814 async_wait_for(req, &rc); 815 703 816 return rc; 704 817 } … … 721 834 722 835 return rc; 836 } 837 838 /** Return a new file handle representing the local root 839 * 840 * @return A clone of the local root file handle or a negative error code 841 */ 842 int vfs_root(void) 843 { 844 fibril_mutex_lock(&root_mutex); 845 int r; 846 if (root_fd < 0) 847 r = ENOENT; 848 else 849 r = vfs_clone(root_fd, -1, true); 850 fibril_mutex_unlock(&root_mutex); 851 return r; 852 } 853 854 /** Set a new local root 855 * 856 * Note that it is still possible to have file handles for other roots and pass 857 * them to the API functions. Functions like vfs_root() and vfs_lookup() will 858 * however consider the file set by this function to be the root. 859 * 860 * @param nroot The new local root file handle 861 */ 862 void vfs_root_set(int nroot) 863 { 864 fibril_mutex_lock(&root_mutex); 865 if (root_fd >= 0) 866 vfs_put(root_fd); 867 root_fd = vfs_clone(nroot, -1, true); 868 fibril_mutex_unlock(&root_mutex); 723 869 } 724 870 … … 777 923 } 778 924 779 static int get_parent_and_child(const char *path, char **child) 780 { 781 size_t size; 782 char *apath = vfs_absolutize(path, &size); 783 if (!apath) 784 return ENOMEM; 785 786 char *slash = str_rchr(apath, L'/'); 787 int parent; 788 if (slash == apath) { 789 parent = vfs_root(); 790 *child = apath; 791 } else { 792 *slash = '\0'; 793 parent = vfs_lookup(apath, WALK_DIRECTORY); 794 if (parent < 0) { 795 free(apath); 796 return parent; 797 } 798 *slash = '/'; 799 *child = str_dup(slash); 800 free(apath); 801 if (!*child) { 802 vfs_put(parent); 803 return ENOMEM; 804 } 805 } 806 807 return parent; 808 } 809 810 /** Link a file or directory 811 * 812 * Create a new name and an empty file or an empty directory in a parent 813 * directory. If child with the same name already exists, the function returns 814 * a failure, the existing file remains untouched and no file system object 815 * is created. 816 * 817 * @param parent File handle of the parent directory node 818 * @param child New name to be linked 819 * @param kind Kind of the object to be created: KIND_FILE or 820 * KIND_DIRECTORY 925 /** Get filesystem statistics 926 * 927 * @param file File located on the queried file system 928 * @param[out] st Buffer for storing information 929 * 821 930 * @return EOK on success or a negative error code 822 931 */ 823 int vfs_link(int parent, const char *child, vfs_file_kind_t kind) 824 { 825 int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR; 826 int file = vfs_walk(parent, child, WALK_MUST_CREATE | flags); 827 932 int vfs_statfs(int file, struct statfs *st) 933 { 934 sysarg_t rc, ret; 935 aid_t req; 936 937 async_exch_t *exch = vfs_exchange_begin(); 938 939 req = async_send_1(exch, VFS_IN_STATFS, file, NULL); 940 rc = async_data_read_start(exch, (void *) st, sizeof(*st)); 941 942 vfs_exchange_end(exch); 943 async_wait_for(req, &ret); 944 945 rc = (ret != EOK ? ret : rc); 946 947 return rc; 948 } 949 950 /** Get filesystem statistics 951 * 952 * @param file Path pointing to the queried file system 953 * @param[out] st Buffer for storing information 954 * 955 * @return EOK on success or a negative error code 956 */ 957 int vfs_statfs_path(const char *path, struct statfs *st) 958 { 959 int file = vfs_lookup(path, 0); 828 960 if (file < 0) 829 961 return file; 962 963 int rc = vfs_statfs(file, st); 830 964 831 965 vfs_put(file); 832 966 833 return EOK; 834 } 835 836 /** Link a file or directory 837 * 838 * Create a new name and an empty file or an empty directory at given path. 839 * If a link with the same name already exists, the function returns 840 * a failure, the existing file remains untouched and no file system object 841 * is created. 842 * 843 * @param path New path to be linked 844 * @param kind Kind of the object to be created: KIND_FILE or 845 * KIND_DIRECTORY 846 * @return EOK on success or a negative error code 847 */ 848 int vfs_link_path(const char *path, vfs_file_kind_t kind) 849 { 850 char *child; 851 int parent = get_parent_and_child(path, &child); 852 if (parent < 0) 853 return parent; 854 855 int rc = vfs_link(parent, child, kind); 856 857 free(child); 858 vfs_put(parent); 859 return rc; 860 } 967 return rc; 968 } 969 970 /** Synchronize file 971 * 972 * @param file File handle to synchronize 973 * 974 * @return EOK on success or a negative error code 975 */ 976 int vfs_sync(int file) 977 { 978 async_exch_t *exch = vfs_exchange_begin(); 979 int rc = async_req_1_0(exch, VFS_IN_SYNC, file); 980 vfs_exchange_end(exch); 981 982 return rc; 983 } 861 984 862 985 /** Unlink a file or directory … … 923 1046 } 924 1047 925 /** Rename a file or directory 926 * 927 * There is no file-handle-based variant to disallow attempts to introduce loops 928 * and breakage in the directory tree when relinking eg. a node under its own 929 * descendant. The path-based variant is not susceptible because the VFS can 930 * prevent this lexically by comparing the paths. 931 * 932 * @param old Old path 933 * @param new New path 1048 /** Unmount a file system 1049 * 1050 * @param mp File handle representing the mount-point 934 1051 * 935 1052 * @return EOK on success or a negative error code 936 1053 */ 937 int vfs_rename_path(const char *old, const char *new) 938 { 939 sysarg_t rc; 1054 int vfs_unmount(int mp) 1055 { 1056 async_exch_t *exch = vfs_exchange_begin(); 1057 int rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp); 1058 vfs_exchange_end(exch); 1059 return rc; 1060 } 1061 1062 /** Unmount a file system 1063 * 1064 * @param mpp Mount-point path 1065 * 1066 * @return EOK on success or a negative error code 1067 */ 1068 int vfs_unmount_path(const char *mpp) 1069 { 1070 int mp = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY); 1071 if (mp < 0) 1072 return mp; 1073 1074 int rc = vfs_unmount(mp); 1075 vfs_put(mp); 1076 return rc; 1077 } 1078 1079 /** Walk a path starting in a parent node 1080 * 1081 * @param parent File handle of the parent node where the walk starts 1082 * @param path Parent-relative path to be walked 1083 * @param flags Flags influencing the walk 1084 * 1085 * @retrun File handle representing the result on success or 1086 * a negative error code on error 1087 */ 1088 int vfs_walk(int parent, const char *path, int flags) 1089 { 1090 async_exch_t *exch = vfs_exchange_begin(); 1091 1092 ipc_call_t answer; 1093 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer); 1094 sysarg_t rc = async_data_write_start(exch, path, str_size(path)); 1095 vfs_exchange_end(exch); 1096 940 1097 sysarg_t rc_orig; 941 aid_t req; 942 943 size_t olda_size; 944 char *olda = vfs_absolutize(old, &olda_size); 945 if (olda == NULL) 946 return ENOMEM; 947 948 size_t newa_size; 949 char *newa = vfs_absolutize(new, &newa_size); 950 if (newa == NULL) { 951 free(olda); 952 return ENOMEM; 953 } 954 955 async_exch_t *exch = vfs_exchange_begin(); 956 int root = vfs_root(); 957 if (root < 0) { 958 free(olda); 959 free(newa); 960 return ENOENT; 961 } 962 963 req = async_send_1(exch, VFS_IN_RENAME, root, NULL); 964 rc = async_data_write_start(exch, olda, olda_size); 965 if (rc != EOK) { 966 vfs_exchange_end(exch); 967 free(olda); 968 free(newa); 969 vfs_put(root); 970 async_wait_for(req, &rc_orig); 971 if (rc_orig != EOK) 972 rc = rc_orig; 973 return rc; 974 } 975 rc = async_data_write_start(exch, newa, newa_size); 976 if (rc != EOK) { 977 vfs_exchange_end(exch); 978 free(olda); 979 free(newa); 980 vfs_put(root); 981 async_wait_for(req, &rc_orig); 982 if (rc_orig != EOK) 983 rc = rc_orig; 984 return rc; 985 } 986 vfs_exchange_end(exch); 987 free(olda); 988 free(newa); 989 vfs_put(root); 990 async_wait_for(req, &rc); 991 992 return rc; 993 } 994 995 /** Change working directory 996 * 997 * @param path Path of the new working directory 998 * 999 * @return EOK on success or a negative error code 1000 */ 1001 int vfs_cwd_set(const char *path) 1002 { 1003 size_t abs_size; 1004 char *abs = vfs_absolutize(path, &abs_size); 1005 if (!abs) 1006 return ENOMEM; 1007 1008 int fd = vfs_lookup(abs, WALK_DIRECTORY); 1009 if (fd < 0) { 1010 free(abs); 1011 return fd; 1012 } 1013 1014 fibril_mutex_lock(&cwd_mutex); 1015 1016 if (cwd_fd >= 0) 1017 vfs_put(cwd_fd); 1018 1019 if (cwd_path) 1020 free(cwd_path); 1021 1022 cwd_fd = fd; 1023 cwd_path = abs; 1024 cwd_size = abs_size; 1025 1026 fibril_mutex_unlock(&cwd_mutex); 1027 return EOK; 1028 } 1029 1030 /** Get current working directory path 1031 * 1032 * @param[out] buf Buffer 1033 * @param size Size of @a buf 1034 * 1035 * @return EOK on success or a non-negative error code 1036 */ 1037 int vfs_cwd_get(char *buf, size_t size) 1038 { 1039 fibril_mutex_lock(&cwd_mutex); 1040 1041 if ((cwd_size == 0) || (size < cwd_size + 1)) { 1042 fibril_mutex_unlock(&cwd_mutex); 1043 return ERANGE; 1044 } 1045 1046 str_cpy(buf, size, cwd_path); 1047 fibril_mutex_unlock(&cwd_mutex); 1048 1049 return EOK; 1050 } 1051 1052 /** Open session to service represented by a special file 1053 * 1054 * Given that the file referred to by @a file represents a service, 1055 * open a session to that service. 1056 * 1057 * @param file File handle representing a service 1058 * @param iface Interface to connect to (XXX Should be automatic) 1059 * 1060 * @return Session pointer on success. 1061 * @return @c NULL or error. 1062 */ 1063 async_sess_t *vfs_fd_session(int file, iface_t iface) 1064 { 1065 struct stat stat; 1066 int rc = vfs_stat(file, &stat); 1067 if (rc != 0) 1068 return NULL; 1069 1070 if (stat.service == 0) 1071 return NULL; 1072 1073 return loc_service_connect(stat.service, iface, 0); 1074 } 1075 1076 /** Get filesystem statistics 1077 * 1078 * @param file File located on the queried file system 1079 * @param[out] st Buffer for storing information 1080 * 1081 * @return EOK on success or a negative error code 1082 */ 1083 int vfs_statfs(int file, struct statfs *st) 1084 { 1085 sysarg_t rc, ret; 1086 aid_t req; 1087 1088 async_exch_t *exch = vfs_exchange_begin(); 1089 1090 req = async_send_1(exch, VFS_IN_STATFS, file, NULL); 1091 rc = async_data_read_start(exch, (void *) st, sizeof(*st)); 1092 1093 vfs_exchange_end(exch); 1094 async_wait_for(req, &ret); 1095 1096 rc = (ret != EOK ? ret : rc); 1097 1098 return rc; 1099 } 1100 1101 /** Get filesystem statistics 1102 * 1103 * @param file Path pointing to the queried file system 1104 * @param[out] st Buffer for storing information 1105 * 1106 * @return EOK on success or a negative error code 1107 */ 1108 int vfs_statfs_path(const char *path, struct statfs *st) 1109 { 1110 int file = vfs_lookup(path, 0); 1111 if (file < 0) 1112 return file; 1113 1114 int rc = vfs_statfs(file, st); 1115 1116 vfs_put(file); 1117 1118 return rc; 1119 } 1120 1121 /** Pass a file handle to another VFS client 1122 * 1123 * @param vfs_exch Donor's VFS exchange 1124 * @param file Donor's file handle to pass 1125 * @param exch Exchange to the acceptor 1126 * 1127 * @return EOK on success or a negative error code 1128 */ 1129 int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch) 1130 { 1131 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file, 1132 0, vfs_exch); 1133 } 1134 1135 /** Receive a file handle from another VFS client 1136 * 1137 * @param high If true, the received file handle will be allocated from high 1138 * indices 1139 * 1140 * @return EOK on success or a negative error code 1141 */ 1142 int vfs_receive_handle(bool high) 1143 { 1144 ipc_callid_t callid; 1145 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) { 1146 async_answer_0(callid, EINVAL); 1147 return EINVAL; 1148 } 1149 1150 async_exch_t *vfs_exch = vfs_exchange_begin(); 1151 1152 async_state_change_finalize(callid, vfs_exch); 1153 1154 sysarg_t ret; 1155 sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret); 1156 1157 async_exchange_end(vfs_exch); 1098 async_wait_for(req, &rc_orig); 1099 1100 if (rc_orig != EOK) 1101 return (int) rc_orig; 1102 1103 if (rc != EOK) 1104 return (int) rc; 1105 1106 return (int) IPC_GET_ARG1(answer); 1107 } 1108 1109 /** Write data 1110 * 1111 * This function fails if it cannot write exactly @a len bytes to the file. 1112 * 1113 * @param file File handle to write to 1114 * @param[inout] pos Position to write to, updated by the actual bytes 1115 * written 1116 * @param buf Data, @a nbytes bytes long 1117 * @param nbytes Number of bytes to write 1118 * 1119 * @return On success, non-negative number of bytes written 1120 * @return On failure, a negative error code 1121 */ 1122 ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte) 1123 { 1124 ssize_t cnt = 0; 1125 ssize_t nwritten = 0; 1126 const uint8_t *bp = (uint8_t *) buf; 1127 int rc; 1128 1129 do { 1130 bp += cnt; 1131 nwritten += cnt; 1132 *pos += cnt; 1133 rc = vfs_write_short(file, *pos, bp, nbyte - nwritten, &cnt); 1134 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0); 1158 1135 1159 1136 if (rc != EOK) 1160 1137 return rc; 1161 return ret; 1162 } 1163 1164 /** Clone a file handle 1165 * 1166 * The caller can choose whether to clone an existing file handle into another 1167 * already existing file handle (in which case it is first closed) or to a new 1168 * file handle allocated either from low or high indices. 1169 * 1170 * @param file_from Source file handle 1171 * @param file_to Destination file handle or -1 1172 * @param high If file_to is -1, high controls whether the new file 1173 * handle will be allocated from high indices 1174 * 1175 * @return New file handle on success or a negative error code 1176 */ 1177 int vfs_clone(int file_from, int file_to, bool high) 1178 { 1179 async_exch_t *vfs_exch = vfs_exchange_begin(); 1180 int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from, 1181 (sysarg_t) file_to, (sysarg_t) high); 1182 vfs_exchange_end(vfs_exch); 1183 return rc; 1138 1139 *pos += cnt; 1140 return nbyte; 1141 } 1142 1143 /** Write bytes to a file 1144 * 1145 * Write up to @a nbyte bytes from file. The actual number of bytes written 1146 * may be lower, but greater than zero. 1147 * 1148 * @param file File handle to write to 1149 * @param[in] pos Position to write to 1150 * @param buf Buffer to write to 1151 * @param nbyte Maximum number of bytes to write 1152 * @param[out] nread Actual number of bytes written (0 or more) 1153 * 1154 * @return EOK on success or a negative error code 1155 */ 1156 int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte, 1157 ssize_t *nwritten) 1158 { 1159 sysarg_t rc; 1160 ipc_call_t answer; 1161 aid_t req; 1162 1163 if (nbyte > DATA_XFER_LIMIT) 1164 nbyte = DATA_XFER_LIMIT; 1165 1166 async_exch_t *exch = vfs_exchange_begin(); 1167 1168 req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos), 1169 UPPER32(pos), &answer); 1170 rc = async_data_write_start(exch, (void *) buf, nbyte); 1171 1172 vfs_exchange_end(exch); 1173 1174 if (rc == EOK) 1175 async_wait_for(req, &rc); 1176 else 1177 async_forget(req); 1178 1179 if (rc != EOK) 1180 return rc; 1181 1182 *nwritten = (ssize_t) IPC_GET_ARG1(answer); 1183 return EOK; 1184 1184 } 1185 1185 -
uspace/lib/c/include/vfs/vfs.h
rca7506f r3ba431a 73 73 }; 74 74 75 extern char *vfs_absolutize(const char *, size_t *);76 extern int vfs_cwd_set(const char *path);77 extern int vfs_cwd_get(char *path, size_t);78 79 75 extern int vfs_fhandle(FILE *, int *); 80 76 77 extern char *vfs_absolutize(const char *, size_t *); 78 extern int vfs_clone(int, int, bool); 79 extern int vfs_cwd_get(char *path, size_t); 80 extern int vfs_cwd_set(const char *path); 81 81 extern async_exch_t *vfs_exchange_begin(void); 82 82 extern void vfs_exchange_end(async_exch_t *); 83 84 extern int vfs_pass_handle(async_exch_t *, int, async_exch_t *);85 extern int vfs_receive_handle(bool);86 87 extern int vfs_clone(int, int, bool);88 83 extern int vfs_link(int, const char *, vfs_file_kind_t); 89 84 extern int vfs_link_path(const char *, vfs_file_kind_t); … … 95 90 unsigned, int *); 96 91 extern int vfs_open(int, int); 92 extern int vfs_pass_handle(async_exch_t *, int, async_exch_t *); 97 93 extern int vfs_put(int); 94 extern ssize_t vfs_read(int, aoff64_t *, void *, size_t); 98 95 extern int vfs_read_short(int, aoff64_t, void *, size_t, ssize_t *); 99 extern ssize_t vfs_read(int, aoff64_t *, void *, size_t);96 extern int vfs_receive_handle(bool); 100 97 extern int vfs_rename_path(const char *, const char *); 101 98 extern int vfs_resize(int, aoff64_t); … … 112 109 extern int vfs_unmount_path(const char *); 113 110 extern int vfs_walk(int, const char *, int); 111 extern ssize_t vfs_write(int, aoff64_t *, const void *, size_t); 114 112 extern int vfs_write_short(int, aoff64_t, const void *, size_t, ssize_t *); 115 extern ssize_t vfs_write(int, aoff64_t *, const void *, size_t);116 113 117 114 #endif
Note:
See TracChangeset
for help on using the changeset viewer.