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

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

Use async sessions in the VFS libc client code.

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