source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 80743a1

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

Rename (un)mount to vfs_(un)mount_path

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