source: mainline/uspace/lib/libc/generic/vfs/vfs.c@ 28be7fa

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 28be7fa was 28be7fa, checked in by Martin Decky <martin@…>, 15 years ago

cstyle changes, no change in functionality

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