source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 438f355

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 438f355 was 438f355, checked in by Jakub Jermar <jakub@…>, 8 years ago

Move mtab emulation to its own file

  • Property mode set to 100644
File size: 20.4 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
16 *
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.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35#include <vfs/vfs.h>
36#include <vfs/canonify.h>
37#include <vfs/vfs_mtab.h>
38#include <vfs/vfs_sess.h>
39#include <macros.h>
40#include <stdlib.h>
41#include <sys/types.h>
42#include <ipc/services.h>
43#include <ns.h>
44#include <async.h>
45#include <fibril_synch.h>
46#include <errno.h>
47#include <assert.h>
48#include <str.h>
49#include <loc.h>
50#include <ipc/vfs.h>
51#include <ipc/loc.h>
52
53static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
54static async_sess_t *vfs_sess = NULL;
55
56static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
57
58static int cwd_fd = -1;
59static char *cwd_path = NULL;
60static size_t cwd_size = 0;
61
62static FIBRIL_MUTEX_INITIALIZE(root_mutex);
63static int root_fd = -1;
64
65int vfs_root(void)
66{
67 fibril_mutex_lock(&root_mutex);
68 int r;
69 if (root_fd < 0)
70 r = ENOENT;
71 else
72 r = vfs_clone(root_fd, -1, true);
73 fibril_mutex_unlock(&root_mutex);
74 return r;
75}
76
77void vfs_root_set(int nroot)
78{
79 fibril_mutex_lock(&root_mutex);
80 if (root_fd >= 0)
81 vfs_put(root_fd);
82 root_fd = vfs_clone(nroot, -1, true);
83 fibril_mutex_unlock(&root_mutex);
84}
85
86/** Start an async exchange on the VFS session.
87 *
88 * @return New exchange.
89 *
90 */
91async_exch_t *vfs_exchange_begin(void)
92{
93 fibril_mutex_lock(&vfs_mutex);
94
95 while (vfs_sess == NULL) {
96 vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
97 0);
98 }
99
100 fibril_mutex_unlock(&vfs_mutex);
101
102 return async_exchange_begin(vfs_sess);
103}
104
105/** Finish an async exchange on the VFS session.
106 *
107 * @param exch Exchange to be finished.
108 *
109 */
110void vfs_exchange_end(async_exch_t *exch)
111{
112 async_exchange_end(exch);
113}
114
115int vfs_walk(int parent, const char *path, int flags)
116{
117 async_exch_t *exch = vfs_exchange_begin();
118
119 ipc_call_t answer;
120 aid_t req = async_send_2(exch, VFS_IN_WALK, parent, flags, &answer);
121 sysarg_t rc = async_data_write_start(exch, path, str_size(path));
122 vfs_exchange_end(exch);
123
124 sysarg_t rc_orig;
125 async_wait_for(req, &rc_orig);
126
127 if (rc_orig != EOK)
128 return (int) rc_orig;
129
130 if (rc != EOK)
131 return (int) rc;
132
133 return (int) IPC_GET_ARG1(answer);
134}
135
136int vfs_lookup(const char *path, int flags)
137{
138 size_t size;
139 char *p = vfs_absolutize(path, &size);
140 if (!p)
141 return ENOMEM;
142 int root = vfs_root();
143 if (root < 0) {
144 free(p);
145 return ENOENT;
146 }
147 int rc = vfs_walk(root, p, flags);
148 vfs_put(root);
149 free(p);
150 return rc;
151}
152
153int vfs_open(int file, int mode)
154{
155 async_exch_t *exch = vfs_exchange_begin();
156 int rc = async_req_2_0(exch, VFS_IN_OPEN, file, mode);
157 vfs_exchange_end(exch);
158
159 return rc;
160}
161
162int vfs_lookup_open(const char *path, int flags, int mode)
163{
164 int file = vfs_lookup(path, flags);
165 if (file < 0)
166 return file;
167
168 int rc = vfs_open(file, mode);
169 if (rc != EOK) {
170 vfs_put(file);
171 return rc;
172 }
173
174 return file;
175}
176
177char *vfs_absolutize(const char *path, size_t *retlen)
178{
179 char *ncwd_path;
180 char *ncwd_path_nc;
181
182 fibril_mutex_lock(&cwd_mutex);
183 size_t size = str_size(path);
184 if (*path != '/') {
185 if (cwd_path == NULL) {
186 fibril_mutex_unlock(&cwd_mutex);
187 return NULL;
188 }
189 ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
190 if (ncwd_path_nc == NULL) {
191 fibril_mutex_unlock(&cwd_mutex);
192 return NULL;
193 }
194 str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
195 ncwd_path_nc[cwd_size] = '/';
196 ncwd_path_nc[cwd_size + 1] = '\0';
197 } else {
198 ncwd_path_nc = malloc(size + 1);
199 if (ncwd_path_nc == NULL) {
200 fibril_mutex_unlock(&cwd_mutex);
201 return NULL;
202 }
203 ncwd_path_nc[0] = '\0';
204 }
205 str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
206 ncwd_path = canonify(ncwd_path_nc, retlen);
207 if (ncwd_path == NULL) {
208 fibril_mutex_unlock(&cwd_mutex);
209 free(ncwd_path_nc);
210 return NULL;
211 }
212 /*
213 * We need to clone ncwd_path because canonify() works in-place and thus
214 * the address in ncwd_path need not be the same as ncwd_path_nc, even
215 * though they both point into the same dynamically allocated buffer.
216 */
217 ncwd_path = str_dup(ncwd_path);
218 free(ncwd_path_nc);
219 if (ncwd_path == NULL) {
220 fibril_mutex_unlock(&cwd_mutex);
221 return NULL;
222 }
223 fibril_mutex_unlock(&cwd_mutex);
224 return ncwd_path;
225}
226
227int vfs_mount(int mp, const char *fs_name, service_id_t serv, const char *opts,
228 unsigned int flags, unsigned int instance, int *mountedfd)
229{
230 sysarg_t rc, rc1;
231
232 if (!mountedfd)
233 flags |= VFS_MOUNT_NO_REF;
234 if (mp < 0)
235 flags |= VFS_MOUNT_CONNECT_ONLY;
236
237 ipc_call_t answer;
238 async_exch_t *exch = vfs_exchange_begin();
239 aid_t req = async_send_4(exch, VFS_IN_MOUNT, mp, serv, flags, instance,
240 &answer);
241
242 rc1 = async_data_write_start(exch, (void *) opts, str_size(opts));
243 if (rc1 == EOK) {
244 rc1 = async_data_write_start(exch, (void *) fs_name,
245 str_size(fs_name));
246 }
247
248 vfs_exchange_end(exch);
249
250 async_wait_for(req, &rc);
251
252 if (mountedfd)
253 *mountedfd = (int) IPC_GET_ARG1(answer);
254
255 if (rc != EOK)
256 return rc;
257 return rc1;
258}
259
260int vfs_unmount(int mp)
261{
262 async_exch_t *exch = vfs_exchange_begin();
263 int rc = async_req_1_0(exch, VFS_IN_UNMOUNT, mp);
264 vfs_exchange_end(exch);
265 return rc;
266}
267
268int vfs_mount_path(const char *mp, const char *fs_name, const char *fqsn,
269 const char *opts, unsigned int flags, unsigned int instance)
270{
271 int null_id = -1;
272 char null[LOC_NAME_MAXLEN];
273
274 if (str_cmp(fqsn, "") == 0) {
275 /*
276 * No device specified, create a fresh null/%d device instead.
277 */
278 null_id = loc_null_create();
279
280 if (null_id == -1)
281 return ENOMEM;
282
283 snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
284 fqsn = null;
285 }
286
287 if (flags & IPC_FLAG_BLOCKING)
288 flags = VFS_MOUNT_BLOCKING;
289 else
290 flags = 0;
291
292 service_id_t service_id;
293 int res = loc_service_get_id(fqsn, &service_id, flags);
294 if (res != EOK) {
295 if (null_id != -1)
296 loc_null_destroy(null_id);
297
298 return res;
299 }
300
301 size_t mpa_size;
302 char *mpa = vfs_absolutize(mp, &mpa_size);
303 if (mpa == NULL) {
304 if (null_id != -1)
305 loc_null_destroy(null_id);
306
307 return ENOMEM;
308 }
309
310 fibril_mutex_lock(&root_mutex);
311
312 int rc;
313
314 if (str_cmp(mpa, "/") == 0) {
315 /* Mounting root. */
316
317 if (root_fd >= 0) {
318 fibril_mutex_unlock(&root_mutex);
319 if (null_id != -1)
320 loc_null_destroy(null_id);
321 return EBUSY;
322 }
323
324 int root;
325 rc = vfs_mount(-1, fs_name, service_id, opts, flags, instance,
326 &root);
327 if (rc == EOK)
328 root_fd = root;
329 } else {
330 if (root_fd < 0) {
331 fibril_mutex_unlock(&root_mutex);
332 if (null_id != -1)
333 loc_null_destroy(null_id);
334 return EINVAL;
335 }
336
337 int mpfd = vfs_walk(root_fd, mpa, WALK_DIRECTORY);
338 if (mpfd >= 0) {
339 rc = vfs_mount(mpfd, fs_name, service_id, opts, flags,
340 instance, NULL);
341 vfs_put(mpfd);
342 } else {
343 rc = mpfd;
344 }
345 }
346
347 fibril_mutex_unlock(&root_mutex);
348
349 if ((rc != EOK) && (null_id != -1))
350 loc_null_destroy(null_id);
351
352 return (int) rc;
353}
354
355int vfs_unmount_path(const char *mpp)
356{
357 int mp = vfs_lookup(mpp, WALK_MOUNT_POINT | WALK_DIRECTORY);
358 if (mp < 0)
359 return mp;
360
361 int rc = vfs_unmount(mp);
362 vfs_put(mp);
363 return rc;
364}
365
366/** Close file.
367 *
368 * @param fildes File descriptor
369 * @return EOK on success or a negative error code otherwise.
370 */
371int vfs_put(int fildes)
372{
373 sysarg_t rc;
374
375 async_exch_t *exch = vfs_exchange_begin();
376 rc = async_req_1_0(exch, VFS_IN_PUT, fildes);
377 vfs_exchange_end(exch);
378
379 if (rc != EOK) {
380 errno = rc;
381 return -1;
382 }
383
384 return 0;
385}
386
387/** Read bytes from file.
388 *
389 * Read up to @a nbyte bytes from file. The actual number of bytes read
390 * may be lower, but greater than zero if there are any bytes available.
391 * If there are no bytes available for reading, then the function will
392 * return success with zero bytes read.
393 *
394 * @param file File descriptor
395 * @param pos Position to read from
396 * @param buf Buffer
397 * @param nbyte Maximum number of bytes to read
398 * @param nread Place to store actual number of bytes read (0 or more)
399 *
400 * @return EOK on success, non-zero error code on error.
401 */
402int vfs_read_short(int file, aoff64_t pos, void *buf, size_t nbyte,
403 ssize_t *nread)
404{
405 sysarg_t rc;
406 ipc_call_t answer;
407 aid_t req;
408
409 if (nbyte > DATA_XFER_LIMIT)
410 nbyte = DATA_XFER_LIMIT;
411
412 async_exch_t *exch = vfs_exchange_begin();
413
414 req = async_send_3(exch, VFS_IN_READ, file, LOWER32(pos),
415 UPPER32(pos), &answer);
416 rc = async_data_read_start(exch, (void *) buf, nbyte);
417
418 vfs_exchange_end(exch);
419
420 if (rc == EOK)
421 async_wait_for(req, &rc);
422 else
423 async_forget(req);
424
425 if (rc != EOK)
426 return rc;
427
428 *nread = (ssize_t) IPC_GET_ARG1(answer);
429 return EOK;
430}
431
432/** Write bytes to file.
433 *
434 * Write up to @a nbyte bytes from file. The actual number of bytes written
435 * may be lower, but greater than zero.
436 *
437 * @param file File descriptor
438 * @param pos Position to write to
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 */
445int vfs_write_short(int file, aoff64_t pos, 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_3(exch, VFS_IN_WRITE, file, LOWER32(pos),
458 UPPER32(pos), &answer);
459 rc = async_data_write_start(exch, (void *) buf, nbyte);
460
461 vfs_exchange_end(exch);
462
463 if (rc == EOK)
464 async_wait_for(req, &rc);
465 else
466 async_forget(req);
467
468 if (rc != EOK)
469 return rc;
470
471 *nwritten = (ssize_t) IPC_GET_ARG1(answer);
472 return EOK;
473}
474
475/** Read data.
476 *
477 * Read up to @a nbytes bytes from file if available. This function always reads
478 * all the available bytes up to @a nbytes.
479 *
480 * @param fildes File descriptor
481 * @param pos Pointer to position to read from
482 * @param buf Buffer, @a nbytes bytes long
483 * @param nbytes Number of bytes to read
484 *
485 * @return On success, non-negative number of bytes red.
486 * On failure, a negative error code.
487 */
488ssize_t vfs_read(int file, aoff64_t *pos, void *buf, size_t nbyte)
489{
490 ssize_t cnt = 0;
491 size_t nread = 0;
492 uint8_t *bp = (uint8_t *) buf;
493 int rc;
494
495 do {
496 bp += cnt;
497 nread += cnt;
498 *pos += cnt;
499 rc = vfs_read_short(file, *pos, bp, nbyte - nread, &cnt);
500 } while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
501
502 if (rc != EOK)
503 return rc;
504
505 *pos += cnt;
506 return nread + cnt;
507}
508
509/** Write data.
510 *
511 * This function fails if it cannot write exactly @a len bytes to the file.
512 *
513 * @param file File descriptor
514 * @param pos Pointer to position to write to
515 * @param buf Data, @a nbytes bytes long
516 * @param nbytes Number of bytes to write
517 *
518 * @return On success, non-negative number of bytes written.
519 * On failure, a negative error code.
520 */
521ssize_t vfs_write(int file, aoff64_t *pos, const void *buf, size_t nbyte)
522{
523 ssize_t cnt = 0;
524 ssize_t nwritten = 0;
525 const uint8_t *bp = (uint8_t *) buf;
526 int rc;
527
528 do {
529 bp += cnt;
530 nwritten += cnt;
531 *pos += cnt;
532 rc = vfs_write_short(file, *pos, bp, nbyte - nwritten, &cnt);
533 } while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
534
535 if (rc != EOK)
536 return rc;
537
538 *pos += cnt;
539 return nbyte;
540}
541
542/** Synchronize file.
543 *
544 * @param fildes File descriptor
545 * @return EOK on success or a negative error code otherwise.
546 */
547int vfs_sync(int file)
548{
549 async_exch_t *exch = vfs_exchange_begin();
550 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, file);
551 vfs_exchange_end(exch);
552
553 return rc;
554}
555
556/** Truncate file to a specified length.
557 *
558 * Truncate file so that its size is exactly @a length
559 *
560 * @param fildes File descriptor
561 * @param length Length
562 *
563 * @return EOK on success or a negative erroc code otherwise.
564 */
565int vfs_resize(int file, aoff64_t length)
566{
567 sysarg_t rc;
568
569 async_exch_t *exch = vfs_exchange_begin();
570 rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
571 UPPER32(length));
572 vfs_exchange_end(exch);
573
574 return rc;
575}
576
577/** Get file status.
578 *
579 * @param file File descriptor
580 * @param stat Place to store file information
581 *
582 * @return EOK on success or a negative error code otherwise.
583 */
584int vfs_stat(int file, struct stat *stat)
585{
586 sysarg_t rc;
587 aid_t req;
588
589 async_exch_t *exch = vfs_exchange_begin();
590
591 req = async_send_1(exch, VFS_IN_STAT, file, NULL);
592 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
593 if (rc != EOK) {
594 vfs_exchange_end(exch);
595
596 sysarg_t rc_orig;
597 async_wait_for(req, &rc_orig);
598
599 if (rc_orig != EOK)
600 rc = rc_orig;
601
602 return rc;
603 }
604
605 vfs_exchange_end(exch);
606 async_wait_for(req, &rc);
607
608 return rc;
609}
610
611/** Get file status.
612 *
613 * @param path Path to file
614 * @param stat Place to store file information
615 *
616 * @return EOK on success or a negative error code otherwise.
617 */
618int vfs_stat_path(const char *path, struct stat *stat)
619{
620 int file = vfs_lookup(path, 0);
621 if (file < 0)
622 return file;
623
624 int rc = vfs_stat(file, stat);
625
626 vfs_put(file);
627
628 return rc;
629}
630
631static int get_parent_and_child(const char *path, char **child)
632{
633 size_t size;
634 char *apath = vfs_absolutize(path, &size);
635 if (!apath)
636 return ENOMEM;
637
638 char *slash = str_rchr(apath, L'/');
639 int parent;
640 if (slash == apath) {
641 parent = vfs_root();
642 *child = apath;
643 } else {
644 *slash = '\0';
645 parent = vfs_lookup(apath, WALK_DIRECTORY);
646 if (parent < 0) {
647 free(apath);
648 return parent;
649 }
650 *slash = '/';
651 *child = str_dup(slash);
652 free(apath);
653 if (!*child) {
654 vfs_put(parent);
655 return ENOMEM;
656 }
657 }
658
659 return parent;
660}
661
662int vfs_link(int parent, const char *child, vfs_file_kind_t kind)
663{
664 int flags = (kind == KIND_DIRECTORY) ? WALK_DIRECTORY : WALK_REGULAR;
665 int file = vfs_walk(parent, child, WALK_MUST_CREATE | flags);
666
667 if (file < 0)
668 return file;
669
670 vfs_put(file);
671
672 return EOK;
673}
674
675/** Link a file or directory.
676 *
677 * @param path Path
678 * @param kind Kind of the file to be created.
679 * @return EOK on success or a negative error code otherwise
680 */
681int vfs_link_path(const char *path, vfs_file_kind_t kind)
682{
683 char *child;
684 int parent = get_parent_and_child(path, &child);
685 if (parent < 0)
686 return parent;
687
688 int rc = vfs_link(parent, child, kind);
689
690 free(child);
691 vfs_put(parent);
692 return rc;
693}
694
695int vfs_unlink(int parent, const char *child, int expect)
696{
697 sysarg_t rc;
698 aid_t req;
699
700 async_exch_t *exch = vfs_exchange_begin();
701
702 req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
703 rc = async_data_write_start(exch, child, str_size(child));
704
705 vfs_exchange_end(exch);
706
707 sysarg_t rc_orig;
708 async_wait_for(req, &rc_orig);
709
710 if (rc_orig != EOK)
711 return (int) rc_orig;
712 return rc;
713}
714
715/** Unlink a file or directory.
716 *
717 * @param path Path
718 * @return EOK on success or a negative error code otherwise
719 */
720int vfs_unlink_path(const char *path)
721{
722 int expect = vfs_lookup(path, 0);
723 if (expect < 0)
724 return expect;
725
726 char *child;
727 int parent = get_parent_and_child(path, &child);
728 if (parent < 0) {
729 vfs_put(expect);
730 return parent;
731 }
732
733 int rc = vfs_unlink(parent, child, expect);
734
735 free(child);
736 vfs_put(parent);
737 vfs_put(expect);
738 return rc;
739}
740
741/** Rename directory entry.
742 *
743 * @param old Old name
744 * @param new New name
745 *
746 * @return EOK on success or a negative error code otherwise.
747 */
748int vfs_rename_path(const char *old, const char *new)
749{
750 sysarg_t rc;
751 sysarg_t rc_orig;
752 aid_t req;
753
754 size_t olda_size;
755 char *olda = vfs_absolutize(old, &olda_size);
756 if (olda == NULL)
757 return ENOMEM;
758
759 size_t newa_size;
760 char *newa = vfs_absolutize(new, &newa_size);
761 if (newa == NULL) {
762 free(olda);
763 return ENOMEM;
764 }
765
766 async_exch_t *exch = vfs_exchange_begin();
767 int root = vfs_root();
768 if (root < 0) {
769 free(olda);
770 free(newa);
771 return ENOENT;
772 }
773
774 req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
775 rc = async_data_write_start(exch, olda, olda_size);
776 if (rc != EOK) {
777 vfs_exchange_end(exch);
778 free(olda);
779 free(newa);
780 vfs_put(root);
781 async_wait_for(req, &rc_orig);
782 if (rc_orig != EOK)
783 rc = rc_orig;
784 return rc;
785 }
786 rc = async_data_write_start(exch, newa, newa_size);
787 if (rc != EOK) {
788 vfs_exchange_end(exch);
789 free(olda);
790 free(newa);
791 vfs_put(root);
792 async_wait_for(req, &rc_orig);
793 if (rc_orig != EOK)
794 rc = rc_orig;
795 return rc;
796 }
797 vfs_exchange_end(exch);
798 free(olda);
799 free(newa);
800 vfs_put(root);
801 async_wait_for(req, &rc);
802
803 return rc;
804}
805
806/** Change working directory.
807 *
808 * @param path Path
809 * @return EOK on success or a negative error code otherwise.
810 */
811int vfs_cwd_set(const char *path)
812{
813 size_t abs_size;
814 char *abs = vfs_absolutize(path, &abs_size);
815 if (!abs)
816 return ENOMEM;
817
818 int fd = vfs_lookup(abs, WALK_DIRECTORY);
819 if (fd < 0) {
820 free(abs);
821 return fd;
822 }
823
824 fibril_mutex_lock(&cwd_mutex);
825
826 if (cwd_fd >= 0)
827 vfs_put(cwd_fd);
828
829 if (cwd_path)
830 free(cwd_path);
831
832 cwd_fd = fd;
833 cwd_path = abs;
834 cwd_size = abs_size;
835
836 fibril_mutex_unlock(&cwd_mutex);
837 return EOK;
838}
839
840/** Get current working directory path.
841 *
842 * @param buf Buffer
843 * @param size Size of @a buf
844 * @return EOK on success and a non-negative error code otherwise.
845 */
846int vfs_cwd_get(char *buf, size_t size)
847{
848 fibril_mutex_lock(&cwd_mutex);
849
850 if ((cwd_size == 0) || (size < cwd_size + 1)) {
851 fibril_mutex_unlock(&cwd_mutex);
852 return ERANGE;
853 }
854
855 str_cpy(buf, size, cwd_path);
856 fibril_mutex_unlock(&cwd_mutex);
857
858 return EOK;
859}
860
861/** Open session to service represented by a special file.
862 *
863 * Given that the file referred to by @a fildes represents a service,
864 * open a session to that service.
865 *
866 * @param fildes File descriptor
867 * @param iface Interface to connect to (XXX Should be automatic)
868 * @return On success returns session pointer. On error returns @c NULL.
869 */
870async_sess_t *vfs_fd_session(int file, iface_t iface)
871{
872 struct stat stat;
873 int rc = vfs_stat(file, &stat);
874 if (rc != 0)
875 return NULL;
876
877 if (stat.service == 0)
878 return NULL;
879
880 return loc_service_connect(stat.service, iface, 0);
881}
882
883/** Get filesystem statistics.
884 *
885 * @param file File located on the queried file system
886 * @param st Buffer for storing information
887 * @return EOK on success or a negative error code otherwise.
888 */
889int vfs_statfs(int file, struct statfs *st)
890{
891 sysarg_t rc, ret;
892 aid_t req;
893
894 async_exch_t *exch = vfs_exchange_begin();
895
896 req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
897 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
898
899 vfs_exchange_end(exch);
900 async_wait_for(req, &ret);
901
902 rc = (ret != EOK ? ret : rc);
903
904 return rc;
905}
906/** Get filesystem statistics.
907 *
908 * @param path Mount point path
909 * @param st Buffer for storing information
910 * @return EOK on success or a negative error code otherwise.
911 */
912int vfs_statfs_path(const char *path, struct statfs *st)
913{
914 int file = vfs_lookup(path, 0);
915 if (file < 0)
916 return file;
917
918 int rc = vfs_statfs(file, st);
919
920 vfs_put(file);
921
922 return rc;
923}
924
925int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
926{
927 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
928 0, vfs_exch);
929}
930
931int vfs_receive_handle(bool high_descriptor)
932{
933 ipc_callid_t callid;
934 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
935 async_answer_0(callid, EINVAL);
936 return EINVAL;
937 }
938
939 async_exch_t *vfs_exch = vfs_exchange_begin();
940
941 async_state_change_finalize(callid, vfs_exch);
942
943 sysarg_t ret;
944 sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE,
945 high_descriptor, &ret);
946
947 async_exchange_end(vfs_exch);
948
949 if (rc != EOK)
950 return rc;
951 return ret;
952}
953
954int vfs_clone(int file_from, int file_to, bool high_descriptor)
955{
956 async_exch_t *vfs_exch = vfs_exchange_begin();
957 int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
958 (sysarg_t) file_to, (sysarg_t) high_descriptor);
959 vfs_exchange_end(vfs_exch);
960 return rc;
961}
962
963/** @}
964 */
Note: See TracBrowser for help on using the repository browser.