Changes in uspace/lib/c/generic/vfs/vfs.c [a6fc88a:6afc9d7] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/vfs/vfs.c
ra6fc88a r6afc9d7 33 33 */ 34 34 35 #include <vfs/canonify.h> 35 36 #include <vfs/vfs.h> 36 #include <vfs/canonify.h>37 #include <vfs/vfs_mtab.h>38 37 #include <vfs/vfs_sess.h> 39 38 #include <macros.h> 40 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <dirent.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <sys/stat.h> 45 #include <sys/statfs.h> 41 46 #include <sys/types.h> 42 47 #include <ipc/services.h> … … 51 56 #include <ipc/loc.h> 52 57 53 /*54 * This file contains the implementation of the native HelenOS file system API.55 *56 * The API supports client-side file system roots, client-side IO cursors and57 * uses file handles as a primary means to refer to files. In order to call the58 * API functions, one just includes vfs/vfs.h.59 *60 * The API functions come in two main flavors:61 *62 * - functions that operate on integer file handles, such as:63 * vfs_walk(), vfs_open(), vfs_read(), vfs_link(), ...64 *65 * - functions that operate on paths, such as:66 * vfs_lookup(), vfs_link_path(), vfs_unlink_path(), vfs_rename_path(), ...67 *68 * There is usually a corresponding path function for each file handle function69 * that exists mostly as a convenience wrapper, except for cases when only a70 * path version exists due to file system consistency considerations (see71 * vfs_rename_path()). Sometimes one of the versions does not make sense, in72 * which case it is also omitted.73 *74 * Besides of that, the API provides some convenience wrappers for frequently75 * performed pairs of operations, for example there is a combo API for76 * vfs_lookup() and vfs_open(): vfs_lookup_open().77 *78 * Some of the functions here return a file handle that can be passed to other79 * functions. Note that a file handle does not automatically represent a file80 * from which one can read or to which one can write. In order to do so, the81 * file handle must be opened first for reading/writing using vfs_open().82 *83 * All file handles, no matter whether opened or not, must be eventually84 * returned to the system using vfs_put(). Non-returned file handles are in use85 * and consume system resources.86 *87 * Functions that return int return a negative error code on error and do not88 * set errno. Depending on function, success is signalled by returning either89 * EOK or a non-negative file handle.90 *91 * An example life-cycle of a file handle is as follows:92 *93 * #include <vfs/vfs.h>94 *95 * int file = vfs_lookup("/foo/bar/foobar", WALK_REGULAR);96 * if (file < 0)97 * return file;98 * int rc = vfs_open(file, MODE_READ);99 * if (rc != EOK) {100 * (void) vfs_put(file);101 * return rc;102 * }103 * aoff64_t pos = 42;104 * char buf[512];105 * ssize_t size = vfs_read(file, &pos, buf, sizeof(buf));106 * if (size < 0) {107 * vfs_put(file);108 * return size;109 * }110 *111 * // buf is now filled with data from file112 *113 * vfs_put(file);114 */115 116 58 static FIBRIL_MUTEX_INITIALIZE(vfs_mutex); 117 59 static async_sess_t *vfs_sess = NULL; … … 123 65 static size_t cwd_size = 0; 124 66 125 static FIBRIL_MUTEX_INITIALIZE(root_mutex); 126 static int root_fd = -1; 127 128 static int get_parent_and_child(const char *path, char **child) 129 { 130 size_t size; 131 char *apath = vfs_absolutize(path, &size); 132 if (!apath) 133 return ENOMEM; 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; 157 } 158 159 /** Make a potentially relative path absolute 160 * 161 * This function coverts a current-working-directory-relative path into a 162 * well-formed, absolute path. The caller is responsible for deallocating the 163 * returned buffer. 164 * 165 * @param[in] path Path to be absolutized 166 * @param[out] retlen Length of the absolutized path 167 * 168 * @return New buffer holding the absolutized path or NULL 169 */ 67 /** Start an async exchange on the VFS session. 68 * 69 * @return New exchange. 70 * 71 */ 72 async_exch_t *vfs_exchange_begin(void) 73 { 74 fibril_mutex_lock(&vfs_mutex); 75 76 while (vfs_sess == NULL) 77 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS, 78 0); 79 80 fibril_mutex_unlock(&vfs_mutex); 81 82 return async_exchange_begin(vfs_sess); 83 } 84 85 /** Finish an async exchange on the VFS session. 86 * 87 * @param exch Exchange to be finished. 88 * 89 */ 90 void vfs_exchange_end(async_exch_t *exch) 91 { 92 async_exchange_end(exch); 93 } 94 170 95 char *vfs_absolutize(const char *path, size_t *retlen) 171 96 { … … 218 143 } 219 144 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 * @param[out] linkedfd If not NULL, will receive a file handle to the linked 362 * child 363 * @return EOK on success or a negative error code 364 */ 365 int vfs_link(int parent, const char *child, vfs_file_kind_t kind, int *linkedfd) 366 { 367 int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR; 368 int file = vfs_walk(parent, child, WALK_MUST_CREATE | flags); 369 370 if (file < 0) 371 return file; 372 373 if (linkedfd) 374 *linkedfd = file; 375 else 376 vfs_put(file); 377 378 return EOK; 379 } 380 381 /** Link a file or directory 382 * 383 * Create a new name and an empty file or an empty directory at given path. 384 * If a link with the same name already exists, the function returns 385 * a failure, the existing file remains untouched and no file system object 386 * is created. 387 * 388 * @param path New path to be linked 389 * @param kind Kind of the object to be created: KIND_FILE or 390 * KIND_DIRECTORY 391 * @param[out] linkedfd If not NULL, will receive a file handle to the linked 392 * child 393 * @return EOK on success or a negative error code 394 */ 395 int vfs_link_path(const char *path, vfs_file_kind_t kind, int *linkedfd) 396 { 397 char *child; 398 int parent = get_parent_and_child(path, &child); 399 if (parent < 0) 400 return parent; 401 402 int rc = vfs_link(parent, child, kind, linkedfd); 403 404 free(child); 405 vfs_put(parent); 406 return rc; 407 } 408 409 /** Lookup a path relative to the local root 410 * 411 * @param path Path to be looked up 412 * @param flags Walk flags 413 * 414 * @return File handle representing the result on success or a negative 415 * error code on error 416 */ 417 int vfs_lookup(const char *path, int flags) 418 { 419 size_t size; 420 char *p = vfs_absolutize(path, &size); 421 if (!p) 422 return ENOMEM; 423 int root = vfs_root(); 424 if (root < 0) { 425 free(p); 426 return ENOENT; 427 } 428 int rc = vfs_walk(root, p, flags); 429 vfs_put(root); 430 free(p); 431 return rc; 432 } 433 434 /** Lookup a path relative to the local root and open the result 435 * 436 * This function is a convenience combo for vfs_lookup() and vfs_open(). 437 * 438 * @param path Path to be looked up 439 * @param flags Walk flags 440 * @param mode Mode in which to open file in 441 * 442 * @return EOK on success or a negative error code 443 */ 444 int vfs_lookup_open(const char *path, int flags, int mode) 445 { 446 int file = vfs_lookup(path, flags); 447 if (file < 0) 448 return file; 449 450 int rc = vfs_open(file, mode); 451 if (rc != EOK) { 452 vfs_put(file); 453 return rc; 454 } 455 456 return file; 457 } 458 459 /** Mount a file system 460 * 461 * @param[in] mp File handle representing the mount-point 462 * @param[in] fs_name File system name 463 * @param[in] serv Service representing the mountee 464 * @param[in] opts Mount options for the endpoint file system 465 * @param[in] flags Mount flags 466 * @param[in] instance Instance number of the file system server 467 * @param[out] mountedfd File handle of the mounted root if not NULL 468 * 469 * @return EOK on success or a negative error code 470 */ 471 int vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts, 472 unsigned int flags, unsigned int instance, int *mountedfd) 473 { 474 sysarg_t rc, rc1; 475 476 if (!mountedfd) 477 flags |= VFS_MOUNT_NO_REF; 478 if (mp < 0) 479 flags |= VFS_MOUNT_CONNECT_ONLY; 480 481 ipc_call_t answer; 482 async_exch_t *exch = vfs_exchange_begin(); 483 aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance, 484 &answer); 485 486 rc1 = async_data_write_start(exch, (void *) opts, str_size(opts)); 487 if (rc1 == EOK) { 488 rc1 = async_data_write_start(exch, (void *) fs_name, 489 str_size(fs_name)); 490 } 491 492 vfs_exchange_end(exch); 493 494 async_wait_for(req, &rc); 495 496 if (mountedfd) 497 *mountedfd = (int) IPC_GET_ARG1(answer); 498 499 if (rc != EOK) 500 return rc; 501 return rc1; 502 } 503 504 /** Mount a file system 505 * 506 * @param[in] mp Path representing the mount-point 507 * @param[in] fs_name File system name 508 * @param[in] fqsn Fully qualified service name of the mountee 509 * @param[in] opts Mount options for the endpoint file system 510 * @param[in] flags Mount flags 511 * @param[in] instance Instance number of the file system server 512 * 513 * @return EOK on success or a negative error code 514 */ 515 int vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn, 145 int vfs_mount(const char *fs_name, const char *mp, const char *fqsn, 516 146 const char *opts, unsigned int flags, unsigned int instance) 517 147 { … … 520 150 521 151 if (str_cmp(fqsn, "") == 0) { 522 /* 523 * No device specified, create a fresh null/%d device instead. 524 */ 152 /* No device specified, create a fresh 153 null/%d device instead */ 525 154 null_id = loc_null_create(); 526 155 … … 531 160 fqsn = null; 532 161 } 533 534 if (flags & IPC_FLAG_BLOCKING)535 flags = VFS_MOUNT_BLOCKING;536 else537 flags = 0;538 162 539 163 service_id_t service_id; … … 555 179 } 556 180 557 fibril_mutex_lock(&root_mutex); 558 559 int rc; 560 561 if (str_cmp(mpa, "/") == 0) { 562 /* Mounting root. */ 563 564 if (root_fd >= 0) { 565 fibril_mutex_unlock(&root_mutex); 566 if (null_id != -1) 567 loc_null_destroy(null_id); 568 return EBUSY; 569 } 570 571 int root; 572 rc = vfs_mount(-1, fs_name, service_id, opts, flags, instance, 573 &root); 574 if (rc == EOK) 575 root_fd = root; 576 } else { 577 if (root_fd < 0) { 578 fibril_mutex_unlock(&root_mutex); 579 if (null_id != -1) 580 loc_null_destroy(null_id); 581 return EINVAL; 582 } 583 584 int mpfd = vfs_walk(root_fd, mpa, WALK_DIRECTORY); 585 if (mpfd >= 0) { 586 rc = vfs_mount(mpfd, fs_name, service_id, opts, flags, 587 instance, NULL); 588 vfs_put(mpfd); 589 } else { 590 rc = mpfd; 591 } 592 } 593 594 fibril_mutex_unlock(&root_mutex); 181 async_exch_t *exch = vfs_exchange_begin(); 182 183 sysarg_t rc_orig; 184 aid_t req = async_send_3(exch, VFS_IN_MOUNT, service_id, flags, 185 instance, NULL); 186 sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size); 187 if (rc != EOK) { 188 vfs_exchange_end(exch); 189 free(mpa); 190 async_wait_for(req, &rc_orig); 191 192 if (null_id != -1) 193 loc_null_destroy(null_id); 194 195 if (rc_orig == EOK) 196 return (int) rc; 197 else 198 return (int) rc_orig; 199 } 200 201 rc = async_data_write_start(exch, (void *) opts, str_size(opts)); 202 if (rc != EOK) { 203 vfs_exchange_end(exch); 204 free(mpa); 205 async_wait_for(req, &rc_orig); 206 207 if (null_id != -1) 208 loc_null_destroy(null_id); 209 210 if (rc_orig == EOK) 211 return (int) rc; 212 else 213 return (int) rc_orig; 214 } 215 216 rc = async_data_write_start(exch, (void *) fs_name, str_size(fs_name)); 217 if (rc != EOK) { 218 vfs_exchange_end(exch); 219 free(mpa); 220 async_wait_for(req, &rc_orig); 221 222 if (null_id != -1) 223 loc_null_destroy(null_id); 224 225 if (rc_orig == EOK) 226 return (int) rc; 227 else 228 return (int) rc_orig; 229 } 230 231 /* Ask VFS whether it likes fs_name. */ 232 rc = async_req_0_0(exch, VFS_IN_PING); 233 if (rc != EOK) { 234 vfs_exchange_end(exch); 235 free(mpa); 236 async_wait_for(req, &rc_orig); 237 238 if (null_id != -1) 239 loc_null_destroy(null_id); 240 241 if (rc_orig == EOK) 242 return (int) rc; 243 else 244 return (int) rc_orig; 245 } 246 247 vfs_exchange_end(exch); 248 free(mpa); 249 async_wait_for(req, &rc); 595 250 596 251 if ((rc != EOK) && (null_id != -1)) … … 600 255 } 601 256 602 603 /** Open a file handle for I/O 604 * 605 * @param file File handle to enable I/O on 606 * @param mode Mode in which to open file in 607 * 608 * @return EOK on success or a negative error code 609 */ 610 int vfs_open(int file, int mode) 611 { 612 async_exch_t *exch = vfs_exchange_begin(); 613 int rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode); 614 vfs_exchange_end(exch); 615 616 return rc; 617 } 618 619 /** Pass a file handle to another VFS client 620 * 621 * @param vfs_exch Donor's VFS exchange 622 * @param file Donor's file handle to pass 623 * @param exch Exchange to the acceptor 624 * 625 * @return EOK on success or a negative error code 626 */ 627 int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch) 628 { 629 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file, 630 0, vfs_exch); 631 } 632 633 /** Stop working with a file handle 634 * 635 * @param file File handle to put 636 * 637 * @return EOK on success or a negative error code 638 */ 639 int vfs_put(int file) 640 { 641 async_exch_t *exch = vfs_exchange_begin(); 642 int rc = async_req_1_0(exch, VFS_IN_PUT, file); 643 vfs_exchange_end(exch); 644 645 return rc; 646 } 647 648 /** Receive a file handle from another VFS client 649 * 650 * @param high If true, the received file handle will be allocated from high 651 * indices 652 * 653 * @return EOK on success or a negative error code 654 */ 655 int vfs_receive_handle(bool high) 656 { 657 ipc_callid_t callid; 658 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) { 659 async_answer_0(callid, EINVAL); 660 return EINVAL; 661 } 662 663 async_exch_t *vfs_exch = vfs_exchange_begin(); 664 665 async_state_change_finalize(callid, vfs_exch); 666 667 sysarg_t ret; 668 sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE, high, &ret); 669 670 async_exchange_end(vfs_exch); 671 257 int vfs_unmount(const char *mp) 258 { 259 sysarg_t rc; 260 sysarg_t rc_orig; 261 aid_t req; 262 size_t mpa_size; 263 char *mpa; 264 265 mpa = vfs_absolutize(mp, &mpa_size); 266 if (mpa == NULL) 267 return ENOMEM; 268 269 async_exch_t *exch = vfs_exchange_begin(); 270 271 req = async_send_0(exch, VFS_IN_UNMOUNT, NULL); 272 rc = async_data_write_start(exch, (void *) mpa, mpa_size); 273 if (rc != EOK) { 274 vfs_exchange_end(exch); 275 free(mpa); 276 async_wait_for(req, &rc_orig); 277 if (rc_orig == EOK) 278 return (int) rc; 279 else 280 return (int) rc_orig; 281 } 282 283 284 vfs_exchange_end(exch); 285 free(mpa); 286 async_wait_for(req, &rc); 287 288 return (int) rc; 289 } 290 291 /** Open file (internal). 292 * 293 * @param abs Absolute path to file 294 * @param abs_size Size of @a abs string 295 * @param lflag L_xxx flags 296 * @param oflag O_xxx flags 297 * @param fd Place to store new file descriptor 298 * 299 * @return EOK on success, non-zero error code on error 300 */ 301 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag, 302 int *fd) 303 { 304 async_exch_t *exch = vfs_exchange_begin(); 305 306 ipc_call_t answer; 307 aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer); 308 sysarg_t rc = async_data_write_start(exch, abs, abs_size); 309 310 if (rc != EOK) { 311 vfs_exchange_end(exch); 312 313 sysarg_t rc_orig; 314 async_wait_for(req, &rc_orig); 315 316 if (rc_orig == EOK) 317 return (int) rc; 318 else 319 return (int) rc_orig; 320 } 321 322 vfs_exchange_end(exch); 323 async_wait_for(req, &rc); 324 325 if (rc != EOK) 326 return (int) rc; 327 328 *fd = (int) IPC_GET_ARG1(answer); 329 return EOK; 330 } 331 332 /** Open file. 333 * 334 * @param path File path 335 * @param oflag O_xxx flags 336 * @param mode File mode (only with O_CREAT) 337 * 338 * @return Nonnegative file descriptor on success. On error -1 is returned 339 * and errno is set. 340 */ 341 int open(const char *path, int oflag, ...) 342 { 343 size_t abs_size; 344 char *abs = vfs_absolutize(path, &abs_size); 345 int fd = -1; 346 347 if (abs == NULL) { 348 errno = ENOMEM; 349 return -1; 350 } 351 352 int rc = open_internal(abs, abs_size, L_FILE, oflag, &fd); 353 free(abs); 354 355 if (rc != EOK) { 356 errno = rc; 357 return -1; 358 } 359 360 return fd; 361 } 362 363 /** Close file. 364 * 365 * @param fildes File descriptor 366 * @return Zero on success. On error -1 is returned and errno is set. 367 */ 368 int close(int fildes) 369 { 370 sysarg_t rc; 371 372 async_exch_t *exch = vfs_exchange_begin(); 373 rc = async_req_1_0(exch, VFS_IN_CLOSE, fildes); 374 vfs_exchange_end(exch); 375 376 if (rc != EOK) { 377 errno = rc; 378 return -1; 379 } 380 381 return 0; 382 } 383 384 /** Read bytes from file. 385 * 386 * Read up to @a nbyte bytes from file. The actual number of bytes read 387 * may be lower, but greater than zero if there are any bytes available. 388 * If there are no bytes available for reading, then the function will 389 * return success with zero bytes read. 390 * 391 * @param fildes File descriptor 392 * @param buf Buffer 393 * @param nbyte Maximum number of bytes to read 394 * @param nread Place to store actual number of bytes read (0 or more) 395 * 396 * @return EOK on success, non-zero error code on error. 397 */ 398 static int _read_short(int fildes, void *buf, size_t nbyte, ssize_t *nread) 399 { 400 sysarg_t rc; 401 ipc_call_t answer; 402 aid_t req; 403 404 if (nbyte > DATA_XFER_LIMIT) 405 nbyte = DATA_XFER_LIMIT; 406 407 async_exch_t *exch = vfs_exchange_begin(); 408 409 req = async_send_1(exch, VFS_IN_READ, fildes, &answer); 410 rc = async_data_read_start(exch, (void *) buf, nbyte); 411 if (rc != EOK) { 412 vfs_exchange_end(exch); 413 414 sysarg_t rc_orig; 415 async_wait_for(req, &rc_orig); 416 417 if (rc_orig == EOK) 418 return rc; 419 else 420 return rc_orig; 421 } 422 423 vfs_exchange_end(exch); 424 async_wait_for(req, &rc); 425 672 426 if (rc != EOK) 673 427 return rc; 674 return ret; 675 } 676 677 /** Read data 428 429 *nread = (ssize_t) IPC_GET_ARG1(answer); 430 return EOK; 431 } 432 433 /** Write bytes to file. 434 * 435 * Write up to @a nbyte bytes from file. The actual number of bytes written 436 * may be lower, but greater than zero. 437 * 438 * @param fildes File descriptor 439 * @param buf Buffer 440 * @param nbyte Maximum number of bytes to write 441 * @param nread Place to store actual number of bytes written (0 or more) 442 * 443 * @return EOK on success, non-zero error code on error. 444 */ 445 static int _write_short(int fildes, const void *buf, size_t nbyte, 446 ssize_t *nwritten) 447 { 448 sysarg_t rc; 449 ipc_call_t answer; 450 aid_t req; 451 452 if (nbyte > DATA_XFER_LIMIT) 453 nbyte = DATA_XFER_LIMIT; 454 455 async_exch_t *exch = vfs_exchange_begin(); 456 457 req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer); 458 rc = async_data_write_start(exch, (void *) buf, nbyte); 459 if (rc != EOK) { 460 vfs_exchange_end(exch); 461 462 sysarg_t rc_orig; 463 async_wait_for(req, &rc_orig); 464 465 if (rc_orig == EOK) 466 return rc; 467 else 468 return rc_orig; 469 } 470 471 vfs_exchange_end(exch); 472 async_wait_for(req, &rc); 473 474 if (rc != EOK) 475 return rc; 476 477 *nwritten = (ssize_t) IPC_GET_ARG1(answer); 478 return EOK; 479 } 480 481 /** Read data. 678 482 * 679 483 * Read up to @a nbytes bytes from file if available. This function always reads 680 484 * all the available bytes up to @a nbytes. 681 485 * 682 * @param file File handle to read from 683 * @param[inout] pos Position to read from, updated by the actual bytes read 486 * @param fildes File descriptor 684 487 * @param buf Buffer, @a nbytes bytes long 685 488 * @param nbytes Number of bytes to read 686 489 * 687 * @return On success, non-negative number of bytes read688 * @return On failure, a negative error code689 */ 690 ssize_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte)490 * @return On success, nonnegative number of bytes read. 491 * On failure, -1 and sets errno. 492 */ 493 ssize_t read(int fildes, void *buf, size_t nbyte) 691 494 { 692 495 ssize_t cnt = 0; … … 698 501 bp += cnt; 699 502 nread += cnt; 700 *pos += cnt; 701 rc = vfs_read_short(file, *pos, bp, nbyte - nread, &cnt); 503 rc = _read_short(fildes, bp, nbyte - nread, &cnt); 702 504 } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0); 703 505 704 if (rc != EOK) 705 return rc; 706 707 *pos += cnt; 506 if (rc != EOK) { 507 errno = rc; 508 return -1; 509 } 510 708 511 return nread + cnt; 709 512 } 710 513 711 /** Read bytes from a file 712 * 713 * Read up to @a nbyte bytes from file. The actual number of bytes read 714 * may be lower, but greater than zero if there are any bytes available. 715 * If there are no bytes available for reading, then the function will 716 * return success with zero bytes read. 717 * 718 * @param file File handle to read from 719 * @param[in] pos Position to read from 720 * @param buf Buffer to read from 721 * @param nbyte Maximum number of bytes to read 722 * @param[out] nread Actual number of bytes read (0 or more) 723 * 724 * @return EOK on success or a negative error code 725 */ 726 int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte, 727 ssize_t *nread) 514 /** Write data. 515 * 516 * This function fails if it cannot write exactly @a len bytes to the file. 517 * 518 * @param fildes File descriptor 519 * @param buf Data, @a nbytes bytes long 520 * @param nbytes Number of bytes to write 521 * 522 * @return On success, nonnegative number of bytes written. 523 * On failure, -1 and sets errno. 524 */ 525 ssize_t write(int fildes, const void *buf, size_t nbyte) 526 { 527 ssize_t cnt = 0; 528 ssize_t nwritten = 0; 529 const uint8_t *bp = (uint8_t *) buf; 530 int rc; 531 532 do { 533 bp += cnt; 534 nwritten += cnt; 535 rc = _write_short(fildes, bp, nbyte - nwritten, &cnt); 536 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0); 537 538 if (rc != EOK) { 539 errno = rc; 540 return -1; 541 } 542 543 return nbyte; 544 } 545 546 /** Synchronize file. 547 * 548 * @param fildes File descriptor 549 * @return 0 on success. On error returns -1 and sets errno. 550 */ 551 int fsync(int fildes) 552 { 553 async_exch_t *exch = vfs_exchange_begin(); 554 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes); 555 vfs_exchange_end(exch); 556 557 if (rc != EOK) { 558 errno = rc; 559 return -1; 560 } 561 562 return 0; 563 } 564 565 /** Seek to a position. 566 * 567 * @param fildes File descriptor 568 * @param offset Offset 569 * @param whence SEEK_SET, SEEK_CUR or SEEK_END 570 * 571 * @return On success the nonnegative offset from start of file. On error 572 * returns (off64_t)-1 and sets errno. 573 */ 574 off64_t lseek(int fildes, off64_t offset, int whence) 575 { 576 async_exch_t *exch = vfs_exchange_begin(); 577 578 sysarg_t newoff_lo; 579 sysarg_t newoff_hi; 580 sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes, 581 LOWER32(offset), UPPER32(offset), whence, 582 &newoff_lo, &newoff_hi); 583 584 vfs_exchange_end(exch); 585 586 if (rc != EOK) { 587 errno = rc; 588 return (off64_t) -1; 589 } 590 591 return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi); 592 } 593 594 /** Truncate file to a specified length. 595 * 596 * Truncate file so that its size is exactly @a length 597 * 598 * @param fildes File descriptor 599 * @param length Length 600 * 601 * @return 0 on success, -1 on error and sets errno. 602 */ 603 int ftruncate(int fildes, aoff64_t length) 728 604 { 729 605 sysarg_t rc; 730 ipc_call_t answer; 606 607 async_exch_t *exch = vfs_exchange_begin(); 608 rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes, 609 LOWER32(length), UPPER32(length)); 610 vfs_exchange_end(exch); 611 612 if (rc != EOK) { 613 errno = rc; 614 return -1; 615 } 616 617 return 0; 618 } 619 620 /** Get file status. 621 * 622 * @param fildes File descriptor 623 * @param stat Place to store file information 624 * 625 * @return 0 on success, -1 on error and sets errno. 626 */ 627 int fstat(int fildes, struct stat *stat) 628 { 629 sysarg_t rc; 731 630 aid_t req; 732 631 733 if (nbyte > DATA_XFER_LIMIT) 734 nbyte = DATA_XFER_LIMIT; 735 736 async_exch_t *exch = vfs_exchange_begin(); 737 738 req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos), 739 UPPER32(pos), &answer); 740 rc = async_data_read_start(exch, (void *) buf, nbyte); 741 742 vfs_exchange_end(exch); 743 744 if (rc == EOK) 745 async_wait_for(req, &rc); 746 else 747 async_forget(req); 748 749 if (rc != EOK) 750 return rc; 751 752 *nread = (ssize_t) IPC_GET_ARG1(answer); 753 return EOK; 754 } 755 756 /** Rename a file or directory 757 * 758 * There is no file-handle-based variant to disallow attempts to introduce loops 759 * and breakage in the directory tree when relinking eg. a node under its own 760 * descendant. The path-based variant is not susceptible because the VFS can 761 * prevent this lexically by comparing the paths. 762 * 763 * @param old Old path 764 * @param new New path 765 * 766 * @return EOK on success or a negative error code 767 */ 768 int vfs_rename_path(const char *old, const char *new) 632 async_exch_t *exch = vfs_exchange_begin(); 633 634 req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL); 635 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat)); 636 if (rc != EOK) { 637 vfs_exchange_end(exch); 638 639 sysarg_t rc_orig; 640 async_wait_for(req, &rc_orig); 641 642 if (rc_orig != EOK) 643 rc = rc_orig; 644 if (rc != EOK) { 645 errno = rc; 646 return -1; 647 } 648 649 return 0; 650 } 651 652 vfs_exchange_end(exch); 653 async_wait_for(req, &rc); 654 655 if (rc != EOK) { 656 errno = rc; 657 return -1; 658 } 659 660 return 0; 661 } 662 663 /** Get file status. 664 * 665 * @param path Path to file 666 * @param stat Place to store file information 667 * 668 * @return 0 on success, -1 on error and sets errno. 669 */ 670 int stat(const char *path, struct stat *stat) 769 671 { 770 672 sysarg_t rc; … … 772 674 aid_t req; 773 675 676 size_t pa_size; 677 char *pa = vfs_absolutize(path, &pa_size); 678 if (pa == NULL) { 679 errno = ENOMEM; 680 return -1; 681 } 682 683 async_exch_t *exch = vfs_exchange_begin(); 684 685 req = async_send_0(exch, VFS_IN_STAT, NULL); 686 rc = async_data_write_start(exch, pa, pa_size); 687 if (rc != EOK) { 688 vfs_exchange_end(exch); 689 free(pa); 690 async_wait_for(req, &rc_orig); 691 if (rc_orig != EOK) 692 rc = rc_orig; 693 if (rc != EOK) { 694 errno = rc; 695 return -1; 696 } 697 } 698 rc = async_data_read_start(exch, stat, sizeof(struct stat)); 699 if (rc != EOK) { 700 vfs_exchange_end(exch); 701 free(pa); 702 async_wait_for(req, &rc_orig); 703 if (rc_orig != EOK) 704 rc = rc_orig; 705 if (rc != EOK) { 706 errno = rc; 707 return -1; 708 } 709 } 710 vfs_exchange_end(exch); 711 free(pa); 712 async_wait_for(req, &rc); 713 if (rc != EOK) { 714 errno = rc; 715 return -1; 716 } 717 return 0; 718 } 719 720 /** Open directory. 721 * 722 * @param dirname Directory pathname 723 * 724 * @return Non-NULL pointer on success. On error returns @c NULL and sets errno. 725 */ 726 DIR *opendir(const char *dirname) 727 { 728 DIR *dirp = malloc(sizeof(DIR)); 729 int fd = -1; 730 731 if (dirp == NULL) { 732 errno = ENOMEM; 733 return NULL; 734 } 735 736 size_t abs_size; 737 char *abs = vfs_absolutize(dirname, &abs_size); 738 if (abs == NULL) { 739 free(dirp); 740 errno = ENOMEM; 741 return NULL; 742 } 743 744 int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd); 745 free(abs); 746 747 if (rc != EOK) { 748 free(dirp); 749 errno = rc; 750 return NULL; 751 } 752 753 dirp->fd = fd; 754 return dirp; 755 } 756 757 /** Read directory entry. 758 * 759 * @param dirp Open directory 760 * @return Non-NULL pointer to directory entry on success. On error returns 761 * @c NULL and sets errno. 762 */ 763 struct dirent *readdir(DIR *dirp) 764 { 765 int rc; 766 ssize_t len; 767 768 rc = _read_short(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1, &len); 769 if (rc != EOK) { 770 errno = rc; 771 return NULL; 772 } 773 774 (void) len; 775 return &dirp->res; 776 } 777 778 /** Rewind directory position to the beginning. 779 * 780 * @param dirp Open directory 781 */ 782 void rewinddir(DIR *dirp) 783 { 784 (void) lseek(dirp->fd, 0, SEEK_SET); 785 } 786 787 /** Close directory. 788 * 789 * @param dirp Open directory 790 * @return 0 on success. On error returns -1 and sets errno. 791 */ 792 int closedir(DIR *dirp) 793 { 794 int rc; 795 796 rc = close(dirp->fd); 797 free(dirp); 798 799 /* On error errno was set by close() */ 800 return rc; 801 } 802 803 /** Create directory. 804 * 805 * @param path Path 806 * @param mode File mode 807 * @return 0 on success. On error returns -1 and sets errno. 808 */ 809 int mkdir(const char *path, mode_t mode) 810 { 811 sysarg_t rc; 812 aid_t req; 813 814 size_t pa_size; 815 char *pa = vfs_absolutize(path, &pa_size); 816 if (pa == NULL) { 817 errno = ENOMEM; 818 return -1; 819 } 820 821 async_exch_t *exch = vfs_exchange_begin(); 822 823 req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL); 824 rc = async_data_write_start(exch, pa, pa_size); 825 if (rc != EOK) { 826 vfs_exchange_end(exch); 827 free(pa); 828 829 sysarg_t rc_orig; 830 async_wait_for(req, &rc_orig); 831 832 if (rc_orig != EOK) 833 rc = rc_orig; 834 835 if (rc != EOK) { 836 errno = rc; 837 return -1; 838 } 839 840 return 0; 841 } 842 843 vfs_exchange_end(exch); 844 free(pa); 845 async_wait_for(req, &rc); 846 847 if (rc != EOK) { 848 errno = rc; 849 return -1; 850 } 851 852 return 0; 853 } 854 855 /** Unlink a file or directory. 856 * 857 * @param path Path to file or empty directory 858 * @param lflag L_xxx flag (L_NONE, L_FILE or L_DIRECTORY) 859 * @return EOK on success, non-zero error code on error 860 */ 861 static int _unlink(const char *path, int lflag) 862 { 863 sysarg_t rc; 864 aid_t req; 865 866 size_t pa_size; 867 char *pa = vfs_absolutize(path, &pa_size); 868 if (pa == NULL) 869 return ENOMEM; 870 871 async_exch_t *exch = vfs_exchange_begin(); 872 873 req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL); 874 rc = async_data_write_start(exch, pa, pa_size); 875 if (rc != EOK) { 876 vfs_exchange_end(exch); 877 free(pa); 878 879 sysarg_t rc_orig; 880 async_wait_for(req, &rc_orig); 881 882 if (rc_orig == EOK) 883 return (int) rc; 884 else 885 return (int) rc_orig; 886 } 887 vfs_exchange_end(exch); 888 free(pa); 889 async_wait_for(req, &rc); 890 return rc; 891 } 892 893 /** Unlink file or directory. 894 * 895 * @param path Path 896 * @return EOk on success, error code on error 897 */ 898 int unlink(const char *path) 899 { 900 int rc; 901 902 rc = _unlink(path, L_NONE); 903 if (rc != EOK) { 904 errno = rc; 905 return -1; 906 } 907 908 return 0; 909 } 910 911 /** Remove empty directory. 912 * 913 * @param path Path 914 * @return 0 on success. On error returns -1 and sets errno. 915 */ 916 int rmdir(const char *path) 917 { 918 int rc; 919 920 rc = _unlink(path, L_DIRECTORY); 921 if (rc != EOK) { 922 errno = rc; 923 return -1; 924 } 925 926 return 0; 927 } 928 929 /** Rename directory entry. 930 * 931 * @param old Old name 932 * @param new New name 933 * 934 * @return 0 on success. On error returns -1 and sets errno. 935 */ 936 int rename(const char *old, const char *new) 937 { 938 sysarg_t rc; 939 sysarg_t rc_orig; 940 aid_t req; 941 774 942 size_t olda_size; 775 943 char *olda = vfs_absolutize(old, &olda_size); 776 if (olda == NULL) 777 return ENOMEM; 944 if (olda == NULL) { 945 errno = ENOMEM; 946 return -1; 947 } 778 948 779 949 size_t newa_size; … … 781 951 if (newa == NULL) { 782 952 free(olda); 783 return ENOMEM; 784 } 785 786 async_exch_t *exch = vfs_exchange_begin(); 787 int root = vfs_root(); 788 if (root < 0) { 953 errno = ENOMEM; 954 return -1; 955 } 956 957 async_exch_t *exch = vfs_exchange_begin(); 958 959 req = async_send_0(exch, VFS_IN_RENAME, NULL); 960 rc = async_data_write_start(exch, olda, olda_size); 961 if (rc != EOK) { 962 vfs_exchange_end(exch); 789 963 free(olda); 790 964 free(newa); 791 return ENOENT; 792 } 793 794 req = async_send_1(exch, VFS_IN_RENAME, root, NULL); 795 rc = async_data_write_start(exch, olda, olda_size); 965 async_wait_for(req, &rc_orig); 966 if (rc_orig != EOK) 967 rc = rc_orig; 968 if (rc != EOK) { 969 errno = rc; 970 return -1; 971 } 972 return 0; 973 } 974 rc = async_data_write_start(exch, newa, newa_size); 796 975 if (rc != EOK) { 797 976 vfs_exchange_end(exch); 798 977 free(olda); 799 978 free(newa); 800 vfs_put(root);801 979 async_wait_for(req, &rc_orig); 802 980 if (rc_orig != EOK) 803 981 rc = rc_orig; 804 return rc; 805 } 806 rc = async_data_write_start(exch, newa, newa_size); 807 if (rc != EOK) { 808 vfs_exchange_end(exch); 809 free(olda); 810 free(newa); 811 vfs_put(root); 812 async_wait_for(req, &rc_orig); 813 if (rc_orig != EOK) 814 rc = rc_orig; 815 return rc; 982 if (rc != EOK) { 983 errno = rc; 984 return -1; 985 } 986 return 0; 816 987 } 817 988 vfs_exchange_end(exch); 818 989 free(olda); 819 990 free(newa); 820 vfs_put(root);821 991 async_wait_for(req, &rc); 822 992 823 return rc; 824 } 825 826 /** Resize file to a specified length 827 * 828 * Resize file so that its size is exactly @a length. 829 * 830 * @param file File handle to resize 831 * @param length New length 832 * 833 * @return EOK on success or a negative error code 834 */ 835 int vfs_resize(int file, aoff64_t length) 836 { 837 async_exch_t *exch = vfs_exchange_begin(); 838 int rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length), 839 UPPER32(length)); 840 vfs_exchange_end(exch); 841 842 return rc; 843 } 844 845 /** Return a new file handle representing the local root 846 * 847 * @return A clone of the local root file handle or a negative error code 848 */ 849 int vfs_root(void) 850 { 851 fibril_mutex_lock(&root_mutex); 852 int r; 853 if (root_fd < 0) 854 r = ENOENT; 855 else 856 r = vfs_clone(root_fd, -1, true); 857 fibril_mutex_unlock(&root_mutex); 858 return r; 859 } 860 861 /** Set a new local root 862 * 863 * Note that it is still possible to have file handles for other roots and pass 864 * them to the API functions. Functions like vfs_root() and vfs_lookup() will 865 * however consider the file set by this function to be the root. 866 * 867 * @param nroot The new local root file handle 868 */ 869 void vfs_root_set(int nroot) 870 { 871 fibril_mutex_lock(&root_mutex); 872 if (root_fd >= 0) 873 vfs_put(root_fd); 874 root_fd = vfs_clone(nroot, -1, true); 875 fibril_mutex_unlock(&root_mutex); 876 } 877 878 /** Get file information 879 * 880 * @param file File handle to get information about 881 * @param[out] stat Place to store file information 882 * 883 * @return EOK on success or a negative error code 884 */ 885 int vfs_stat(int file, struct stat *stat) 993 if (rc != EOK) { 994 errno = rc; 995 return -1; 996 } 997 998 return 0; 999 } 1000 1001 /** Remove directory entry. 1002 * 1003 * @param path Path 1004 * @return 0 on success. On error returns -1 and sets errno. 1005 */ 1006 int remove(const char *path) 1007 { 1008 return unlink(path); 1009 } 1010 1011 /** Change working directory. 1012 * 1013 * @param path Path 1014 * @return 0 on success. On error returns -1 and sets errno. 1015 */ 1016 int chdir(const char *path) 1017 { 1018 size_t abs_size; 1019 char *abs = vfs_absolutize(path, &abs_size); 1020 int fd = -1; 1021 1022 if (abs == NULL) { 1023 errno = ENOMEM; 1024 return -1; 1025 } 1026 1027 int rc = open_internal(abs, abs_size, L_DIRECTORY, O_DESC, &fd); 1028 1029 if (rc != EOK) { 1030 free(abs); 1031 errno = rc; 1032 return -1; 1033 } 1034 1035 fibril_mutex_lock(&cwd_mutex); 1036 1037 if (cwd_fd >= 0) 1038 close(cwd_fd); 1039 1040 if (cwd_path) 1041 free(cwd_path); 1042 1043 cwd_fd = fd; 1044 cwd_path = abs; 1045 cwd_size = abs_size; 1046 1047 fibril_mutex_unlock(&cwd_mutex); 1048 return 0; 1049 } 1050 1051 /** Get current working directory path. 1052 * 1053 * @param buf Buffer 1054 * @param size Size of @a buf 1055 * @return On success returns @a buf. On failure returns @c NULL and sets errno. 1056 */ 1057 char *getcwd(char *buf, size_t size) 1058 { 1059 if (size == 0) { 1060 errno = EINVAL; 1061 return NULL; 1062 } 1063 1064 fibril_mutex_lock(&cwd_mutex); 1065 1066 if ((cwd_size == 0) || (size < cwd_size + 1)) { 1067 fibril_mutex_unlock(&cwd_mutex); 1068 errno = ERANGE; 1069 return NULL; 1070 } 1071 1072 str_cpy(buf, size, cwd_path); 1073 fibril_mutex_unlock(&cwd_mutex); 1074 1075 return buf; 1076 } 1077 1078 /** Open session to service represented by a special file. 1079 * 1080 * Given that the file referred to by @a fildes represents a service, 1081 * open a session to that service. 1082 * 1083 * @param fildes File descriptor 1084 * @param iface Interface to connect to (XXX Should be automatic) 1085 * @return On success returns session pointer. On error returns @c NULL. 1086 */ 1087 async_sess_t *vfs_fd_session(int fildes, iface_t iface) 1088 { 1089 struct stat stat; 1090 int rc = fstat(fildes, &stat); 1091 if (rc != 0) 1092 return NULL; 1093 1094 if (stat.service == 0) 1095 return NULL; 1096 1097 return loc_service_connect(stat.service, iface, 0); 1098 } 1099 1100 /** Duplicate open file. 1101 * 1102 * Duplicate open file under a new file descriptor. 1103 * 1104 * @param oldfd Old file descriptor 1105 * @param newfd New file descriptor 1106 * @return 0 on success. On error -1 is returned and errno is set 1107 */ 1108 int dup2(int oldfd, int newfd) 1109 { 1110 async_exch_t *exch = vfs_exchange_begin(); 1111 1112 sysarg_t ret; 1113 sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret); 1114 1115 vfs_exchange_end(exch); 1116 1117 if (rc == EOK) 1118 rc = ret; 1119 1120 if (rc != EOK) { 1121 errno = rc; 1122 return -1; 1123 } 1124 1125 return 0; 1126 } 1127 1128 int vfs_fd_wait(void) 1129 { 1130 async_exch_t *exch = vfs_exchange_begin(); 1131 1132 sysarg_t ret; 1133 sysarg_t rc = async_req_0_1(exch, VFS_IN_WAIT_HANDLE, &ret); 1134 1135 vfs_exchange_end(exch); 1136 1137 if (rc == EOK) 1138 return (int) ret; 1139 1140 return (int) rc; 1141 } 1142 1143 int vfs_get_mtab_list(list_t *mtab_list) 886 1144 { 887 1145 sysarg_t rc; 888 1146 aid_t req; 889 890 async_exch_t *exch = vfs_exchange_begin(); 891 892 req = async_send_1(exch, VFS_IN_STAT, file, NULL); 893 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat)); 894 if (rc != EOK) { 895 vfs_exchange_end(exch); 896 897 sysarg_t rc_orig; 898 async_wait_for(req, &rc_orig); 899 900 if (rc_orig != EOK) 901 rc = rc_orig; 902 903 return rc; 904 } 905 906 vfs_exchange_end(exch); 1147 size_t i; 1148 sysarg_t num_mounted_fs; 1149 1150 async_exch_t *exch = vfs_exchange_begin(); 1151 1152 req = async_send_0(exch, VFS_IN_MTAB_GET, NULL); 1153 1154 /* Ask VFS how many filesystems are mounted */ 1155 rc = async_req_0_1(exch, VFS_IN_PING, &num_mounted_fs); 1156 if (rc != EOK) 1157 goto exit; 1158 1159 for (i = 0; i < num_mounted_fs; ++i) { 1160 mtab_ent_t *mtab_ent; 1161 1162 mtab_ent = malloc(sizeof(mtab_ent_t)); 1163 if (mtab_ent == NULL) { 1164 rc = ENOMEM; 1165 goto exit; 1166 } 1167 1168 memset(mtab_ent, 0, sizeof(mtab_ent_t)); 1169 1170 rc = async_data_read_start(exch, (void *) mtab_ent->mp, 1171 MAX_PATH_LEN); 1172 if (rc != EOK) 1173 goto exit; 1174 1175 rc = async_data_read_start(exch, (void *) mtab_ent->opts, 1176 MAX_MNTOPTS_LEN); 1177 if (rc != EOK) 1178 goto exit; 1179 1180 rc = async_data_read_start(exch, (void *) mtab_ent->fs_name, 1181 FS_NAME_MAXLEN); 1182 if (rc != EOK) 1183 goto exit; 1184 1185 sysarg_t p[2]; 1186 1187 rc = async_req_0_2(exch, VFS_IN_PING, &p[0], &p[1]); 1188 if (rc != EOK) 1189 goto exit; 1190 1191 mtab_ent->instance = p[0]; 1192 mtab_ent->service_id = p[1]; 1193 1194 link_initialize(&mtab_ent->link); 1195 list_append(&mtab_ent->link, mtab_list); 1196 } 1197 1198 exit: 907 1199 async_wait_for(req, &rc); 908 1200 vfs_exchange_end(exch); 909 1201 return rc; 910 1202 } 911 1203 912 /** Get file information 913 * 914 * @param path File path to get information about 915 * @param[out] stat Place to store file information 916 * 917 * @return EOK on success or a negative error code 918 */ 919 int vfs_stat_path(const char *path, struct stat *stat) 920 { 921 int file = vfs_lookup(path, 0); 922 if (file < 0) 923 return file; 924 925 int rc = vfs_stat(file, stat); 926 927 vfs_put(file); 928 929 return rc; 930 } 931 932 /** Get filesystem statistics 933 * 934 * @param file File located on the queried file system 935 * @param[out] st Buffer for storing information 936 * 937 * @return EOK on success or a negative error code 938 */ 939 int vfs_statfs(int file, struct statfs *st) 940 { 941 sysarg_t rc, ret; 1204 /** Get filesystem statistics. 1205 * 1206 * @param path Mount point path 1207 * @param st Buffer for storing information 1208 * @return 0 on success. On error -1 is returned and errno is set. 1209 */ 1210 int statfs(const char *path, struct statfs *st) 1211 { 1212 sysarg_t rc, rc_orig; 942 1213 aid_t req; 943 944 async_exch_t *exch = vfs_exchange_begin(); 945 946 req = async_send_1(exch, VFS_IN_STATFS, file, NULL); 1214 size_t pa_size; 1215 1216 char *pa = vfs_absolutize(path, &pa_size); 1217 if (pa == NULL) { 1218 errno = ENOMEM; 1219 return -1; 1220 } 1221 1222 async_exch_t *exch = vfs_exchange_begin(); 1223 1224 req = async_send_0(exch, VFS_IN_STATFS, NULL); 1225 rc = async_data_write_start(exch, pa, pa_size); 1226 if (rc != EOK) 1227 goto exit; 1228 947 1229 rc = async_data_read_start(exch, (void *) st, sizeof(*st)); 948 1230 949 vfs_exchange_end(exch); 950 async_wait_for(req, &ret); 951 952 rc = (ret != EOK ? ret : rc); 953 954 return rc; 955 } 956 957 /** Get filesystem statistics 958 * 959 * @param file Path pointing to the queried file system 960 * @param[out] st Buffer for storing information 961 * 962 * @return EOK on success or a negative error code 963 */ 964 int vfs_statfs_path(const char *path, struct statfs *st) 965 { 966 int file = vfs_lookup(path, 0); 967 if (file < 0) 968 return file; 969 970 int rc = vfs_statfs(file, st); 971 972 vfs_put(file); 973 974 return rc; 975 } 976 977 /** Synchronize file 978 * 979 * @param file File handle to synchronize 980 * 981 * @return EOK on success or a negative error code 982 */ 983 int vfs_sync(int file) 984 { 985 async_exch_t *exch = vfs_exchange_begin(); 986 int rc = async_req_1_0(exch, VFS_IN_SYNC, file); 987 vfs_exchange_end(exch); 988 989 return rc; 990 } 991 992 /** Unlink a file or directory 993 * 994 * Unlink a name from a parent directory. The caller can supply the file handle 995 * of the unlinked child in order to detect a possible race with vfs_link() and 996 * avoid unlinking a wrong file. If the last link for a file or directory is 997 * removed, the FS implementation will deallocate its resources. 998 * 999 * @param parent File handle of the parent directory node 1000 * @param child Old name to be unlinked 1001 * @param expect File handle of the unlinked child 1002 * 1003 * @return EOK on success or a negative error code 1004 */ 1005 int vfs_unlink(int parent, const char *child, int expect) 1006 { 1007 sysarg_t rc; 1008 aid_t req; 1009 1010 async_exch_t *exch = vfs_exchange_begin(); 1011 1012 req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL); 1013 rc = async_data_write_start(exch, child, str_size(child)); 1014 1015 vfs_exchange_end(exch); 1016 1017 sysarg_t rc_orig; 1231 exit: 1232 vfs_exchange_end(exch); 1233 free(pa); 1018 1234 async_wait_for(req, &rc_orig); 1019 1020 if (rc_orig != EOK) 1021 return (int) rc_orig; 1022 return rc; 1023 } 1024 1025 /** Unlink a file or directory 1026 * 1027 * Unlink a path. If the last link for a file or directory is removed, the FS 1028 * implementation will deallocate its resources. 1029 * 1030 * @param path Old path to be unlinked 1031 * 1032 * @return EOK on success or a negative error code 1033 */ 1034 int vfs_unlink_path(const char *path) 1035 { 1036 int expect = vfs_lookup(path, 0); 1037 if (expect < 0) 1038 return expect; 1039 1040 char *child; 1041 int parent = get_parent_and_child(path, &child); 1042 if (parent < 0) { 1043 vfs_put(expect); 1044 return parent; 1045 } 1046 1047 int rc = vfs_unlink(parent, child, expect); 1048 1049 free(child); 1050 vfs_put(parent); 1051 vfs_put(expect); 1052 return rc; 1053 } 1054 1055 /** Unmount a file system 1056 * 1057 * @param mp File handle representing the mount-point 1058 * 1059 * @return EOK on success or a negative error code 1060 */ 1061 int vfs_unmount(int mp) 1062 { 1063 async_exch_t *exch = vfs_exchange_begin(); 1064 int rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp); 1065 vfs_exchange_end(exch); 1066 return rc; 1067 } 1068 1069 /** Unmount a file system 1070 * 1071 * @param mpp Mount-point path 1072 * 1073 * @return EOK on success or a negative error code 1074 */ 1075 int vfs_unmount_path(const char *mpp) 1076 { 1077 int mp = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY); 1078 if (mp < 0) 1079 return mp; 1080 1081 int rc = vfs_unmount(mp); 1082 vfs_put(mp); 1083 return rc; 1084 } 1085 1086 /** Walk a path starting in a parent node 1087 * 1088 * @param parent File handle of the parent node where the walk starts 1089 * @param path Parent-relative path to be walked 1090 * @param flags Flags influencing the walk 1091 * 1092 * @retrun File handle representing the result on success or 1093 * a negative error code on error 1094 */ 1095 int vfs_walk(int parent, const char *path, int flags) 1096 { 1097 async_exch_t *exch = vfs_exchange_begin(); 1098 1099 ipc_call_t answer; 1100 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer); 1101 sysarg_t rc = async_data_write_start(exch, path, str_size(path)); 1102 vfs_exchange_end(exch); 1103 1104 sysarg_t rc_orig; 1105 async_wait_for(req, &rc_orig); 1106 1107 if (rc_orig != EOK) 1108 return (int) rc_orig; 1109 1110 if (rc != EOK) 1111 return (int) rc; 1112 1113 return (int) IPC_GET_ARG1(answer); 1114 } 1115 1116 /** Write data 1117 * 1118 * This function fails if it cannot write exactly @a len bytes to the file. 1119 * 1120 * @param file File handle to write to 1121 * @param[inout] pos Position to write to, updated by the actual bytes 1122 * written 1123 * @param buf Data, @a nbytes bytes long 1124 * @param nbytes Number of bytes to write 1125 * 1126 * @return On success, non-negative number of bytes written 1127 * @return On failure, a negative error code 1128 */ 1129 ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte) 1130 { 1131 ssize_t cnt = 0; 1132 ssize_t nwritten = 0; 1133 const uint8_t *bp = (uint8_t *) buf; 1134 int rc; 1135 1136 do { 1137 bp += cnt; 1138 nwritten += cnt; 1139 *pos += cnt; 1140 rc = vfs_write_short(file, *pos, bp, nbyte - nwritten, &cnt); 1141 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0); 1142 1143 if (rc != EOK) 1144 return rc; 1145 1146 *pos += cnt; 1147 return nbyte; 1148 } 1149 1150 /** Write bytes to a file 1151 * 1152 * Write up to @a nbyte bytes from file. The actual number of bytes written 1153 * may be lower, but greater than zero. 1154 * 1155 * @param file File handle to write to 1156 * @param[in] pos Position to write to 1157 * @param buf Buffer to write to 1158 * @param nbyte Maximum number of bytes to write 1159 * @param[out] nread Actual number of bytes written (0 or more) 1160 * 1161 * @return EOK on success or a negative error code 1162 */ 1163 int vfs_write_short(int file, aoff64_t pos, const void *buf, size_t nbyte, 1164 ssize_t *nwritten) 1165 { 1166 sysarg_t rc; 1167 ipc_call_t answer; 1168 aid_t req; 1169 1170 if (nbyte > DATA_XFER_LIMIT) 1171 nbyte = DATA_XFER_LIMIT; 1172 1173 async_exch_t *exch = vfs_exchange_begin(); 1174 1175 req = async_send_3(exch, VFS_IN_WRITE, file, LOWER32(pos), 1176 UPPER32(pos), &answer); 1177 rc = async_data_write_start(exch, (void *) buf, nbyte); 1178 1179 vfs_exchange_end(exch); 1180 1181 if (rc == EOK) 1182 async_wait_for(req, &rc); 1183 else 1184 async_forget(req); 1185 1186 if (rc != EOK) 1187 return rc; 1188 1189 *nwritten = (ssize_t) IPC_GET_ARG1(answer); 1190 return EOK; 1235 rc = (rc_orig != EOK ? rc_orig : rc); 1236 1237 if (rc != EOK) { 1238 errno = rc; 1239 return -1; 1240 } 1241 1242 return 0; 1191 1243 } 1192 1244
Note:
See TracChangeset
for help on using the changeset viewer.