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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b272c67a was 6afc9d7, checked in by Jiri Svoboda <jiri@…>, 10 years ago

UNIX-like I/O functions should use errno to return error code for many reasons.

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