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

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

Finish the libc implementation of unmount().

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