source: mainline/uspace/lib/c/generic/vfs/vfs.c@ 8e80d3f

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

Rename async_data_read/write_start_flexible() to async_data_read/write_start_generic().

  • Property mode set to 100644
File size: 16.0 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_generic(vfs_phone, (void *) buf, nbyte,
381 IPC_XF_RESTRICT);
382 if (rc != EOK) {
383 vfs_exchange_end(vfs_phone);
384
385 sysarg_t rc_orig;
386 async_wait_for(req, &rc_orig);
387
388 if (rc_orig == EOK)
389 return (ssize_t) rc;
390 else
391 return (ssize_t) rc_orig;
392 }
393 vfs_exchange_end(vfs_phone);
394 async_wait_for(req, &rc);
395 if (rc == EOK)
396 return (ssize_t) IPC_GET_ARG1(answer);
397 else
398 return rc;
399}
400
401ssize_t write(int fildes, const void *buf, size_t nbyte)
402{
403 sysarg_t rc;
404 ipc_call_t answer;
405 aid_t req;
406
407 int vfs_phone = vfs_exchange_begin();
408
409 req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer);
410 rc = async_data_write_start_generic(vfs_phone, (void *) buf, nbyte,
411 IPC_XF_RESTRICT);
412 if (rc != EOK) {
413 vfs_exchange_end(vfs_phone);
414
415 sysarg_t rc_orig;
416 async_wait_for(req, &rc_orig);
417
418 if (rc_orig == EOK)
419 return (ssize_t) rc;
420 else
421 return (ssize_t) rc_orig;
422 }
423 vfs_exchange_end(vfs_phone);
424 async_wait_for(req, &rc);
425 if (rc == EOK)
426 return (ssize_t) IPC_GET_ARG1(answer);
427 else
428 return -1;
429}
430
431int fsync(int fildes)
432{
433 int vfs_phone = vfs_exchange_begin();
434
435 sysarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes);
436
437 vfs_exchange_end(vfs_phone);
438
439 return (int) rc;
440}
441
442off64_t lseek(int fildes, off64_t offset, int whence)
443{
444 int vfs_phone = vfs_exchange_begin();
445
446 sysarg_t newoff_lo;
447 sysarg_t newoff_hi;
448 sysarg_t rc = async_req_4_2(vfs_phone, VFS_IN_SEEK, fildes,
449 LOWER32(offset), UPPER32(offset), whence,
450 &newoff_lo, &newoff_hi);
451
452 vfs_exchange_end(vfs_phone);
453
454 if (rc != EOK)
455 return (off64_t) -1;
456
457 return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
458}
459
460int ftruncate(int fildes, aoff64_t length)
461{
462 sysarg_t rc;
463
464 int vfs_phone = vfs_exchange_begin();
465
466 rc = async_req_3_0(vfs_phone, VFS_IN_TRUNCATE, fildes,
467 LOWER32(length), UPPER32(length));
468 vfs_exchange_end(vfs_phone);
469
470 return (int) rc;
471}
472
473int fstat(int fildes, struct stat *stat)
474{
475 sysarg_t rc;
476 aid_t req;
477
478 int vfs_phone = vfs_exchange_begin();
479
480 req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL);
481 rc = async_data_read_start(vfs_phone, (void *) stat, sizeof(struct stat));
482 if (rc != EOK) {
483 vfs_exchange_end(vfs_phone);
484
485 sysarg_t rc_orig;
486 async_wait_for(req, &rc_orig);
487
488 if (rc_orig == EOK)
489 return (ssize_t) rc;
490 else
491 return (ssize_t) rc_orig;
492 }
493 vfs_exchange_end(vfs_phone);
494 async_wait_for(req, &rc);
495
496 return rc;
497}
498
499int stat(const char *path, struct stat *stat)
500{
501 sysarg_t rc;
502 sysarg_t rc_orig;
503 aid_t req;
504
505 size_t pa_size;
506 char *pa = absolutize(path, &pa_size);
507 if (!pa)
508 return ENOMEM;
509
510 int vfs_phone = vfs_exchange_begin();
511
512 req = async_send_0(vfs_phone, VFS_IN_STAT, NULL);
513 rc = async_data_write_start(vfs_phone, pa, pa_size);
514 if (rc != EOK) {
515 vfs_exchange_end(vfs_phone);
516 free(pa);
517 async_wait_for(req, &rc_orig);
518 if (rc_orig == EOK)
519 return (int) rc;
520 else
521 return (int) rc_orig;
522 }
523 rc = async_data_read_start(vfs_phone, stat, sizeof(struct stat));
524 if (rc != EOK) {
525 vfs_exchange_end(vfs_phone);
526 free(pa);
527 async_wait_for(req, &rc_orig);
528 if (rc_orig == EOK)
529 return (int) rc;
530 else
531 return (int) rc_orig;
532 }
533 vfs_exchange_end(vfs_phone);
534 free(pa);
535 async_wait_for(req, &rc);
536 return rc;
537}
538
539DIR *opendir(const char *dirname)
540{
541 DIR *dirp = malloc(sizeof(DIR));
542 if (!dirp)
543 return NULL;
544
545 size_t abs_size;
546 char *abs = absolutize(dirname, &abs_size);
547 if (!abs) {
548 free(dirp);
549 return NULL;
550 }
551
552 int ret = open_internal(abs, abs_size, L_DIRECTORY, 0);
553 free(abs);
554
555 if (ret < 0) {
556 free(dirp);
557 return NULL;
558 }
559
560 dirp->fd = ret;
561 return dirp;
562}
563
564struct dirent *readdir(DIR *dirp)
565{
566 ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
567 if (len <= 0)
568 return NULL;
569 return &dirp->res;
570}
571
572void rewinddir(DIR *dirp)
573{
574 (void) lseek(dirp->fd, 0, SEEK_SET);
575}
576
577int closedir(DIR *dirp)
578{
579 (void) close(dirp->fd);
580 free(dirp);
581 return 0;
582}
583
584int mkdir(const char *path, mode_t mode)
585{
586 sysarg_t rc;
587 aid_t req;
588
589 size_t pa_size;
590 char *pa = absolutize(path, &pa_size);
591 if (!pa)
592 return ENOMEM;
593
594 int vfs_phone = vfs_exchange_begin();
595
596 req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL);
597 rc = async_data_write_start(vfs_phone, pa, pa_size);
598 if (rc != EOK) {
599 vfs_exchange_end(vfs_phone);
600 free(pa);
601
602 sysarg_t rc_orig;
603 async_wait_for(req, &rc_orig);
604
605 if (rc_orig == EOK)
606 return (int) rc;
607 else
608 return (int) rc_orig;
609 }
610 vfs_exchange_end(vfs_phone);
611 free(pa);
612 async_wait_for(req, &rc);
613 return rc;
614}
615
616static int _unlink(const char *path, int lflag)
617{
618 sysarg_t rc;
619 aid_t req;
620
621 size_t pa_size;
622 char *pa = absolutize(path, &pa_size);
623 if (!pa)
624 return ENOMEM;
625
626 int vfs_phone = vfs_exchange_begin();
627
628 req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL);
629 rc = async_data_write_start(vfs_phone, pa, pa_size);
630 if (rc != EOK) {
631 vfs_exchange_end(vfs_phone);
632 free(pa);
633
634 sysarg_t rc_orig;
635 async_wait_for(req, &rc_orig);
636
637 if (rc_orig == EOK)
638 return (int) rc;
639 else
640 return (int) rc_orig;
641 }
642 vfs_exchange_end(vfs_phone);
643 free(pa);
644 async_wait_for(req, &rc);
645 return rc;
646}
647
648int unlink(const char *path)
649{
650 return _unlink(path, L_NONE);
651}
652
653int rmdir(const char *path)
654{
655 return _unlink(path, L_DIRECTORY);
656}
657
658int rename(const char *old, const char *new)
659{
660 sysarg_t rc;
661 sysarg_t rc_orig;
662 aid_t req;
663
664 size_t olda_size;
665 char *olda = absolutize(old, &olda_size);
666 if (!olda)
667 return ENOMEM;
668
669 size_t newa_size;
670 char *newa = absolutize(new, &newa_size);
671 if (!newa) {
672 free(olda);
673 return ENOMEM;
674 }
675
676 int vfs_phone = vfs_exchange_begin();
677
678 req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL);
679 rc = async_data_write_start(vfs_phone, olda, olda_size);
680 if (rc != EOK) {
681 vfs_exchange_end(vfs_phone);
682 free(olda);
683 free(newa);
684 async_wait_for(req, &rc_orig);
685 if (rc_orig == EOK)
686 return (int) rc;
687 else
688 return (int) rc_orig;
689 }
690 rc = async_data_write_start(vfs_phone, newa, newa_size);
691 if (rc != EOK) {
692 vfs_exchange_end(vfs_phone);
693 free(olda);
694 free(newa);
695 async_wait_for(req, &rc_orig);
696 if (rc_orig == EOK)
697 return (int) rc;
698 else
699 return (int) rc_orig;
700 }
701 vfs_exchange_end(vfs_phone);
702 free(olda);
703 free(newa);
704 async_wait_for(req, &rc);
705 return rc;
706}
707
708int chdir(const char *path)
709{
710 size_t abs_size;
711 char *abs = absolutize(path, &abs_size);
712 if (!abs)
713 return ENOMEM;
714
715 int fd = open_internal(abs, abs_size, L_DIRECTORY, O_DESC);
716
717 if (fd < 0) {
718 free(abs);
719 return ENOENT;
720 }
721
722 fibril_mutex_lock(&cwd_mutex);
723
724 if (cwd_fd >= 0)
725 close(cwd_fd);
726
727
728 if (cwd_path)
729 free(cwd_path);
730
731 cwd_fd = fd;
732 cwd_path = abs;
733 cwd_size = abs_size;
734
735 fibril_mutex_unlock(&cwd_mutex);
736 return EOK;
737}
738
739char *getcwd(char *buf, size_t size)
740{
741 if (size == 0)
742 return NULL;
743
744 fibril_mutex_lock(&cwd_mutex);
745
746 if ((cwd_size == 0) || (size < cwd_size + 1)) {
747 fibril_mutex_unlock(&cwd_mutex);
748 return NULL;
749 }
750
751 str_cpy(buf, size, cwd_path);
752 fibril_mutex_unlock(&cwd_mutex);
753
754 return buf;
755}
756
757int fd_phone(int fildes)
758{
759 struct stat stat;
760
761 int rc = fstat(fildes, &stat);
762 if (rc != 0)
763 return rc;
764
765 if (!stat.device)
766 return -1;
767
768 return devmap_device_connect(stat.device, 0);
769}
770
771int fd_node(int fildes, fdi_node_t *node)
772{
773 struct stat stat;
774 int rc;
775
776 rc = fstat(fildes, &stat);
777
778 if (rc == EOK) {
779 node->fs_handle = stat.fs_handle;
780 node->devmap_handle = stat.devmap_handle;
781 node->index = stat.index;
782 }
783
784 return rc;
785}
786
787int dup2(int oldfd, int newfd)
788{
789 int vfs_phone = vfs_exchange_begin();
790
791 sysarg_t ret;
792 sysarg_t rc = async_req_2_1(vfs_phone, VFS_IN_DUP, oldfd, newfd, &ret);
793
794 vfs_exchange_end(vfs_phone);
795
796 if (rc == EOK)
797 return (int) ret;
798
799 return (int) rc;
800}
801
802/** @}
803 */
Note: See TracBrowser for help on using the repository browser.