source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 86ffa27f

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

Merge mainline changes.

  • Property mode set to 100644
File size: 16.8 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/types.h>
46#include <ipc/services.h>
47#include <ns.h>
48#include <async.h>
49#include <fibril_synch.h>
50#include <errno.h>
51#include <assert.h>
52#include <str.h>
53#include <loc.h>
54#include <ipc/vfs.h>
55#include <ipc/loc.h>
56
57static FIBRIL_MUTEX_INITIALIZE(vfs_mutex);
58static async_sess_t *vfs_sess = NULL;
59
60static FIBRIL_MUTEX_INITIALIZE(cwd_mutex);
61
62static int cwd_fd = -1;
63static char *cwd_path = NULL;
64static size_t cwd_size = 0;
65
66/** Start an async exchange on the VFS session.
67 *
68 * @return New exchange.
69 *
70 */
71static async_exch_t *vfs_exchange_begin(void)
72{
73 fibril_mutex_lock(&vfs_mutex);
74
75 while (vfs_sess == NULL)
76 vfs_sess = service_connect_blocking(EXCHANGE_PARALLEL, SERVICE_VFS,
77 0, 0);
78
79 fibril_mutex_unlock(&vfs_mutex);
80
81 return async_exchange_begin(vfs_sess);
82}
83
84/** Finish an async exchange on the VFS session.
85 *
86 * @param exch Exchange to be finished.
87 *
88 */
89static void vfs_exchange_end(async_exch_t *exch)
90{
91 async_exchange_end(exch);
92}
93
94char *absolutize(const char *path, size_t *retlen)
95{
96 char *ncwd_path;
97 char *ncwd_path_nc;
98
99 fibril_mutex_lock(&cwd_mutex);
100 size_t size = str_size(path);
101 if (*path != '/') {
102 if (!cwd_path) {
103 fibril_mutex_unlock(&cwd_mutex);
104 return NULL;
105 }
106 ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
107 if (!ncwd_path_nc) {
108 fibril_mutex_unlock(&cwd_mutex);
109 return NULL;
110 }
111 str_cpy(ncwd_path_nc, cwd_size + 1 + size + 1, cwd_path);
112 ncwd_path_nc[cwd_size] = '/';
113 ncwd_path_nc[cwd_size + 1] = '\0';
114 } else {
115 ncwd_path_nc = malloc(size + 1);
116 if (!ncwd_path_nc) {
117 fibril_mutex_unlock(&cwd_mutex);
118 return NULL;
119 }
120 ncwd_path_nc[0] = '\0';
121 }
122 str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
123 ncwd_path = canonify(ncwd_path_nc, retlen);
124 if (!ncwd_path) {
125 fibril_mutex_unlock(&cwd_mutex);
126 free(ncwd_path_nc);
127 return NULL;
128 }
129 /*
130 * We need to clone ncwd_path because canonify() works in-place and thus
131 * the address in ncwd_path need not be the same as ncwd_path_nc, even
132 * though they both point into the same dynamically allocated buffer.
133 */
134 ncwd_path = str_dup(ncwd_path);
135 free(ncwd_path_nc);
136 if (!ncwd_path) {
137 fibril_mutex_unlock(&cwd_mutex);
138 return NULL;
139 }
140 fibril_mutex_unlock(&cwd_mutex);
141 return ncwd_path;
142}
143
144int mount(const char *fs_name, const char *mp, const char *fqsn,
145 const char *opts, unsigned int flags)
146{
147 int null_id = -1;
148 char null[LOC_NAME_MAXLEN];
149
150 if (str_cmp(fqsn, "") == 0) {
151 /* No device specified, create a fresh
152 null/%d device instead */
153 null_id = loc_null_create();
154
155 if (null_id == -1)
156 return ENOMEM;
157
158 snprintf(null, LOC_NAME_MAXLEN, "null/%d", null_id);
159 fqsn = null;
160 }
161
162 service_id_t service_id;
163 int res = loc_service_get_id(fqsn, &service_id, flags);
164 if (res != EOK) {
165 if (null_id != -1)
166 loc_null_destroy(null_id);
167
168 return res;
169 }
170
171 size_t mpa_size;
172 char *mpa = absolutize(mp, &mpa_size);
173 if (!mpa) {
174 if (null_id != -1)
175 loc_null_destroy(null_id);
176
177 return ENOMEM;
178 }
179
180 async_exch_t *exch = vfs_exchange_begin();
181
182 sysarg_t rc_orig;
183 aid_t req = async_send_2(exch, VFS_IN_MOUNT, service_id, flags, NULL);
184 sysarg_t rc = async_data_write_start(exch, (void *) mpa, mpa_size);
185 if (rc != EOK) {
186 vfs_exchange_end(exch);
187 free(mpa);
188 async_wait_for(req, &rc_orig);
189
190 if (null_id != -1)
191 loc_null_destroy(null_id);
192
193 if (rc_orig == EOK)
194 return (int) rc;
195 else
196 return (int) rc_orig;
197 }
198
199 rc = async_data_write_start(exch, (void *) opts, str_size(opts));
200 if (rc != EOK) {
201 vfs_exchange_end(exch);
202 free(mpa);
203 async_wait_for(req, &rc_orig);
204
205 if (null_id != -1)
206 loc_null_destroy(null_id);
207
208 if (rc_orig == EOK)
209 return (int) rc;
210 else
211 return (int) rc_orig;
212 }
213
214 rc = async_data_write_start(exch, (void *) fs_name, str_size(fs_name));
215 if (rc != EOK) {
216 vfs_exchange_end(exch);
217 free(mpa);
218 async_wait_for(req, &rc_orig);
219
220 if (null_id != -1)
221 loc_null_destroy(null_id);
222
223 if (rc_orig == EOK)
224 return (int) rc;
225 else
226 return (int) rc_orig;
227 }
228
229 /* Ask VFS whether it likes fs_name. */
230 rc = async_req_0_0(exch, VFS_IN_PING);
231 if (rc != EOK) {
232 vfs_exchange_end(exch);
233 free(mpa);
234 async_wait_for(req, &rc_orig);
235
236 if (null_id != -1)
237 loc_null_destroy(null_id);
238
239 if (rc_orig == EOK)
240 return (int) rc;
241 else
242 return (int) rc_orig;
243 }
244
245 vfs_exchange_end(exch);
246 free(mpa);
247 async_wait_for(req, &rc);
248
249 if ((rc != EOK) && (null_id != -1))
250 loc_null_destroy(null_id);
251
252 return (int) rc;
253}
254
255int unmount(const char *mp)
256{
257 sysarg_t rc;
258 sysarg_t rc_orig;
259 aid_t req;
260 size_t mpa_size;
261 char *mpa;
262
263 mpa = absolutize(mp, &mpa_size);
264 if (!mpa)
265 return ENOMEM;
266
267 async_exch_t *exch = vfs_exchange_begin();
268
269 req = async_send_0(exch, VFS_IN_UNMOUNT, NULL);
270 rc = async_data_write_start(exch, (void *) mpa, mpa_size);
271 if (rc != EOK) {
272 vfs_exchange_end(exch);
273 free(mpa);
274 async_wait_for(req, &rc_orig);
275 if (rc_orig == EOK)
276 return (int) rc;
277 else
278 return (int) rc_orig;
279 }
280
281
282 vfs_exchange_end(exch);
283 free(mpa);
284 async_wait_for(req, &rc);
285
286 return (int) rc;
287}
288
289static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
290{
291 async_exch_t *exch = vfs_exchange_begin();
292
293 ipc_call_t answer;
294 aid_t req = async_send_3(exch, VFS_IN_OPEN, lflag, oflag, 0, &answer);
295 sysarg_t rc = async_data_write_start(exch, abs, abs_size);
296
297 if (rc != EOK) {
298 vfs_exchange_end(exch);
299
300 sysarg_t rc_orig;
301 async_wait_for(req, &rc_orig);
302
303 if (rc_orig == EOK)
304 return (int) rc;
305 else
306 return (int) rc_orig;
307 }
308
309 vfs_exchange_end(exch);
310 async_wait_for(req, &rc);
311
312 if (rc != EOK)
313 return (int) rc;
314
315 return (int) IPC_GET_ARG1(answer);
316}
317
318int open(const char *path, int oflag, ...)
319{
320 size_t abs_size;
321 char *abs = absolutize(path, &abs_size);
322 if (!abs)
323 return ENOMEM;
324
325 int ret = open_internal(abs, abs_size, L_FILE, oflag);
326 free(abs);
327
328 return ret;
329}
330
331int open_node(fdi_node_t *node, int oflag)
332{
333 async_exch_t *exch = vfs_exchange_begin();
334
335 ipc_call_t answer;
336 aid_t req = async_send_4(exch, VFS_IN_OPEN_NODE, node->fs_handle,
337 node->service_id, node->index, oflag, &answer);
338
339 vfs_exchange_end(exch);
340
341 sysarg_t rc;
342 async_wait_for(req, &rc);
343
344 if (rc != EOK)
345 return (int) rc;
346
347 return (int) IPC_GET_ARG1(answer);
348}
349
350int close(int fildes)
351{
352 sysarg_t rc;
353
354 async_exch_t *exch = vfs_exchange_begin();
355 rc = async_req_1_0(exch, VFS_IN_CLOSE, fildes);
356 vfs_exchange_end(exch);
357
358 return (int) rc;
359}
360
361ssize_t read(int fildes, void *buf, size_t nbyte)
362{
363 sysarg_t rc;
364 ipc_call_t answer;
365 aid_t req;
366
367 async_exch_t *exch = vfs_exchange_begin();
368
369 req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
370 rc = async_data_read_start(exch, (void *)buf, nbyte);
371 if (rc != EOK) {
372 vfs_exchange_end(exch);
373
374 sysarg_t rc_orig;
375 async_wait_for(req, &rc_orig);
376
377 if (rc_orig == EOK)
378 return (ssize_t) rc;
379 else
380 return (ssize_t) rc_orig;
381 }
382 vfs_exchange_end(exch);
383 async_wait_for(req, &rc);
384 if (rc == EOK)
385 return (ssize_t) IPC_GET_ARG1(answer);
386 else
387 return rc;
388}
389
390ssize_t write(int fildes, const void *buf, size_t nbyte)
391{
392 sysarg_t rc;
393 ipc_call_t answer;
394 aid_t req;
395
396 async_exch_t *exch = vfs_exchange_begin();
397
398 req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
399 rc = async_data_write_start(exch, (void *)buf, nbyte);
400 if (rc != EOK) {
401 vfs_exchange_end(exch);
402
403 sysarg_t rc_orig;
404 async_wait_for(req, &rc_orig);
405
406 if (rc_orig == EOK)
407 return (ssize_t) rc;
408 else
409 return (ssize_t) rc_orig;
410 }
411 vfs_exchange_end(exch);
412 async_wait_for(req, &rc);
413 if (rc == EOK)
414 return (ssize_t) IPC_GET_ARG1(answer);
415 else
416 return -1;
417}
418
419/** Read entire buffer.
420 *
421 * In face of short reads this function continues reading until either
422 * the entire buffer is read or no more data is available (at end of file).
423 *
424 * @param fildes File descriptor
425 * @param buf Buffer, @a nbytes bytes long
426 * @param nbytes Number of bytes to read
427 *
428 * @return On success, positive number of bytes read.
429 * On failure, negative error code from read().
430 */
431ssize_t read_all(int fildes, void *buf, size_t nbyte)
432{
433 ssize_t cnt = 0;
434 size_t nread = 0;
435 uint8_t *bp = (uint8_t *) buf;
436
437 do {
438 bp += cnt;
439 nread += cnt;
440 cnt = read(fildes, bp, nbyte - nread);
441 } while (cnt > 0 && (nbyte - nread - cnt) > 0);
442
443 if (cnt < 0)
444 return cnt;
445
446 return nread + cnt;
447}
448
449/** Write entire buffer.
450 *
451 * This function fails if it cannot write exactly @a len bytes to the file.
452 *
453 * @param fildes File descriptor
454 * @param buf Data, @a nbytes bytes long
455 * @param nbytes Number of bytes to write
456 *
457 * @return EOK on error, return value from write() if writing
458 * failed.
459 */
460ssize_t write_all(int fildes, const void *buf, size_t nbyte)
461{
462 ssize_t cnt = 0;
463 ssize_t nwritten = 0;
464 const uint8_t *bp = (uint8_t *) buf;
465
466 do {
467 bp += cnt;
468 nwritten += cnt;
469 cnt = write(fildes, bp, nbyte - nwritten);
470 } while (cnt > 0 && ((ssize_t )nbyte - nwritten - cnt) > 0);
471
472 if (cnt < 0)
473 return cnt;
474
475 if ((ssize_t)nbyte - nwritten - cnt > 0)
476 return EIO;
477
478 return nbyte;
479}
480
481int fsync(int fildes)
482{
483 async_exch_t *exch = vfs_exchange_begin();
484 sysarg_t rc = async_req_1_0(exch, VFS_IN_SYNC, fildes);
485 vfs_exchange_end(exch);
486
487 return (int) rc;
488}
489
490off64_t lseek(int fildes, off64_t offset, int whence)
491{
492 async_exch_t *exch = vfs_exchange_begin();
493
494 sysarg_t newoff_lo;
495 sysarg_t newoff_hi;
496 sysarg_t rc = async_req_4_2(exch, VFS_IN_SEEK, fildes,
497 LOWER32(offset), UPPER32(offset), whence,
498 &newoff_lo, &newoff_hi);
499
500 vfs_exchange_end(exch);
501
502 if (rc != EOK)
503 return (off64_t) -1;
504
505 return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
506}
507
508int ftruncate(int fildes, aoff64_t length)
509{
510 sysarg_t rc;
511
512 async_exch_t *exch = vfs_exchange_begin();
513 rc = async_req_3_0(exch, VFS_IN_TRUNCATE, fildes,
514 LOWER32(length), UPPER32(length));
515 vfs_exchange_end(exch);
516
517 return (int) rc;
518}
519
520int fstat(int fildes, struct stat *stat)
521{
522 sysarg_t rc;
523 aid_t req;
524
525 async_exch_t *exch = vfs_exchange_begin();
526
527 req = async_send_1(exch, VFS_IN_FSTAT, fildes, NULL);
528 rc = async_data_read_start(exch, (void *) stat, sizeof(struct stat));
529 if (rc != EOK) {
530 vfs_exchange_end(exch);
531
532 sysarg_t rc_orig;
533 async_wait_for(req, &rc_orig);
534
535 if (rc_orig == EOK)
536 return (ssize_t) rc;
537 else
538 return (ssize_t) rc_orig;
539 }
540 vfs_exchange_end(exch);
541 async_wait_for(req, &rc);
542
543 return rc;
544}
545
546int stat(const char *path, struct stat *stat)
547{
548 sysarg_t rc;
549 sysarg_t rc_orig;
550 aid_t req;
551
552 size_t pa_size;
553 char *pa = absolutize(path, &pa_size);
554 if (!pa)
555 return ENOMEM;
556
557 async_exch_t *exch = vfs_exchange_begin();
558
559 req = async_send_0(exch, VFS_IN_STAT, NULL);
560 rc = async_data_write_start(exch, pa, pa_size);
561 if (rc != EOK) {
562 vfs_exchange_end(exch);
563 free(pa);
564 async_wait_for(req, &rc_orig);
565 if (rc_orig == EOK)
566 return (int) rc;
567 else
568 return (int) rc_orig;
569 }
570 rc = async_data_read_start(exch, stat, sizeof(struct stat));
571 if (rc != EOK) {
572 vfs_exchange_end(exch);
573 free(pa);
574 async_wait_for(req, &rc_orig);
575 if (rc_orig == EOK)
576 return (int) rc;
577 else
578 return (int) rc_orig;
579 }
580 vfs_exchange_end(exch);
581 free(pa);
582 async_wait_for(req, &rc);
583 return rc;
584}
585
586DIR *opendir(const char *dirname)
587{
588 DIR *dirp = malloc(sizeof(DIR));
589 if (!dirp)
590 return NULL;
591
592 size_t abs_size;
593 char *abs = absolutize(dirname, &abs_size);
594 if (!abs) {
595 free(dirp);
596 return NULL;
597 }
598
599 int ret = open_internal(abs, abs_size, L_DIRECTORY, 0);
600 free(abs);
601
602 if (ret < 0) {
603 free(dirp);
604 return NULL;
605 }
606
607 dirp->fd = ret;
608 return dirp;
609}
610
611struct dirent *readdir(DIR *dirp)
612{
613 ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
614 if (len <= 0)
615 return NULL;
616 return &dirp->res;
617}
618
619void rewinddir(DIR *dirp)
620{
621 (void) lseek(dirp->fd, 0, SEEK_SET);
622}
623
624int closedir(DIR *dirp)
625{
626 (void) close(dirp->fd);
627 free(dirp);
628 return 0;
629}
630
631int mkdir(const char *path, mode_t mode)
632{
633 sysarg_t rc;
634 aid_t req;
635
636 size_t pa_size;
637 char *pa = absolutize(path, &pa_size);
638 if (!pa)
639 return ENOMEM;
640
641 async_exch_t *exch = vfs_exchange_begin();
642
643 req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
644 rc = async_data_write_start(exch, pa, pa_size);
645 if (rc != EOK) {
646 vfs_exchange_end(exch);
647 free(pa);
648
649 sysarg_t rc_orig;
650 async_wait_for(req, &rc_orig);
651
652 if (rc_orig == EOK)
653 return (int) rc;
654 else
655 return (int) rc_orig;
656 }
657 vfs_exchange_end(exch);
658 free(pa);
659 async_wait_for(req, &rc);
660 return rc;
661}
662
663static int _unlink(const char *path, int lflag)
664{
665 sysarg_t rc;
666 aid_t req;
667
668 size_t pa_size;
669 char *pa = absolutize(path, &pa_size);
670 if (!pa)
671 return ENOMEM;
672
673 async_exch_t *exch = vfs_exchange_begin();
674
675 req = async_send_0(exch, VFS_IN_UNLINK, NULL);
676 rc = async_data_write_start(exch, pa, pa_size);
677 if (rc != EOK) {
678 vfs_exchange_end(exch);
679 free(pa);
680
681 sysarg_t rc_orig;
682 async_wait_for(req, &rc_orig);
683
684 if (rc_orig == EOK)
685 return (int) rc;
686 else
687 return (int) rc_orig;
688 }
689 vfs_exchange_end(exch);
690 free(pa);
691 async_wait_for(req, &rc);
692 return rc;
693}
694
695int unlink(const char *path)
696{
697 return _unlink(path, L_NONE);
698}
699
700int rmdir(const char *path)
701{
702 return _unlink(path, L_DIRECTORY);
703}
704
705int rename(const char *old, const char *new)
706{
707 sysarg_t rc;
708 sysarg_t rc_orig;
709 aid_t req;
710
711 size_t olda_size;
712 char *olda = absolutize(old, &olda_size);
713 if (!olda)
714 return ENOMEM;
715
716 size_t newa_size;
717 char *newa = absolutize(new, &newa_size);
718 if (!newa) {
719 free(olda);
720 return ENOMEM;
721 }
722
723 async_exch_t *exch = vfs_exchange_begin();
724
725 req = async_send_0(exch, VFS_IN_RENAME, NULL);
726 rc = async_data_write_start(exch, olda, olda_size);
727 if (rc != EOK) {
728 vfs_exchange_end(exch);
729 free(olda);
730 free(newa);
731 async_wait_for(req, &rc_orig);
732 if (rc_orig == EOK)
733 return (int) rc;
734 else
735 return (int) rc_orig;
736 }
737 rc = async_data_write_start(exch, newa, newa_size);
738 if (rc != EOK) {
739 vfs_exchange_end(exch);
740 free(olda);
741 free(newa);
742 async_wait_for(req, &rc_orig);
743 if (rc_orig == EOK)
744 return (int) rc;
745 else
746 return (int) rc_orig;
747 }
748 vfs_exchange_end(exch);
749 free(olda);
750 free(newa);
751 async_wait_for(req, &rc);
752 return rc;
753}
754
755int chdir(const char *path)
756{
757 size_t abs_size;
758 char *abs = absolutize(path, &abs_size);
759 if (!abs)
760 return ENOMEM;
761
762 int fd = open_internal(abs, abs_size, L_DIRECTORY, O_DESC);
763
764 if (fd < 0) {
765 free(abs);
766 return ENOENT;
767 }
768
769 fibril_mutex_lock(&cwd_mutex);
770
771 if (cwd_fd >= 0)
772 close(cwd_fd);
773
774
775 if (cwd_path)
776 free(cwd_path);
777
778 cwd_fd = fd;
779 cwd_path = abs;
780 cwd_size = abs_size;
781
782 fibril_mutex_unlock(&cwd_mutex);
783 return EOK;
784}
785
786char *getcwd(char *buf, size_t size)
787{
788 if (size == 0)
789 return NULL;
790
791 fibril_mutex_lock(&cwd_mutex);
792
793 if ((cwd_size == 0) || (size < cwd_size + 1)) {
794 fibril_mutex_unlock(&cwd_mutex);
795 return NULL;
796 }
797
798 str_cpy(buf, size, cwd_path);
799 fibril_mutex_unlock(&cwd_mutex);
800
801 return buf;
802}
803
804async_sess_t *fd_session(exch_mgmt_t mgmt, int fildes)
805{
806 struct stat stat;
807 int rc = fstat(fildes, &stat);
808 if (rc != 0) {
809 errno = rc;
810 return NULL;
811 }
812
813 if (!stat.service) {
814 errno = ENOENT;
815 return NULL;
816 }
817
818 return loc_service_connect(mgmt, stat.service, 0);
819}
820
821int fd_node(int fildes, fdi_node_t *node)
822{
823 struct stat stat;
824 int rc = fstat(fildes, &stat);
825
826 if (rc == EOK) {
827 node->fs_handle = stat.fs_handle;
828 node->service_id = stat.service_id;
829 node->index = stat.index;
830 }
831
832 return rc;
833}
834
835int dup2(int oldfd, int newfd)
836{
837 async_exch_t *exch = vfs_exchange_begin();
838
839 sysarg_t ret;
840 sysarg_t rc = async_req_2_1(exch, VFS_IN_DUP, oldfd, newfd, &ret);
841
842 vfs_exchange_end(exch);
843
844 if (rc == EOK)
845 return (int) ret;
846
847 return (int) rc;
848}
849
850/** @}
851 */
Note: See TracBrowser for help on using the repository browser.