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

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

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5 up to revision 1926

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