source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 3abfe9a8

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

use the return value

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