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

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

Rename fsync() to vfs_sync()

  • Property mode set to 100644
File size: 24.1 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) vfs_resize(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 EOK on success or a negative error code otherwise.
600 */
601int vfs_sync(int file)
602{
603 async_exch_t *exch = vfs_exchange_begin();
604 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, file);
605 vfs_exchange_end(exch);
606
607 return rc;
608}
609
610/** Truncate file to a specified length.
611 *
612 * Truncate file so that its size is exactly @a length
613 *
614 * @param fildes File descriptor
615 * @param length Length
616 *
617 * @return EOK on success or a negative erroc code otherwise.
618 */
619int vfs_resize(int file, aoff64_t length)
620{
621 sysarg_t rc;
622
623 async_exch_t *exch = vfs_exchange_begin();
624 rc = async_req_3_0(exch, VFS_IN_RESIZE, file, LOWER32(length),
625 UPPER32(length));
626 vfs_exchange_end(exch);
627
628 return rc;
629}
630
631/** Get file status.
632 *
633 * @param file File descriptor
634 * @param stat Place to store file information
635 *
636 * @return EOK on success or a negative error code otherwise.
637 */
638int vfs_stat(int file, struct stat *stat)
639{
640 sysarg_t rc;
641 aid_t req;
642
643 async_exch_t *exch = vfs_exchange_begin();
644
645 req = async_send_1(exch, VFS_IN_STAT, file, NULL);
646 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
647 if (rc != EOK) {
648 vfs_exchange_end(exch);
649
650 sysarg_t rc_orig;
651 async_wait_for(req, &rc_orig);
652
653 if (rc_orig != EOK)
654 rc = rc_orig;
655
656 return rc;
657 }
658
659 vfs_exchange_end(exch);
660 async_wait_for(req, &rc);
661
662 return rc;
663}
664
665/** Get file status.
666 *
667 * @param path Path to file
668 * @param stat Place to store file information
669 *
670 * @return EOK on success or a negative error code otherwise.
671 */
672int vfs_stat_path(const char *path, struct stat *stat)
673{
674 int file = vfs_lookup(path, 0);
675 if (file < 0)
676 return file;
677
678 int rc = vfs_stat(file, stat);
679
680 close(file);
681
682 return rc;
683}
684
685/** Open directory.
686 *
687 * @param dirname Directory pathname
688 *
689 * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
690 */
691DIR *opendir(const char *dirname)
692{
693 DIR *dirp = malloc(sizeof(DIR));
694 if (!dirp) {
695 errno = ENOMEM;
696 return NULL;
697 }
698
699 int fd = vfs_lookup(dirname, WALK_DIRECTORY);
700 if (fd < 0) {
701 free(dirp);
702 errno = fd;
703 return NULL;
704 }
705
706 int rc = _vfs_open(fd, MODE_READ);
707 if (rc < 0) {
708 free(dirp);
709 close(fd);
710 errno = rc;
711 return NULL;
712 }
713
714 dirp->fd = fd;
715 dirp->pos = 0;
716 return dirp;
717}
718
719/** Read directory entry.
720 *
721 * @param dirp Open directory
722 * @return Non-NULL pointer to directory entry on success. On error returns
723 * @c NULL and sets errno.
724 */
725struct dirent *readdir(DIR *dirp)
726{
727 int rc;
728 ssize_t len = 0;
729
730 rc = _read_short(dirp->fd, dirp->pos, &dirp->res.d_name[0],
731 NAME_MAX + 1, &len);
732 if (rc != EOK) {
733 errno = rc;
734 return NULL;
735 }
736
737 dirp->pos += len;
738
739 return &dirp->res;
740}
741
742/** Rewind directory position to the beginning.
743 *
744 * @param dirp Open directory
745 */
746void rewinddir(DIR *dirp)
747{
748 dirp->pos = 0;
749}
750
751/** Close directory.
752 *
753 * @param dirp Open directory
754 * @return 0 on success. On error returns -1 and sets errno.
755 */
756int closedir(DIR *dirp)
757{
758 int rc;
759
760 rc = close(dirp->fd);
761 free(dirp);
762
763 /* On error errno was set by close() */
764 return rc;
765}
766
767/** Create directory.
768 *
769 * @param path Path
770 * @param mode File mode
771 * @return 0 on success. On error returns -1 and sets errno.
772 */
773int mkdir(const char *path, mode_t mode)
774{
775 int fd = vfs_lookup(path, WALK_MUST_CREATE | WALK_DIRECTORY);
776 if (fd < 0) {
777 errno = fd;
778 return -1;
779 }
780
781 return close(fd);
782}
783
784int vfs_unlink(int parent, const char *child, int expect)
785{
786 sysarg_t rc;
787 aid_t req;
788
789 async_exch_t *exch = vfs_exchange_begin();
790
791 req = async_send_2(exch, VFS_IN_UNLINK, parent, expect, NULL);
792 rc = async_data_write_start(exch, child, str_size(child));
793
794 vfs_exchange_end(exch);
795
796 sysarg_t rc_orig;
797 async_wait_for(req, &rc_orig);
798
799 if (rc_orig != EOK)
800 return (int) rc_orig;
801 return rc;
802}
803
804/** Unlink file or directory.
805 *
806 * @param path Path
807 * @return EOk on success or a negative error code otherwise
808 */
809int vfs_unlink_path(const char *path)
810{
811 size_t pa_size;
812 char *pa = vfs_absolutize(path, &pa_size);
813 if (!pa)
814 return ENOMEM;
815
816 int parent;
817 int expect = vfs_lookup(path, 0);
818 if (expect < 0) {
819 free(pa);
820 return expect;
821 }
822
823 char *slash = str_rchr(pa, L'/');
824 if (slash != pa) {
825 *slash = '\0';
826 parent = vfs_lookup(pa, 0);
827 *slash = '/';
828 } else {
829 parent = vfs_root();
830 }
831
832 if (parent < 0) {
833 free(pa);
834 close(expect);
835 return parent;
836 }
837
838 int rc = vfs_unlink(parent, slash, expect);
839
840 free(pa);
841 close(parent);
842 close(expect);
843 return rc;
844}
845
846/** Rename directory entry.
847 *
848 * @param old Old name
849 * @param new New name
850 *
851 * @return 0 on success. On error returns -1 and sets errno.
852 */
853int rename(const char *old, const char *new)
854{
855 sysarg_t rc;
856 sysarg_t rc_orig;
857 aid_t req;
858
859 size_t olda_size;
860 char *olda = vfs_absolutize(old, &olda_size);
861 if (olda == NULL) {
862 errno = ENOMEM;
863 return -1;
864 }
865
866 size_t newa_size;
867 char *newa = vfs_absolutize(new, &newa_size);
868 if (newa == NULL) {
869 free(olda);
870 errno = ENOMEM;
871 return -1;
872 }
873
874 async_exch_t *exch = vfs_exchange_begin();
875 int root = vfs_root();
876 if (root < 0) {
877 free(olda);
878 free(newa);
879 errno = ENOENT;
880 return -1;
881 }
882
883 req = async_send_1(exch, VFS_IN_RENAME, root, NULL);
884 rc = async_data_write_start(exch, olda, olda_size);
885 if (rc != EOK) {
886 vfs_exchange_end(exch);
887 free(olda);
888 free(newa);
889 close(root);
890 async_wait_for(req, &rc_orig);
891 if (rc_orig != EOK)
892 rc = rc_orig;
893 if (rc != EOK) {
894 errno = rc;
895 return -1;
896 }
897 return 0;
898 }
899 rc = async_data_write_start(exch, newa, newa_size);
900 if (rc != EOK) {
901 vfs_exchange_end(exch);
902 free(olda);
903 free(newa);
904 close(root);
905 async_wait_for(req, &rc_orig);
906 if (rc_orig != EOK)
907 rc = rc_orig;
908 if (rc != EOK) {
909 errno = rc;
910 return -1;
911 }
912 return 0;
913 }
914 vfs_exchange_end(exch);
915 free(olda);
916 free(newa);
917 close(root);
918 async_wait_for(req, &rc);
919
920 if (rc != EOK) {
921 errno = rc;
922 return -1;
923 }
924
925 return 0;
926}
927
928/** Change working directory.
929 *
930 * @param path Path
931 * @return 0 on success. On error returns -1 and sets errno.
932 */
933int chdir(const char *path)
934{
935 size_t abs_size;
936 char *abs = vfs_absolutize(path, &abs_size);
937 if (!abs) {
938 errno = ENOMEM;
939 return -1;
940 }
941
942 int fd = vfs_lookup(abs, WALK_DIRECTORY);
943 if (fd < 0) {
944 free(abs);
945 errno = fd;
946 return -1;
947 }
948
949 fibril_mutex_lock(&cwd_mutex);
950
951 if (cwd_fd >= 0)
952 close(cwd_fd);
953
954 if (cwd_path)
955 free(cwd_path);
956
957 cwd_fd = fd;
958 cwd_path = abs;
959 cwd_size = abs_size;
960
961 fibril_mutex_unlock(&cwd_mutex);
962 return 0;
963}
964
965/** Get current working directory path.
966 *
967 * @param buf Buffer
968 * @param size Size of @a buf
969 * @return On success returns @a buf. On failure returns @c NULL and sets errno.
970 */
971char *getcwd(char *buf, size_t size)
972{
973 if (size == 0) {
974 errno = EINVAL;
975 return NULL;
976 }
977
978 fibril_mutex_lock(&cwd_mutex);
979
980 if ((cwd_size == 0) || (size < cwd_size + 1)) {
981 fibril_mutex_unlock(&cwd_mutex);
982 errno = ERANGE;
983 return NULL;
984 }
985
986 str_cpy(buf, size, cwd_path);
987 fibril_mutex_unlock(&cwd_mutex);
988
989 return buf;
990}
991
992/** Open session to service represented by a special file.
993 *
994 * Given that the file referred to by @a fildes represents a service,
995 * open a session to that service.
996 *
997 * @param fildes File descriptor
998 * @param iface Interface to connect to (XXX Should be automatic)
999 * @return On success returns session pointer. On error returns @c NULL.
1000 */
1001async_sess_t *vfs_fd_session(int file, iface_t iface)
1002{
1003 struct stat stat;
1004 int rc = vfs_stat(file, &stat);
1005 if (rc != 0)
1006 return NULL;
1007
1008 if (stat.service == 0)
1009 return NULL;
1010
1011 return loc_service_connect(stat.service, iface, 0);
1012}
1013
1014static void process_mp(const char *path, struct stat *stat, list_t *mtab_list)
1015{
1016 mtab_ent_t *ent;
1017
1018 ent = (mtab_ent_t *) malloc(sizeof(mtab_ent_t));
1019 if (!ent)
1020 return;
1021
1022 link_initialize(&ent->link);
1023 str_cpy(ent->mp, sizeof(ent->mp), path);
1024 ent->service_id = stat->service_id;
1025
1026 struct statfs stfs;
1027 if (vfs_statfs_path(path, &stfs) == EOK)
1028 str_cpy(ent->fs_name, sizeof(ent->fs_name), stfs.fs_name);
1029 else
1030 str_cpy(ent->fs_name, sizeof(ent->fs_name), "?");
1031
1032 list_append(&ent->link, mtab_list);
1033}
1034
1035static int vfs_get_mtab_visit(const char *path, list_t *mtab_list,
1036 fs_handle_t fs_handle, service_id_t service_id)
1037{
1038 DIR *dir;
1039 struct dirent *dirent;
1040
1041 dir = opendir(path);
1042 if (!dir)
1043 return ENOENT;
1044
1045 while ((dirent = readdir(dir)) != NULL) {
1046 char *child;
1047 struct stat st;
1048 int rc;
1049
1050 rc = asprintf(&child, "%s/%s", path, dirent->d_name);
1051 if (rc < 0) {
1052 closedir(dir);
1053 return rc;
1054 }
1055
1056 char *pa = vfs_absolutize(child, NULL);
1057 if (!pa) {
1058 free(child);
1059 closedir(dir);
1060 return ENOMEM;
1061 }
1062
1063 free(child);
1064 child = pa;
1065
1066 rc = vfs_stat_path(child, &st);
1067 if (rc != 0) {
1068 free(child);
1069 closedir(dir);
1070 return rc;
1071 }
1072
1073 if (st.fs_handle != fs_handle || st.service_id != service_id) {
1074 /*
1075 * We have discovered a mountpoint.
1076 */
1077 process_mp(child, &st, mtab_list);
1078 }
1079
1080 if (st.is_directory) {
1081 (void) vfs_get_mtab_visit(child, mtab_list,
1082 st.fs_handle, st.service_id);
1083 }
1084
1085 free(child);
1086 }
1087
1088 closedir(dir);
1089 return EOK;
1090}
1091
1092int vfs_get_mtab_list(list_t *mtab_list)
1093{
1094 struct stat st;
1095
1096 int rc = vfs_stat_path("/", &st);
1097 if (rc != 0)
1098 return rc;
1099
1100 process_mp("/", &st, mtab_list);
1101
1102 return vfs_get_mtab_visit("/", mtab_list, st.fs_handle, st.service_id);
1103}
1104
1105/** Get filesystem statistics.
1106 *
1107 * @param file File located on the queried file system
1108 * @param st Buffer for storing information
1109 * @return EOK on success or a negative error code otherwise.
1110 */
1111int vfs_statfs(int file, struct statfs *st)
1112{
1113 sysarg_t rc, ret;
1114 aid_t req;
1115
1116 async_exch_t *exch = vfs_exchange_begin();
1117
1118 req = async_send_1(exch, VFS_IN_STATFS, file, NULL);
1119 rc = async_data_read_start(exch, (void *) st, sizeof(*st));
1120
1121 vfs_exchange_end(exch);
1122 async_wait_for(req, &ret);
1123
1124 rc = (ret != EOK ? ret : rc);
1125
1126 return rc;
1127}
1128/** Get filesystem statistics.
1129 *
1130 * @param path Mount point path
1131 * @param st Buffer for storing information
1132 * @return EOK on success or a negative error code otherwise.
1133 */
1134int vfs_statfs_path(const char *path, struct statfs *st)
1135{
1136 int file = vfs_lookup(path, 0);
1137 if (file < 0)
1138 return file;
1139
1140 int rc = vfs_statfs(file, st);
1141
1142 close(file);
1143
1144 return rc;
1145}
1146
1147int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
1148{
1149 return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t) file,
1150 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,
1167 high_descriptor, &ret);
1168
1169 async_exchange_end(vfs_exch);
1170
1171 if (rc != EOK)
1172 return rc;
1173 return ret;
1174}
1175
1176int vfs_clone(int file_from, int file_to, bool high_descriptor)
1177{
1178 async_exch_t *vfs_exch = vfs_exchange_begin();
1179 int rc = async_req_3_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file_from,
1180 (sysarg_t) file_to, (sysarg_t) high_descriptor);
1181 vfs_exchange_end(vfs_exch);
1182 return rc;
1183}
1184
1185/** @}
1186 */
Note: See TracBrowser for help on using the repository browser.