source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 007e6efa

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