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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1090b8c was 1090b8c, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

C binding for devmap. Gets rid of duplicate code.

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