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

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

mount: resolve device using devmap

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