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

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

Support mount options.
Let tmpfs decide whether to start empty or restored a TMPFS dump based on the mount option.

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