source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 79ea5af

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

Rename unlink() to vfs_unlink_path() and _vfs_unlink() to vfs_unlink()

  • Also, remove rmdir()
  • Property mode set to 100644
File size: 24.2 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
794int vfs_unlink(int parent, const char *child, int expect)
795{
796 sysarg_t rc;
797 aid_t req;
798
799 async_exch_t *exch = vfs_exchange_begin();
800
801 req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
802 rc = async_data_write_start(exch, child, str_size(child));
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 or a negative error code otherwise
818 */
819int vfs_unlink_path(const char *path)
820{
821 size_t pa_size;
822 char *pa = vfs_absolutize(path, &pa_size);
823 if (!pa)
824 return ENOMEM;
825
826 int parent;
827 int expect = vfs_lookup(path, 0);
828 if (expect < 0) {
829 free(pa);
830 return expect;
831 }
832
833 char *slash = str_rchr(pa, L'/');
834 if (slash != pa) {
835 *slash = '\0';
836 parent = vfs_lookup(pa, 0);
837 *slash = '/';
838 } else {
839 parent = vfs_root();
840 }
841
842 if (parent < 0) {
843 free(pa);
844 close(expect);
845 return parent;
846 }
847
848 int rc = vfs_unlink(parent, slash, expect);
849
850 free(pa);
851 close(parent);
852 close(expect);
853 return rc;
854}
855
856/** Rename directory entry.
857 *
858 * @param old Old name
859 * @param new New name
860 *
861 * @return 0 on success. On error returns -1 and sets errno.
862 */
863int rename(const char *old, const char *new)
864{
865 sysarg_t rc;
866 sysarg_t rc_orig;
867 aid_t req;
868
869 size_t olda_size;
870 char *olda = vfs_absolutize(old, &olda_size);
871 if (olda == NULL) {
872 errno = ENOMEM;
873 return -1;
874 }
875
876 size_t newa_size;
877 char *newa = vfs_absolutize(new, &newa_size);
878 if (newa == NULL) {
879 free(olda);
880 errno = ENOMEM;
881 return -1;
882 }
883
884 async_exch_t *exch = vfs_exchange_begin();
885 int root = vfs_root();
886 if (root < 0) {
887 free(olda);
888 free(newa);
889 errno = ENOENT;
890 return -1;
891 }
892
893 req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
894 rc = async_data_write_start(exch, olda, olda_size);
895 if (rc != EOK) {
896 vfs_exchange_end(exch);
897 free(olda);
898 free(newa);
899 close(root);
900 async_wait_for(req, &rc_orig);
901 if (rc_orig != EOK)
902 rc = rc_orig;
903 if (rc != EOK) {
904 errno = rc;
905 return -1;
906 }
907 return 0;
908 }
909 rc = async_data_write_start(exch, newa, newa_size);
910 if (rc != EOK) {
911 vfs_exchange_end(exch);
912 free(olda);
913 free(newa);
914 close(root);
915 async_wait_for(req, &rc_orig);
916 if (rc_orig != EOK)
917 rc = rc_orig;
918 if (rc != EOK) {
919 errno = rc;
920 return -1;
921 }
922 return 0;
923 }
924 vfs_exchange_end(exch);
925 free(olda);
926 free(newa);
927 close(root);
928 async_wait_for(req, &rc);
929
930 if (rc != EOK) {
931 errno = rc;
932 return -1;
933 }
934
935 return 0;
936}
937
938/** Change working directory.
939 *
940 * @param path Path
941 * @return 0 on success. On error returns -1 and sets errno.
942 */
943int chdir(const char *path)
944{
945 size_t abs_size;
946 char *abs = vfs_absolutize(path, &abs_size);
947 if (!abs) {
948 errno = ENOMEM;
949 return -1;
950 }
951
952 int fd = vfs_lookup(abs, WALK_DIRECTORY);
953 if (fd < 0) {
954 free(abs);
955 errno = fd;
956 return -1;
957 }
958
959 fibril_mutex_lock(&cwd_mutex);
960
961 if (cwd_fd >= 0)
962 close(cwd_fd);
963
964 if (cwd_path)
965 free(cwd_path);
966
967 cwd_fd = fd;
968 cwd_path = abs;
969 cwd_size = abs_size;
970
971 fibril_mutex_unlock(&cwd_mutex);
972 return 0;
973}
974
975/** Get current working directory path.
976 *
977 * @param buf Buffer
978 * @param size Size of @a buf
979 * @return On success returns @a buf. On failure returns @c NULL and sets errno.
980 */
981char *getcwd(char *buf, size_t size)
982{
983 if (size == 0) {
984 errno = EINVAL;
985 return NULL;
986 }
987
988 fibril_mutex_lock(&cwd_mutex);
989
990 if ((cwd_size == 0) || (size < cwd_size + 1)) {
991 fibril_mutex_unlock(&cwd_mutex);
992 errno = ERANGE;
993 return NULL;
994 }
995
996 str_cpy(buf, size, cwd_path);
997 fibril_mutex_unlock(&cwd_mutex);
998
999 return buf;
1000}
1001
1002/** Open session to service represented by a special file.
1003 *
1004 * Given that the file referred to by @a fildes represents a service,
1005 * open a session to that service.
1006 *
1007 * @param fildes File descriptor
1008 * @param iface Interface to connect to (XXX Should be automatic)
1009 * @return On success returns session pointer. On error returns @c NULL.
1010 */
1011async_sess_t *vfs_fd_session(int file, iface_t iface)
1012{
1013 struct stat stat;
1014 int rc = vfs_stat(file, &stat);
1015 if (rc != 0)
1016 return NULL;
1017
1018 if (stat.service == 0)
1019 return NULL;
1020
1021 return loc_service_connect(stat.service, iface, 0);
1022}
1023
1024static void process_mp(const char *path, struct stat *stat, list_t *mtab_list)
1025{
1026 mtab_ent_t *ent;
1027
1028 ent = (mtab_ent_t *) malloc(sizeof(mtab_ent_t));
1029 if (!ent)
1030 return;
1031
1032 link_initialize(&ent->link);
1033 str_cpy(ent->mp, sizeof(ent->mp), path);
1034 ent->service_id = stat->service_id;
1035
1036 struct statfs stfs;
1037 if (vfs_statfs_path(path, &stfs) == EOK)
1038 str_cpy(ent->fs_name, sizeof(ent->fs_name), stfs.fs_name);
1039 else
1040 str_cpy(ent->fs_name, sizeof(ent->fs_name), "?");
1041
1042 list_append(&ent->link, mtab_list);
1043}
1044
1045static int vfs_get_mtab_visit(const char *path, list_t *mtab_list,
1046 fs_handle_t fs_handle, service_id_t service_id)
1047{
1048 DIR *dir;
1049 struct dirent *dirent;
1050
1051 dir = opendir(path);
1052 if (!dir)
1053 return ENOENT;
1054
1055 while ((dirent = readdir(dir)) != NULL) {
1056 char *child;
1057 struct stat st;
1058 int rc;
1059
1060 rc = asprintf(&child, "%s/%s", path, dirent->d_name);
1061 if (rc < 0) {
1062 closedir(dir);
1063 return rc;
1064 }
1065
1066 char *pa = vfs_absolutize(child, NULL);
1067 if (!pa) {
1068 free(child);
1069 closedir(dir);
1070 return ENOMEM;
1071 }
1072
1073 free(child);
1074 child = pa;
1075
1076 rc = vfs_stat_path(child, &st);
1077 if (rc != 0) {
1078 free(child);
1079 closedir(dir);
1080 return rc;
1081 }
1082
1083 if (st.fs_handle != fs_handle || st.service_id != service_id) {
1084 /*
1085 * We have discovered a mountpoint.
1086 */
1087 process_mp(child, &st, mtab_list);
1088 }
1089
1090 if (st.is_directory) {
1091 (void) vfs_get_mtab_visit(child, mtab_list,
1092 st.fs_handle, st.service_id);
1093 }
1094
1095 free(child);
1096 }
1097
1098 closedir(dir);
1099 return EOK;
1100}
1101
1102int vfs_get_mtab_list(list_t *mtab_list)
1103{
1104 struct stat st;
1105
1106 int rc = vfs_stat_path("/", &st);
1107 if (rc != 0)
1108 return rc;
1109
1110 process_mp("/", &st, mtab_list);
1111
1112 return vfs_get_mtab_visit("/", mtab_list, st.fs_handle, st.service_id);
1113}
1114
1115/** Get filesystem statistics.
1116 *
1117 * @param file File located on the queried file system
1118 * @param st Buffer for storing information
1119 * @return EOK on success or a negative error code otherwise.
1120 */
1121int vfs_statfs(int file, struct statfs *st)
1122{
1123 sysarg_t rc, ret;
1124 aid_t req;
1125
1126 async_exch_t *exch = vfs_exchange_begin();
1127
1128 req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
1129 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
1130
1131 vfs_exchange_end(exch);
1132 async_wait_for(req, &ret);
1133
1134 rc = (ret != EOK ? ret : rc);
1135
1136 return rc;
1137}
1138/** Get filesystem statistics.
1139 *
1140 * @param path Mount point path
1141 * @param st Buffer for storing information
1142 * @return EOK on success or a negative error code otherwise.
1143 */
1144int vfs_statfs_path(const char *path, struct statfs *st)
1145{
1146 int file = vfs_lookup(path, 0);
1147 if (file < 0)
1148 return file;
1149
1150 int rc = vfs_statfs(file, st);
1151
1152 close(file);
1153
1154 return rc;
1155}
1156
1157int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
1158{
1159 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
1160 0, vfs_exch);
1161}
1162
1163int vfs_receive_handle(bool high_descriptor)
1164{
1165 ipc_callid_t callid;
1166 if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
1167 async_answer_0(callid, EINVAL);
1168 return EINVAL;
1169 }
1170
1171 async_exch_t *vfs_exch = vfs_exchange_begin();
1172
1173 async_state_change_finalize(callid, vfs_exch);
1174
1175 sysarg_t ret;
1176 sysarg_t rc = async_req_1_1(vfs_exch, VFS_IN_WAIT_HANDLE,
1177 high_descriptor, &ret);
1178
1179 async_exchange_end(vfs_exch);
1180
1181 if (rc != EOK)
1182 return rc;
1183 return ret;
1184}
1185
1186int vfs_clone(int file_from, int file_to, bool high_descriptor)
1187{
1188 async_exch_t *vfs_exch = vfs_exchange_begin();
1189 int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
1190 (sysarg_t) file_to, (sysarg_t) high_descriptor);
1191 vfs_exchange_end(vfs_exch);
1192 return rc;
1193}
1194
1195/** @}
1196 */
Note: See TracBrowser for help on using the repository browser.