source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 64d2b10

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

libc: do not intermix low-level IPC methods with async framework methods

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