cstyle
[helenos.git] / uspace / lib / c / generic / vfs / vfs.c
blob63478d9db725a6ab265c29c8d952251891ff4d54
1 /*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup libc
30 * @{
32 /** @file
35 #include <vfs/canonify.h>
36 #include <vfs/vfs.h>
37 #include <vfs/vfs_sess.h>
38 #include <macros.h>
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>
46 #include <sys/types.h>
47 #include <ipc/services.h>
48 #include <ns.h>
49 #include <async.h>
50 #include <fibril_synch.h>
51 #include <errno.h>
52 #include <assert.h>
53 #include <str.h>
54 #include <loc.h>
55 #include <ipc/vfs.h>
56 #include <ipc/loc.h>
58 static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
59 static async_sess_t *vfs_sess = NULL;
61 static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
63 static int cwd_fd = -1;
64 static char *cwd_path = NULL;
65 static size_t cwd_size = 0;
67 /** Start an async exchange on the VFS session.
69 * @return New exchange.
72 async_exch_t *vfs_exchange_begin(void)
74 fibril_mutex_lock(&vfs_mutex);
76 while (vfs_sess == NULL)
77 vfs_sess = service_connect_blocking(EXCHANGE_PARALLEL, SERVICE_VFS,
78 0, 0);
80 fibril_mutex_unlock(&vfs_mutex);
82 return async_exchange_begin(vfs_sess);
85 /** Finish an async exchange on the VFS session.
87 * @param exch Exchange to be finished.
90 void vfs_exchange_end(async_exch_t *exch)
92 async_exchange_end(exch);
95 char *absolutize(const char *path, size_t *retlen)
97 char *ncwd_path;
98 char *ncwd_path_nc;
100 fibril_mutex_lock(&cwd_mutex);
101 size_t size = str_size(path);
102 if (*path != '/') {
103 if (!cwd_path) {
104 fibril_mutex_unlock(&cwd_mutex);
105 return NULL;
107 ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
108 if (!ncwd_path_nc) {
109 fibril_mutex_unlock(&cwd_mutex);
110 return NULL;
112 str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
113 ncwd_path_nc[cwd_size] = '/';
114 ncwd_path_nc[cwd_size + 1] = '\0';
115 } else {
116 ncwd_path_nc = malloc(size + 1);
117 if (!ncwd_path_nc) {
118 fibril_mutex_unlock(&cwd_mutex);
119 return NULL;
121 ncwd_path_nc[0] = '\0';
123 str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
124 ncwd_path = canonify(ncwd_path_nc, retlen);
125 if (!ncwd_path) {
126 fibril_mutex_unlock(&cwd_mutex);
127 free(ncwd_path_nc);
128 return NULL;
131 * We need to clone ncwd_path because canonify() works in-place and thus
132 * the address in ncwd_path need not be the same as ncwd_path_nc, even
133 * though they both point into the same dynamically allocated buffer.
135 ncwd_path = str_dup(ncwd_path);
136 free(ncwd_path_nc);
137 if (!ncwd_path) {
138 fibril_mutex_unlock(&cwd_mutex);
139 return NULL;
141 fibril_mutex_unlock(&cwd_mutex);
142 return ncwd_path;
145 int mount(const char *fs_name, const char *mp, const char *fqsn,
146 const char *opts, unsigned int flags, unsigned int instance)
148 int null_id = -1;
149 char null[LOC_NAME_MAXLEN];
151 if (str_cmp(fqsn, "") == 0) {
152 /* No device specified, create a fresh
153 null/%d device instead */
154 null_id = loc_null_create();
156 if (null_id == -1)
157 return ENOMEM;
159 snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
160 fqsn = null;
163 service_id_t service_id;
164 int res = loc_service_get_id(fqsn, &service_id, flags);
165 if (res != EOK) {
166 if (null_id != -1)
167 loc_null_destroy(null_id);
169 return res;
172 size_t mpa_size;
173 char *mpa = absolutize(mp, &mpa_size);
174 if (!mpa) {
175 if (null_id != -1)
176 loc_null_destroy(null_id);
178 return ENOMEM;
181 async_exch_t *exch = vfs_exchange_begin();
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);
192 if (null_id != -1)
193 loc_null_destroy(null_id);
195 if (rc_orig == EOK)
196 return (int) rc;
197 else
198 return (int) rc_orig;
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);
207 if (null_id != -1)
208 loc_null_destroy(null_id);
210 if (rc_orig == EOK)
211 return (int) rc;
212 else
213 return (int) rc_orig;
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);
222 if (null_id != -1)
223 loc_null_destroy(null_id);
225 if (rc_orig == EOK)
226 return (int) rc;
227 else
228 return (int) rc_orig;
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);
238 if (null_id != -1)
239 loc_null_destroy(null_id);
241 if (rc_orig == EOK)
242 return (int) rc;
243 else
244 return (int) rc_orig;
247 vfs_exchange_end(exch);
248 free(mpa);
249 async_wait_for(req, &rc);
251 if ((rc != EOK) && (null_id != -1))
252 loc_null_destroy(null_id);
254 return (int) rc;
257 int unmount(const char *mp)
259 sysarg_t rc;
260 sysarg_t rc_orig;
261 aid_t req;
262 size_t mpa_size;
263 char *mpa;
265 mpa = absolutize(mp, &mpa_size);
266 if (!mpa)
267 return ENOMEM;
269 async_exch_t *exch = vfs_exchange_begin();
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;
284 vfs_exchange_end(exch);
285 free(mpa);
286 async_wait_for(req, &rc);
288 return (int) rc;
291 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
293 async_exch_t *exch = vfs_exchange_begin();
295 ipc_call_t answer;
296 aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer);
297 sysarg_t rc = async_data_write_start(exch, abs, abs_size);
299 if (rc != EOK) {
300 vfs_exchange_end(exch);
302 sysarg_t rc_orig;
303 async_wait_for(req, &rc_orig);
305 if (rc_orig == EOK)
306 return (int) rc;
307 else
308 return (int) rc_orig;
311 vfs_exchange_end(exch);
312 async_wait_for(req, &rc);
314 if (rc != EOK)
315 return (int) rc;
317 return (int) IPC_GET_ARG1(answer);
320 int open(const char *path, int oflag, ...)
322 size_t abs_size;
323 char *abs = absolutize(path, &abs_size);
324 if (!abs)
325 return ENOMEM;
327 int ret = open_internal(abs, abs_size, L_FILE, oflag);
328 free(abs);
330 return ret;
333 int close(int fildes)
335 sysarg_t rc;
337 async_exch_t *exch = vfs_exchange_begin();
338 rc = async_req_1_0(exch, VFS_IN_CLOSE, fildes);
339 vfs_exchange_end(exch);
341 return (int) rc;
344 ssize_t read(int fildes, void *buf, size_t nbyte)
346 sysarg_t rc;
347 ipc_call_t answer;
348 aid_t req;
350 async_exch_t *exch = vfs_exchange_begin();
352 req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
353 rc = async_data_read_start(exch, (void *)buf, nbyte);
354 if (rc != EOK) {
355 vfs_exchange_end(exch);
357 sysarg_t rc_orig;
358 async_wait_for(req, &rc_orig);
360 if (rc_orig == EOK)
361 return (ssize_t) rc;
362 else
363 return (ssize_t) rc_orig;
365 vfs_exchange_end(exch);
366 async_wait_for(req, &rc);
367 if (rc == EOK)
368 return (ssize_t) IPC_GET_ARG1(answer);
369 else
370 return rc;
373 ssize_t write(int fildes, const void *buf, size_t nbyte)
375 sysarg_t rc;
376 ipc_call_t answer;
377 aid_t req;
379 async_exch_t *exch = vfs_exchange_begin();
381 req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
382 rc = async_data_write_start(exch, (void *)buf, nbyte);
383 if (rc != EOK) {
384 vfs_exchange_end(exch);
386 sysarg_t rc_orig;
387 async_wait_for(req, &rc_orig);
389 if (rc_orig == EOK)
390 return (ssize_t) rc;
391 else
392 return (ssize_t) rc_orig;
394 vfs_exchange_end(exch);
395 async_wait_for(req, &rc);
396 if (rc == EOK)
397 return (ssize_t) IPC_GET_ARG1(answer);
398 else
399 return -1;
402 /** Read entire buffer.
404 * In face of short reads this function continues reading until either
405 * the entire buffer is read or no more data is available (at end of file).
407 * @param fildes File descriptor
408 * @param buf Buffer, @a nbytes bytes long
409 * @param nbytes Number of bytes to read
411 * @return On success, positive number of bytes read.
412 * On failure, negative error code from read().
414 ssize_t read_all(int fildes, void *buf, size_t nbyte)
416 ssize_t cnt = 0;
417 size_t nread = 0;
418 uint8_t *bp = (uint8_t *) buf;
420 do {
421 bp += cnt;
422 nread += cnt;
423 cnt = read(fildes, bp, nbyte - nread);
424 } while (cnt > 0 && (nbyte - nread - cnt) > 0);
426 if (cnt < 0)
427 return cnt;
429 return nread + cnt;
432 /** Write entire buffer.
434 * This function fails if it cannot write exactly @a len bytes to the file.
436 * @param fildes File descriptor
437 * @param buf Data, @a nbytes bytes long
438 * @param nbytes Number of bytes to write
440 * @return EOK on error, return value from write() if writing
441 * failed.
443 ssize_t write_all(int fildes, const void *buf, size_t nbyte)
445 ssize_t cnt = 0;
446 ssize_t nwritten = 0;
447 const uint8_t *bp = (uint8_t *) buf;
449 do {
450 bp += cnt;
451 nwritten += cnt;
452 cnt = write(fildes, bp, nbyte - nwritten);
453 } while (cnt > 0 && ((ssize_t )nbyte - nwritten - cnt) > 0);
455 if (cnt < 0)
456 return cnt;
458 if ((ssize_t)nbyte - nwritten - cnt > 0)
459 return EIO;
461 return nbyte;
464 int fsync(int fildes)
466 async_exch_t *exch = vfs_exchange_begin();
467 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes);
468 vfs_exchange_end(exch);
470 return (int) rc;
473 off64_t lseek(int fildes, off64_t offset, int whence)
475 async_exch_t *exch = vfs_exchange_begin();
477 sysarg_t newoff_lo;
478 sysarg_t newoff_hi;
479 sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes,
480 LOWER32(offset), UPPER32(offset), whence,
481 &newoff_lo, &newoff_hi);
483 vfs_exchange_end(exch);
485 if (rc != EOK)
486 return (off64_t) -1;
488 return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
491 int ftruncate(int fildes, aoff64_t length)
493 sysarg_t rc;
495 async_exch_t *exch = vfs_exchange_begin();
496 rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes,
497 LOWER32(length), UPPER32(length));
498 vfs_exchange_end(exch);
500 return (int) rc;
503 int fstat(int fildes, struct stat *stat)
505 sysarg_t rc;
506 aid_t req;
508 async_exch_t *exch = vfs_exchange_begin();
510 req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
511 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
512 if (rc != EOK) {
513 vfs_exchange_end(exch);
515 sysarg_t rc_orig;
516 async_wait_for(req, &rc_orig);
518 if (rc_orig == EOK)
519 return (ssize_t) rc;
520 else
521 return (ssize_t) rc_orig;
523 vfs_exchange_end(exch);
524 async_wait_for(req, &rc);
526 return rc;
529 int stat(const char *path, struct stat *stat)
531 sysarg_t rc;
532 sysarg_t rc_orig;
533 aid_t req;
535 size_t pa_size;
536 char *pa = absolutize(path, &pa_size);
537 if (!pa)
538 return ENOMEM;
540 async_exch_t *exch = vfs_exchange_begin();
542 req = async_send_0(exch, VFS_IN_STAT, NULL);
543 rc = async_data_write_start(exch, pa, pa_size);
544 if (rc != EOK) {
545 vfs_exchange_end(exch);
546 free(pa);
547 async_wait_for(req, &rc_orig);
548 if (rc_orig == EOK)
549 return (int) rc;
550 else
551 return (int) rc_orig;
553 rc = async_data_read_start(exch, stat, sizeof(struct stat));
554 if (rc != EOK) {
555 vfs_exchange_end(exch);
556 free(pa);
557 async_wait_for(req, &rc_orig);
558 if (rc_orig == EOK)
559 return (int) rc;
560 else
561 return (int) rc_orig;
563 vfs_exchange_end(exch);
564 free(pa);
565 async_wait_for(req, &rc);
566 return rc;
569 DIR *opendir(const char *dirname)
571 DIR *dirp = malloc(sizeof(DIR));
572 if (!dirp)
573 return NULL;
575 size_t abs_size;
576 char *abs = absolutize(dirname, &abs_size);
577 if (!abs) {
578 free(dirp);
579 return NULL;
582 int ret = open_internal(abs, abs_size, L_DIRECTORY, 0);
583 free(abs);
585 if (ret < 0) {
586 free(dirp);
587 return NULL;
590 dirp->fd = ret;
591 return dirp;
594 struct dirent *readdir(DIR *dirp)
596 ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
597 if (len <= 0)
598 return NULL;
599 return &dirp->res;
602 void rewinddir(DIR *dirp)
604 (void) lseek(dirp->fd, 0, SEEK_SET);
607 int closedir(DIR *dirp)
609 (void) close(dirp->fd);
610 free(dirp);
611 return 0;
614 int mkdir(const char *path, mode_t mode)
616 sysarg_t rc;
617 aid_t req;
619 size_t pa_size;
620 char *pa = absolutize(path, &pa_size);
621 if (!pa)
622 return ENOMEM;
624 async_exch_t *exch = vfs_exchange_begin();
626 req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
627 rc = async_data_write_start(exch, pa, pa_size);
628 if (rc != EOK) {
629 vfs_exchange_end(exch);
630 free(pa);
632 sysarg_t rc_orig;
633 async_wait_for(req, &rc_orig);
635 if (rc_orig == EOK)
636 return (int) rc;
637 else
638 return (int) rc_orig;
640 vfs_exchange_end(exch);
641 free(pa);
642 async_wait_for(req, &rc);
643 return rc;
646 static int _unlink(const char *path, int lflag)
648 sysarg_t rc;
649 aid_t req;
651 size_t pa_size;
652 char *pa = absolutize(path, &pa_size);
653 if (!pa)
654 return ENOMEM;
656 async_exch_t *exch = vfs_exchange_begin();
658 req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL);
659 rc = async_data_write_start(exch, pa, pa_size);
660 if (rc != EOK) {
661 vfs_exchange_end(exch);
662 free(pa);
664 sysarg_t rc_orig;
665 async_wait_for(req, &rc_orig);
667 if (rc_orig == EOK)
668 return (int) rc;
669 else
670 return (int) rc_orig;
672 vfs_exchange_end(exch);
673 free(pa);
674 async_wait_for(req, &rc);
675 return rc;
678 int unlink(const char *path)
680 return _unlink(path, L_NONE);
683 int rmdir(const char *path)
685 return _unlink(path, L_DIRECTORY);
688 int rename(const char *old, const char *new)
690 sysarg_t rc;
691 sysarg_t rc_orig;
692 aid_t req;
694 size_t olda_size;
695 char *olda = absolutize(old, &olda_size);
696 if (!olda)
697 return ENOMEM;
699 size_t newa_size;
700 char *newa = absolutize(new, &newa_size);
701 if (!newa) {
702 free(olda);
703 return ENOMEM;
706 async_exch_t *exch = vfs_exchange_begin();
708 req = async_send_0(exch, VFS_IN_RENAME, NULL);
709 rc = async_data_write_start(exch, olda, olda_size);
710 if (rc != EOK) {
711 vfs_exchange_end(exch);
712 free(olda);
713 free(newa);
714 async_wait_for(req, &rc_orig);
715 if (rc_orig == EOK)
716 return (int) rc;
717 else
718 return (int) rc_orig;
720 rc = async_data_write_start(exch, newa, newa_size);
721 if (rc != EOK) {
722 vfs_exchange_end(exch);
723 free(olda);
724 free(newa);
725 async_wait_for(req, &rc_orig);
726 if (rc_orig == EOK)
727 return (int) rc;
728 else
729 return (int) rc_orig;
731 vfs_exchange_end(exch);
732 free(olda);
733 free(newa);
734 async_wait_for(req, &rc);
735 return rc;
738 int chdir(const char *path)
740 size_t abs_size;
741 char *abs = absolutize(path, &abs_size);
742 if (!abs)
743 return ENOMEM;
745 int fd = open_internal(abs, abs_size, L_DIRECTORY, O_DESC);
747 if (fd < 0) {
748 free(abs);
749 return ENOENT;
752 fibril_mutex_lock(&cwd_mutex);
754 if (cwd_fd >= 0)
755 close(cwd_fd);
758 if (cwd_path)
759 free(cwd_path);
761 cwd_fd = fd;
762 cwd_path = abs;
763 cwd_size = abs_size;
765 fibril_mutex_unlock(&cwd_mutex);
766 return EOK;
769 char *getcwd(char *buf, size_t size)
771 if (size == 0)
772 return NULL;
774 fibril_mutex_lock(&cwd_mutex);
776 if ((cwd_size == 0) || (size < cwd_size + 1)) {
777 fibril_mutex_unlock(&cwd_mutex);
778 return NULL;
781 str_cpy(buf, size, cwd_path);
782 fibril_mutex_unlock(&cwd_mutex);
784 return buf;
787 async_sess_t *fd_session(exch_mgmt_t mgmt, int fildes)
789 struct stat stat;
790 int rc = fstat(fildes, &stat);
791 if (rc != 0) {
792 errno = rc;
793 return NULL;
796 if (!stat.service) {
797 errno = ENOENT;
798 return NULL;
801 return loc_service_connect(mgmt, stat.service, 0);
804 int dup2(int oldfd, int newfd)
806 async_exch_t *exch = vfs_exchange_begin();
808 sysarg_t ret;
809 sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret);
811 vfs_exchange_end(exch);
813 if (rc == EOK)
814 return (int) ret;
816 return (int) rc;
819 int fd_wait(void)
821 async_exch_t *exch = vfs_exchange_begin();
823 sysarg_t ret;
824 sysarg_t rc = async_req_0_1(exch, VFS_IN_WAIT_HANDLE, &ret);
826 vfs_exchange_end(exch);
828 if (rc == EOK)
829 return (int) ret;
831 return (int) rc;
834 int get_mtab_list(list_t *mtab_list)
836 sysarg_t rc;
837 aid_t req;
838 size_t i;
839 sysarg_t num_mounted_fs;
841 async_exch_t *exch = vfs_exchange_begin();
843 req = async_send_0(exch, VFS_IN_MTAB_GET, NULL);
845 /* Ask VFS how many filesystems are mounted */
846 rc = async_req_0_1(exch, VFS_IN_PING, &num_mounted_fs);
847 if (rc != EOK)
848 goto exit;
850 for (i = 0; i < num_mounted_fs; ++i) {
851 mtab_ent_t *mtab_ent;
853 mtab_ent = malloc(sizeof(mtab_ent_t));
854 if (!mtab_ent) {
855 rc = ENOMEM;
856 goto exit;
859 memset(mtab_ent, 0, sizeof(mtab_ent_t));
861 rc = async_data_read_start(exch, (void *) mtab_ent->mp,
862 MAX_PATH_LEN);
863 if (rc != EOK)
864 goto exit;
866 rc = async_data_read_start(exch, (void *) mtab_ent->opts,
867 MAX_MNTOPTS_LEN);
868 if (rc != EOK)
869 goto exit;
871 rc = async_data_read_start(exch, (void *) mtab_ent->fs_name,
872 FS_NAME_MAXLEN);
873 if (rc != EOK)
874 goto exit;
876 sysarg_t p[2];
878 rc = async_req_0_2(exch, VFS_IN_PING, &p[0], &p[1]);
879 if (rc != EOK)
880 goto exit;
882 mtab_ent->instance = p[0];
883 mtab_ent->service_id = p[1];
885 link_initialize(&mtab_ent->link);
886 list_append(&mtab_ent->link, mtab_list);
889 exit:
890 async_wait_for(req, &rc);
891 vfs_exchange_end(exch);
892 return rc;
895 int statfs(const char *path, struct statfs *st)
897 sysarg_t rc, rc_orig;
898 aid_t req;
899 size_t pa_size;
901 char *pa = absolutize(path, &pa_size);
902 if (!pa)
903 return ENOMEM;
905 async_exch_t *exch = vfs_exchange_begin();
907 req = async_send_0(exch, VFS_IN_STATFS, NULL);
908 rc = async_data_write_start(exch, pa, pa_size);
909 if (rc != EOK)
910 goto exit;
912 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
914 exit:
915 vfs_exchange_end(exch);
916 free(pa);
917 async_wait_for(req, &rc_orig);
918 return (int) (rc_orig != EOK ? rc_orig : rc);
921 /** @}