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

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

Merge open() with posix_open() and provide vfs_lookup_open() instead

vfs_lookup_open() is really just a convenience wrapper around
vfs_lookup() and vfs_open().

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