source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 35b7d86e

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

Remove VFS_IN_MTAB_GET

The mountpoints in VFS don't know their path anymore and it does not
make much sense to maintain this global mount table when tasks can have
different roots.

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