source: mainline/uspace/lib/libc/generic/vfs/vfs.c@ 415c7e0d

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

Implement stat() and VFS_IN_STAT.
Modify bdsh() to use stat() during ls.
In devfs, allow lookups that don't
specify one of L_FILE and L_DIRECTORY.

  • Property mode set to 100644
File size: 13.2 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 aid_t req;
125 dev_handle_t dev_handle;
126
127 res = devmap_device_get_handle(dev, &dev_handle, flags);
128 if (res != EOK)
129 return res;
130
131 size_t mpa_size;
132 char *mpa = absolutize(mp, &mpa_size);
133 if (!mpa)
134 return ENOMEM;
135
136 futex_down(&vfs_phone_futex);
137 async_serialize_start();
138 vfs_connect();
139
140 req = async_send_2(vfs_phone, VFS_IN_MOUNT, dev_handle, flags, NULL);
141 rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size);
142 if (rc != EOK) {
143 async_wait_for(req, NULL);
144 async_serialize_end();
145 futex_up(&vfs_phone_futex);
146 free(mpa);
147 return (int) rc;
148 }
149
150 rc = ipc_data_write_start(vfs_phone, (void *) opts, str_size(opts));
151 if (rc != EOK) {
152 async_wait_for(req, NULL);
153 async_serialize_end();
154 futex_up(&vfs_phone_futex);
155 free(mpa);
156 return (int) rc;
157 }
158
159 rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
160 if (rc != EOK) {
161 async_wait_for(req, NULL);
162 async_serialize_end();
163 futex_up(&vfs_phone_futex);
164 free(mpa);
165 return (int) rc;
166 }
167
168 /* Ask VFS whether it likes fs_name. */
169 rc = async_req_0_0(vfs_phone, IPC_M_PING);
170 if (rc != EOK) {
171 async_wait_for(req, NULL);
172 async_serialize_end();
173 futex_up(&vfs_phone_futex);
174 free(mpa);
175 return (int) rc;
176 }
177
178 async_wait_for(req, &rc);
179 async_serialize_end();
180 futex_up(&vfs_phone_futex);
181 free(mpa);
182
183 return (int) rc;
184}
185
186static int _open(const char *path, int lflag, int oflag, ...)
187{
188 ipcarg_t rc;
189 ipc_call_t answer;
190 aid_t req;
191
192 size_t pa_size;
193 char *pa = absolutize(path, &pa_size);
194 if (!pa)
195 return ENOMEM;
196
197 futex_down(&vfs_phone_futex);
198 async_serialize_start();
199 vfs_connect();
200
201 req = async_send_3(vfs_phone, VFS_IN_OPEN, lflag, oflag, 0, &answer);
202 rc = ipc_data_write_start(vfs_phone, pa, pa_size);
203 if (rc != EOK) {
204 async_wait_for(req, NULL);
205 async_serialize_end();
206 futex_up(&vfs_phone_futex);
207 free(pa);
208 return (int) rc;
209 }
210 async_wait_for(req, &rc);
211 async_serialize_end();
212 futex_up(&vfs_phone_futex);
213 free(pa);
214
215 if (rc != EOK)
216 return (int) rc;
217
218 return (int) IPC_GET_ARG1(answer);
219}
220
221int open(const char *path, int oflag, ...)
222{
223 return _open(path, L_FILE, oflag);
224}
225
226int open_node(fdi_node_t *node, int oflag)
227{
228 futex_down(&vfs_phone_futex);
229 async_serialize_start();
230 vfs_connect();
231
232 ipc_call_t answer;
233 aid_t req = async_send_4(vfs_phone, VFS_IN_OPEN_NODE, node->fs_handle,
234 node->dev_handle, node->index, oflag, &answer);
235
236 ipcarg_t rc;
237 async_wait_for(req, &rc);
238 async_serialize_end();
239 futex_up(&vfs_phone_futex);
240
241 if (rc != EOK)
242 return (int) rc;
243
244 return (int) IPC_GET_ARG1(answer);
245}
246
247int close(int fildes)
248{
249 ipcarg_t rc;
250
251 futex_down(&vfs_phone_futex);
252 async_serialize_start();
253 vfs_connect();
254
255 rc = async_req_1_0(vfs_phone, VFS_IN_CLOSE, fildes);
256
257 async_serialize_end();
258 futex_up(&vfs_phone_futex);
259
260 return (int)rc;
261}
262
263ssize_t read(int fildes, void *buf, size_t nbyte)
264{
265 ipcarg_t rc;
266 ipc_call_t answer;
267 aid_t req;
268
269 futex_down(&vfs_phone_futex);
270 async_serialize_start();
271 vfs_connect();
272
273 req = async_send_1(vfs_phone, VFS_IN_READ, fildes, &answer);
274 rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
275 if (rc != EOK) {
276 async_wait_for(req, NULL);
277 async_serialize_end();
278 futex_up(&vfs_phone_futex);
279 return (ssize_t) rc;
280 }
281 async_wait_for(req, &rc);
282 async_serialize_end();
283 futex_up(&vfs_phone_futex);
284 if (rc == EOK)
285 return (ssize_t) IPC_GET_ARG1(answer);
286 else
287 return rc;
288}
289
290ssize_t write(int fildes, const void *buf, size_t nbyte)
291{
292 ipcarg_t rc;
293 ipc_call_t answer;
294 aid_t req;
295
296 futex_down(&vfs_phone_futex);
297 async_serialize_start();
298 vfs_connect();
299
300 req = async_send_1(vfs_phone, VFS_IN_WRITE, fildes, &answer);
301 rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
302 if (rc != EOK) {
303 async_wait_for(req, NULL);
304 async_serialize_end();
305 futex_up(&vfs_phone_futex);
306 return (ssize_t) rc;
307 }
308 async_wait_for(req, &rc);
309 async_serialize_end();
310 futex_up(&vfs_phone_futex);
311 if (rc == EOK)
312 return (ssize_t) IPC_GET_ARG1(answer);
313 else
314 return -1;
315}
316
317int fsync(int fildes)
318{
319 futex_down(&vfs_phone_futex);
320 async_serialize_start();
321 vfs_connect();
322
323 ipcarg_t rc = async_req_1_0(vfs_phone, VFS_IN_SYNC, fildes);
324
325 async_serialize_end();
326 futex_up(&vfs_phone_futex);
327
328 return (int) rc;
329}
330
331off_t lseek(int fildes, off_t offset, int whence)
332{
333 ipcarg_t rc;
334
335 futex_down(&vfs_phone_futex);
336 async_serialize_start();
337 vfs_connect();
338
339 ipcarg_t newoffs;
340 rc = async_req_3_1(vfs_phone, VFS_IN_SEEK, fildes, offset, whence,
341 &newoffs);
342
343 async_serialize_end();
344 futex_up(&vfs_phone_futex);
345
346 if (rc != EOK)
347 return (off_t) -1;
348
349 return (off_t) newoffs;
350}
351
352int ftruncate(int fildes, off_t length)
353{
354 ipcarg_t rc;
355
356 futex_down(&vfs_phone_futex);
357 async_serialize_start();
358 vfs_connect();
359
360 rc = async_req_2_0(vfs_phone, VFS_IN_TRUNCATE, fildes, length);
361 async_serialize_end();
362 futex_up(&vfs_phone_futex);
363 return (int) rc;
364}
365
366int fstat(int fildes, struct stat *stat)
367{
368 ipcarg_t rc;
369 ipc_call_t answer;
370 aid_t req;
371
372 futex_down(&vfs_phone_futex);
373 async_serialize_start();
374 vfs_connect();
375
376 req = async_send_1(vfs_phone, VFS_IN_FSTAT, fildes, NULL);
377 rc = ipc_data_read_start(vfs_phone, (void *)stat, sizeof(struct stat));
378 if (rc != EOK) {
379 async_wait_for(req, NULL);
380 async_serialize_end();
381 futex_up(&vfs_phone_futex);
382 return (ssize_t) rc;
383 }
384 async_wait_for(req, &rc);
385 async_serialize_end();
386 futex_up(&vfs_phone_futex);
387
388 return rc;
389}
390
391int stat(const char *path, struct stat *stat)
392{
393 ipcarg_t rc;
394 aid_t req;
395
396 size_t pa_size;
397 char *pa = absolutize(path, &pa_size);
398 if (!pa)
399 return ENOMEM;
400
401 futex_down(&vfs_phone_futex);
402 async_serialize_start();
403 vfs_connect();
404
405 req = async_send_0(vfs_phone, VFS_IN_STAT, NULL);
406 rc = ipc_data_write_start(vfs_phone, pa, pa_size);
407 if (rc != EOK) {
408 async_wait_for(req, NULL);
409 async_serialize_end();
410 futex_up(&vfs_phone_futex);
411 free(pa);
412 return (int) rc;
413 }
414 rc = ipc_data_read_start(vfs_phone, stat, sizeof(struct stat));
415 if (rc != EOK) {
416 async_wait_for(req, NULL);
417 async_serialize_end();
418 futex_up(&vfs_phone_futex);
419 free(pa);
420 return (int) rc;
421 }
422 async_wait_for(req, &rc);
423 async_serialize_end();
424 futex_up(&vfs_phone_futex);
425 free(pa);
426 return rc;
427}
428
429DIR *opendir(const char *dirname)
430{
431 DIR *dirp = malloc(sizeof(DIR));
432 if (!dirp)
433 return NULL;
434 dirp->fd = _open(dirname, L_DIRECTORY, 0);
435 if (dirp->fd < 0) {
436 free(dirp);
437 return NULL;
438 }
439 return dirp;
440}
441
442struct dirent *readdir(DIR *dirp)
443{
444 ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
445 if (len <= 0)
446 return NULL;
447 return &dirp->res;
448}
449
450void rewinddir(DIR *dirp)
451{
452 (void) lseek(dirp->fd, 0, SEEK_SET);
453}
454
455int closedir(DIR *dirp)
456{
457 (void) close(dirp->fd);
458 free(dirp);
459 return 0;
460}
461
462int mkdir(const char *path, mode_t mode)
463{
464 ipcarg_t rc;
465 aid_t req;
466
467 size_t pa_size;
468 char *pa = absolutize(path, &pa_size);
469 if (!pa)
470 return ENOMEM;
471
472 futex_down(&vfs_phone_futex);
473 async_serialize_start();
474 vfs_connect();
475
476 req = async_send_1(vfs_phone, VFS_IN_MKDIR, mode, NULL);
477 rc = ipc_data_write_start(vfs_phone, pa, pa_size);
478 if (rc != EOK) {
479 async_wait_for(req, NULL);
480 async_serialize_end();
481 futex_up(&vfs_phone_futex);
482 free(pa);
483 return (int) rc;
484 }
485 async_wait_for(req, &rc);
486 async_serialize_end();
487 futex_up(&vfs_phone_futex);
488 free(pa);
489 return rc;
490}
491
492static int _unlink(const char *path, int lflag)
493{
494 ipcarg_t rc;
495 aid_t req;
496
497 size_t pa_size;
498 char *pa = absolutize(path, &pa_size);
499 if (!pa)
500 return ENOMEM;
501
502 futex_down(&vfs_phone_futex);
503 async_serialize_start();
504 vfs_connect();
505
506 req = async_send_0(vfs_phone, VFS_IN_UNLINK, NULL);
507 rc = ipc_data_write_start(vfs_phone, pa, pa_size);
508 if (rc != EOK) {
509 async_wait_for(req, NULL);
510 async_serialize_end();
511 futex_up(&vfs_phone_futex);
512 free(pa);
513 return (int) rc;
514 }
515 async_wait_for(req, &rc);
516 async_serialize_end();
517 futex_up(&vfs_phone_futex);
518 free(pa);
519 return rc;
520}
521
522int unlink(const char *path)
523{
524 return _unlink(path, L_NONE);
525}
526
527int rmdir(const char *path)
528{
529 return _unlink(path, L_DIRECTORY);
530}
531
532int rename(const char *old, const char *new)
533{
534 ipcarg_t rc;
535 aid_t req;
536
537 size_t olda_size;
538 char *olda = absolutize(old, &olda_size);
539 if (!olda)
540 return ENOMEM;
541
542 size_t newa_size;
543 char *newa = absolutize(new, &newa_size);
544 if (!newa) {
545 free(olda);
546 return ENOMEM;
547 }
548
549 futex_down(&vfs_phone_futex);
550 async_serialize_start();
551 vfs_connect();
552
553 req = async_send_0(vfs_phone, VFS_IN_RENAME, NULL);
554 rc = ipc_data_write_start(vfs_phone, olda, olda_size);
555 if (rc != EOK) {
556 async_wait_for(req, NULL);
557 async_serialize_end();
558 futex_up(&vfs_phone_futex);
559 free(olda);
560 free(newa);
561 return (int) rc;
562 }
563 rc = ipc_data_write_start(vfs_phone, newa, newa_size);
564 if (rc != EOK) {
565 async_wait_for(req, NULL);
566 async_serialize_end();
567 futex_up(&vfs_phone_futex);
568 free(olda);
569 free(newa);
570 return (int) rc;
571 }
572 async_wait_for(req, &rc);
573 async_serialize_end();
574 futex_up(&vfs_phone_futex);
575 free(olda);
576 free(newa);
577 return rc;
578}
579
580int chdir(const char *path)
581{
582 size_t pa_size;
583 char *pa = absolutize(path, &pa_size);
584 if (!pa)
585 return ENOMEM;
586
587 DIR *d = opendir(pa);
588 if (!d) {
589 free(pa);
590 return ENOENT;
591 }
592
593 futex_down(&cwd_futex);
594 if (cwd_dir) {
595 closedir(cwd_dir);
596 cwd_dir = NULL;
597 free(cwd_path);
598 cwd_path = NULL;
599 cwd_size = 0;
600 }
601 cwd_dir = d;
602 cwd_path = pa;
603 cwd_size = pa_size;
604 futex_up(&cwd_futex);
605 return EOK;
606}
607
608char *getcwd(char *buf, size_t size)
609{
610 if (!size)
611 return NULL;
612 futex_down(&cwd_futex);
613 if (size < cwd_size + 1) {
614 futex_up(&cwd_futex);
615 return NULL;
616 }
617 str_cpy(buf, size, cwd_path);
618 futex_up(&cwd_futex);
619 return buf;
620}
621
622int fd_phone(int fildes)
623{
624 struct stat stat;
625 int rc;
626
627 rc = fstat(fildes, &stat);
628
629 if (!stat.devfs_stat.device)
630 return -1;
631
632 return devmap_device_connect(stat.devfs_stat.device, 0);
633}
634
635int fd_node(int fildes, fdi_node_t *node)
636{
637 struct stat stat;
638 int rc;
639
640 rc = fstat(fildes, &stat);
641
642 if (rc == EOK) {
643 node->fs_handle = stat.fs_handle;
644 node->dev_handle = stat.dev_handle;
645 node->index = stat.index;
646 }
647
648 return rc;
649}
650
651/** @}
652 */
Note: See TracBrowser for help on using the repository browser.