source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 23a0368

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

Rename stat() to vfs_stat_path() and fstat() to vfs_stat()

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