source: mainline/uspace/lib/c/generic/vfs/vfs.c@ c23275a

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

Rename chdir() to vfs_cwd_set() and getcwd() to vfs_cwd_get()

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