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

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

Add dummy unmount() implementation to libc.

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