source: mainline/uspace/lib/libc/generic/vfs/vfs.c@ 12fc042

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

Fix the VFS protocol so that the client can determine that VFS_MOUNT failed due
to a request to mount an unregistered file system.

  • Property mode set to 100644
File size: 12.1 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 <sys/stat.h>
42#include <stdio.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 <ipc/devmap.h>
52#include "../../srv/vfs/vfs.h"
53
54int vfs_phone = -1;
55futex_t vfs_phone_futex = FUTEX_INITIALIZER;
56
57futex_t cwd_futex = FUTEX_INITIALIZER;
58DIR *cwd_dir = NULL;
59char *cwd_path = NULL;
60size_t cwd_len = 0;
61
62static char *absolutize(const char *path, size_t *retlen)
63{
64 char *ncwd_path;
65
66 futex_down(&cwd_futex);
67 size_t len = strlen(path);
68 if (*path != '/') {
69 if (!cwd_path) {
70 futex_up(&cwd_futex);
71 return NULL;
72 }
73 ncwd_path = malloc(len + cwd_len + 1);
74 if (!ncwd_path) {
75 futex_up(&cwd_futex);
76 return NULL;
77 }
78 strcpy(ncwd_path, cwd_path);
79 ncwd_path[cwd_len] = '/';
80 ncwd_path[cwd_len + 1] = '\0';
81 } else {
82 ncwd_path = malloc(len + 1);
83 if (!ncwd_path) {
84 futex_up(&cwd_futex);
85 return NULL;
86 }
87 ncwd_path[0] = '\0';
88 }
89 strcat(ncwd_path, path);
90 if (!canonify(ncwd_path, retlen)) {
91 futex_up(&cwd_futex);
92 free(ncwd_path);
93 return NULL;
94 }
95 futex_up(&cwd_futex);
96 return ncwd_path;
97}
98
99static int vfs_connect(void)
100{
101 if (vfs_phone < 0)
102 vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0);
103 return vfs_phone;
104}
105
106static int device_get_handle(char *name, dev_handle_t *handle)
107{
108 int phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CLIENT,
109 0);
110 if (phone < 0)
111 return phone;
112
113 ipc_call_t answer;
114 aid_t req = async_send_2(phone, DEVMAP_DEVICE_GET_HANDLE, 0, 0,
115 &answer);
116
117 ipcarg_t retval = ipc_data_write_start(phone, name, strlen(name) + 1);
118
119 if (retval != EOK) {
120 async_wait_for(req, NULL);
121 ipc_hangup(phone);
122 return retval;
123 }
124
125 async_wait_for(req, &retval);
126
127 if (handle != NULL)
128 *handle = -1;
129
130 if (retval == EOK) {
131 if (handle != NULL)
132 *handle = (dev_handle_t) IPC_GET_ARG1(answer);
133 }
134
135 ipc_hangup(phone);
136 return retval;
137}
138
139int mount(const char *fs_name, const char *mp, const char *dev)
140{
141 int res;
142 ipcarg_t rc;
143 aid_t req;
144 dev_handle_t dev_handle;
145
146 res = device_get_handle(dev, &dev_handle);
147 if (res != EOK)
148 return res;
149
150 size_t mpa_len;
151 char *mpa = absolutize(mp, &mpa_len);
152 if (!mpa)
153 return ENOMEM;
154
155 futex_down(&vfs_phone_futex);
156 async_serialize_start();
157 if (vfs_phone < 0) {
158 res = vfs_connect();
159 if (res < 0) {
160 async_serialize_end();
161 futex_up(&vfs_phone_futex);
162 free(mpa);
163 return res;
164 }
165 }
166 req = async_send_1(vfs_phone, VFS_MOUNT, dev_handle, NULL);
167 rc = ipc_data_write_start(vfs_phone, (void *)fs_name, strlen(fs_name));
168 if (rc != EOK) {
169 async_wait_for(req, NULL);
170 async_serialize_end();
171 futex_up(&vfs_phone_futex);
172 free(mpa);
173 return (int) rc;
174 }
175 /* Ask VFS whether it likes fs_name. */
176 rc = async_req_0_0(vfs_phone, IPC_M_PING);
177 if (rc != EOK) {
178 async_wait_for(req, NULL);
179 async_serialize_end();
180 futex_up(&vfs_phone_futex);
181 free(mpa);
182 return (int) rc;
183 }
184 rc = ipc_data_write_start(vfs_phone, (void *)mpa, mpa_len);
185 if (rc != EOK) {
186 async_wait_for(req, NULL);
187 async_serialize_end();
188 futex_up(&vfs_phone_futex);
189 free(mpa);
190 return (int) rc;
191 }
192 async_wait_for(req, &rc);
193 async_serialize_end();
194 futex_up(&vfs_phone_futex);
195 free(mpa);
196 return (int) rc;
197}
198
199static int _open(const char *path, int lflag, int oflag, ...)
200{
201 int res;
202 ipcarg_t rc;
203 ipc_call_t answer;
204 aid_t req;
205
206 size_t pa_len;
207 char *pa = absolutize(path, &pa_len);
208 if (!pa)
209 return ENOMEM;
210
211 futex_down(&vfs_phone_futex);
212 async_serialize_start();
213 if (vfs_phone < 0) {
214 res = vfs_connect();
215 if (res < 0) {
216 async_serialize_end();
217 futex_up(&vfs_phone_futex);
218 free(pa);
219 return res;
220 }
221 }
222 req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
223 rc = ipc_data_write_start(vfs_phone, pa, pa_len);
224 if (rc != EOK) {
225 async_wait_for(req, NULL);
226 async_serialize_end();
227 futex_up(&vfs_phone_futex);
228 free(pa);
229 return (int) rc;
230 }
231 async_wait_for(req, &rc);
232 async_serialize_end();
233 futex_up(&vfs_phone_futex);
234 free(pa);
235
236 if (rc != EOK)
237 return (int) rc;
238 return (int) IPC_GET_ARG1(answer);
239}
240
241int open(const char *path, int oflag, ...)
242{
243 return _open(path, L_FILE, oflag);
244}
245
246int close(int fildes)
247{
248 int res;
249 ipcarg_t rc;
250
251 futex_down(&vfs_phone_futex);
252 async_serialize_start();
253 if (vfs_phone < 0) {
254 res = vfs_connect();
255 if (res < 0) {
256 async_serialize_end();
257 futex_up(&vfs_phone_futex);
258 return res;
259 }
260 }
261
262 rc = async_req_1_0(vfs_phone, VFS_CLOSE, fildes);
263
264 async_serialize_end();
265 futex_up(&vfs_phone_futex);
266
267 return (int)rc;
268}
269
270ssize_t read(int fildes, void *buf, size_t nbyte)
271{
272 int res;
273 ipcarg_t rc;
274 ipc_call_t answer;
275 aid_t req;
276
277 futex_down(&vfs_phone_futex);
278 async_serialize_start();
279 if (vfs_phone < 0) {
280 res = vfs_connect();
281 if (res < 0) {
282 async_serialize_end();
283 futex_up(&vfs_phone_futex);
284 return res;
285 }
286 }
287 req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
288 rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
289 if (rc != EOK) {
290 async_wait_for(req, NULL);
291 async_serialize_end();
292 futex_up(&vfs_phone_futex);
293 return (ssize_t) rc;
294 }
295 async_wait_for(req, &rc);
296 async_serialize_end();
297 futex_up(&vfs_phone_futex);
298 if (rc == EOK)
299 return (ssize_t) IPC_GET_ARG1(answer);
300 else
301 return -1;
302}
303
304ssize_t write(int fildes, const void *buf, size_t nbyte)
305{
306 int res;
307 ipcarg_t rc;
308 ipc_call_t answer;
309 aid_t req;
310
311 futex_down(&vfs_phone_futex);
312 async_serialize_start();
313 if (vfs_phone < 0) {
314 res = vfs_connect();
315 if (res < 0) {
316 async_serialize_end();
317 futex_up(&vfs_phone_futex);
318 return res;
319 }
320 }
321 req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer);
322 rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
323 if (rc != EOK) {
324 async_wait_for(req, NULL);
325 async_serialize_end();
326 futex_up(&vfs_phone_futex);
327 return (ssize_t) rc;
328 }
329 async_wait_for(req, &rc);
330 async_serialize_end();
331 futex_up(&vfs_phone_futex);
332 if (rc == EOK)
333 return (ssize_t) IPC_GET_ARG1(answer);
334 else
335 return -1;
336}
337
338off_t lseek(int fildes, off_t offset, int whence)
339{
340 int res;
341 ipcarg_t rc;
342
343 futex_down(&vfs_phone_futex);
344 async_serialize_start();
345 if (vfs_phone < 0) {
346 res = vfs_connect();
347 if (res < 0) {
348 async_serialize_end();
349 futex_up(&vfs_phone_futex);
350 return res;
351 }
352 }
353
354 off_t newoffs;
355 rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
356 (ipcarg_t)&newoffs);
357
358 async_serialize_end();
359 futex_up(&vfs_phone_futex);
360
361 if (rc != EOK)
362 return (off_t) -1;
363
364 return newoffs;
365}
366
367int ftruncate(int fildes, off_t length)
368{
369 int res;
370 ipcarg_t rc;
371
372 futex_down(&vfs_phone_futex);
373 async_serialize_start();
374 if (vfs_phone < 0) {
375 res = vfs_connect();
376 if (res < 0) {
377 async_serialize_end();
378 futex_up(&vfs_phone_futex);
379 return res;
380 }
381 }
382 rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
383 async_serialize_end();
384 futex_up(&vfs_phone_futex);
385 return (int) rc;
386}
387
388DIR *opendir(const char *dirname)
389{
390 DIR *dirp = malloc(sizeof(DIR));
391 if (!dirp)
392 return NULL;
393 dirp->fd = _open(dirname, L_DIRECTORY, 0);
394 if (dirp->fd < 0) {
395 free(dirp);
396 return NULL;
397 }
398 return dirp;
399}
400
401struct dirent *readdir(DIR *dirp)
402{
403 ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
404 if (len <= 0)
405 return NULL;
406 return &dirp->res;
407}
408
409void rewinddir(DIR *dirp)
410{
411 (void) lseek(dirp->fd, 0, SEEK_SET);
412}
413
414int closedir(DIR *dirp)
415{
416 (void) close(dirp->fd);
417 free(dirp);
418 return 0;
419}
420
421int mkdir(const char *path, mode_t mode)
422{
423 int res;
424 ipcarg_t rc;
425 aid_t req;
426
427 size_t pa_len;
428 char *pa = absolutize(path, &pa_len);
429 if (!pa)
430 return ENOMEM;
431
432 futex_down(&vfs_phone_futex);
433 async_serialize_start();
434 if (vfs_phone < 0) {
435 res = vfs_connect();
436 if (res < 0) {
437 async_serialize_end();
438 futex_up(&vfs_phone_futex);
439 free(pa);
440 return res;
441 }
442 }
443 req = async_send_1(vfs_phone, VFS_MKDIR, mode, NULL);
444 rc = ipc_data_write_start(vfs_phone, pa, pa_len);
445 if (rc != EOK) {
446 async_wait_for(req, NULL);
447 async_serialize_end();
448 futex_up(&vfs_phone_futex);
449 free(pa);
450 return (int) rc;
451 }
452 async_wait_for(req, &rc);
453 async_serialize_end();
454 futex_up(&vfs_phone_futex);
455 free(pa);
456 return rc;
457}
458
459static int _unlink(const char *path, int lflag)
460{
461 int res;
462 ipcarg_t rc;
463 aid_t req;
464
465 size_t pa_len;
466 char *pa = absolutize(path, &pa_len);
467 if (!pa)
468 return ENOMEM;
469
470 futex_down(&vfs_phone_futex);
471 async_serialize_start();
472 if (vfs_phone < 0) {
473 res = vfs_connect();
474 if (res < 0) {
475 async_serialize_end();
476 futex_up(&vfs_phone_futex);
477 free(pa);
478 return res;
479 }
480 }
481 req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
482 rc = ipc_data_write_start(vfs_phone, pa, pa_len);
483 if (rc != EOK) {
484 async_wait_for(req, NULL);
485 async_serialize_end();
486 futex_up(&vfs_phone_futex);
487 free(pa);
488 return (int) rc;
489 }
490 async_wait_for(req, &rc);
491 async_serialize_end();
492 futex_up(&vfs_phone_futex);
493 free(pa);
494 return rc;
495}
496
497int unlink(const char *path)
498{
499 return _unlink(path, L_NONE);
500}
501
502int rmdir(const char *path)
503{
504 return _unlink(path, L_DIRECTORY);
505}
506
507int rename(const char *old, const char *new)
508{
509 int res;
510 ipcarg_t rc;
511 aid_t req;
512
513 size_t olda_len;
514 char *olda = absolutize(old, &olda_len);
515 if (!olda)
516 return ENOMEM;
517
518 size_t newa_len;
519 char *newa = absolutize(new, &newa_len);
520 if (!newa) {
521 free(olda);
522 return ENOMEM;
523 }
524
525 futex_down(&vfs_phone_futex);
526 async_serialize_start();
527 if (vfs_phone < 0) {
528 res = vfs_connect();
529 if (res < 0) {
530 async_serialize_end();
531 futex_up(&vfs_phone_futex);
532 free(olda);
533 free(newa);
534 return res;
535 }
536 }
537 req = async_send_0(vfs_phone, VFS_RENAME, NULL);
538 rc = ipc_data_write_start(vfs_phone, olda, olda_len);
539 if (rc != EOK) {
540 async_wait_for(req, NULL);
541 async_serialize_end();
542 futex_up(&vfs_phone_futex);
543 free(olda);
544 free(newa);
545 return (int) rc;
546 }
547 rc = ipc_data_write_start(vfs_phone, newa, newa_len);
548 if (rc != EOK) {
549 async_wait_for(req, NULL);
550 async_serialize_end();
551 futex_up(&vfs_phone_futex);
552 free(olda);
553 free(newa);
554 return (int) rc;
555 }
556 async_wait_for(req, &rc);
557 async_serialize_end();
558 futex_up(&vfs_phone_futex);
559 free(olda);
560 free(newa);
561 return rc;
562}
563
564int chdir(const char *path)
565{
566 size_t pa_len;
567 char *pa = absolutize(path, &pa_len);
568 if (!pa)
569 return ENOMEM;
570
571 DIR *d = opendir(pa);
572 if (!d) {
573 free(pa);
574 return ENOENT;
575 }
576
577 futex_down(&cwd_futex);
578 if (cwd_dir) {
579 closedir(cwd_dir);
580 cwd_dir = NULL;
581 free(cwd_path);
582 cwd_path = NULL;
583 cwd_len = 0;
584 }
585 cwd_dir = d;
586 cwd_path = pa;
587 cwd_len = pa_len;
588 futex_up(&cwd_futex);
589}
590
591char *getcwd(char *buf, size_t size)
592{
593 if (!size)
594 return NULL;
595 futex_down(&cwd_futex);
596 if (size < cwd_len + 1) {
597 futex_up(&cwd_futex);
598 return NULL;
599 }
600 strcpy(buf, cwd_path);
601 futex_up(&cwd_futex);
602 return buf;
603}
604
605/** @}
606 */
Note: See TracBrowser for help on using the repository browser.