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

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

Remove VFS_IN_UNLINK

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