source: mainline/uspace/lib/libc/generic/vfs/vfs.c@ 81342f7

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

getcwd() should return NULL if the current working directory is not set.

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