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

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

Make IPC_M_PING part of the VFS_MOUNT protocol again.

  • Property mode set to 100644
File size: 11.4 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_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
118static int device_get_handle(const char *name, dev_handle_t *handle,
119 const unsigned int flags)
120{
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
128 if (phone < 0)
129 return phone;
130
131 ipc_call_t answer;
132 aid_t req = async_send_2(phone, DEVMAP_DEVICE_GET_HANDLE, flags, 0,
133 &answer);
134
135 ipcarg_t retval = ipc_data_write_start(phone, name, str_size(name) + 1);
136
137 if (retval != EOK) {
138 async_wait_for(req, NULL);
139 ipc_hangup(phone);
140 return retval;
141 }
142
143 async_wait_for(req, &retval);
144
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
157int mount(const char *fs_name, const char *mp, const char *dev,
158 const unsigned int flags)
159{
160 int res;
161 ipcarg_t rc;
162 aid_t req;
163 dev_handle_t dev_handle;
164
165 res = device_get_handle(dev, &dev_handle, flags);
166 if (res != EOK)
167 return res;
168
169 size_t mpa_size;
170 char *mpa = absolutize(mp, &mpa_size);
171 if (!mpa)
172 return ENOMEM;
173
174 futex_down(&vfs_phone_futex);
175 async_serialize_start();
176 vfs_connect();
177
178 req = async_send_2(vfs_phone, VFS_MOUNT, dev_handle, flags, NULL);
179 rc = ipc_data_write_start(vfs_phone, (void *) mpa, mpa_size);
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 }
187
188 rc = ipc_data_write_start(vfs_phone, (void *) fs_name, str_size(fs_name));
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
197 /* Ask VFS whether it likes fs_name. */
198 rc = async_req_0_0(vfs_phone, IPC_M_PING);
199 if (rc != EOK) {
200 async_wait_for(req, NULL);
201 async_serialize_end();
202 futex_up(&vfs_phone_futex);
203 free(mpa);
204 return (int) rc;
205 }
206
207 async_wait_for(req, &rc);
208 async_serialize_end();
209 futex_up(&vfs_phone_futex);
210 free(mpa);
211
212 return (int) rc;
213}
214
215static int _open(const char *path, int lflag, int oflag, ...)
216{
217 ipcarg_t rc;
218 ipc_call_t answer;
219 aid_t req;
220
221 size_t pa_size;
222 char *pa = absolutize(path, &pa_size);
223 if (!pa)
224 return ENOMEM;
225
226 futex_down(&vfs_phone_futex);
227 async_serialize_start();
228 vfs_connect();
229
230 req = async_send_3(vfs_phone, VFS_OPEN, lflag, oflag, 0, &answer);
231 rc = ipc_data_write_start(vfs_phone, pa, pa_size);
232 if (rc != EOK) {
233 async_wait_for(req, NULL);
234 async_serialize_end();
235 futex_up(&vfs_phone_futex);
236 free(pa);
237 return (int) rc;
238 }
239 async_wait_for(req, &rc);
240 async_serialize_end();
241 futex_up(&vfs_phone_futex);
242 free(pa);
243
244 if (rc != EOK)
245 return (int) rc;
246 return (int) IPC_GET_ARG1(answer);
247}
248
249int open(const char *path, int oflag, ...)
250{
251 return _open(path, L_FILE, oflag);
252}
253
254int close(int fildes)
255{
256 ipcarg_t rc;
257
258 futex_down(&vfs_phone_futex);
259 async_serialize_start();
260 vfs_connect();
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 ipcarg_t rc;
273 ipc_call_t answer;
274 aid_t req;
275
276 futex_down(&vfs_phone_futex);
277 async_serialize_start();
278 vfs_connect();
279
280 req = async_send_1(vfs_phone, VFS_READ, fildes, &answer);
281 rc = ipc_data_read_start(vfs_phone, (void *)buf, nbyte);
282 if (rc != EOK) {
283 async_wait_for(req, NULL);
284 async_serialize_end();
285 futex_up(&vfs_phone_futex);
286 return (ssize_t) rc;
287 }
288 async_wait_for(req, &rc);
289 async_serialize_end();
290 futex_up(&vfs_phone_futex);
291 if (rc == EOK)
292 return (ssize_t) IPC_GET_ARG1(answer);
293 else
294 return rc;
295}
296
297ssize_t write(int fildes, const void *buf, size_t nbyte)
298{
299 ipcarg_t rc;
300 ipc_call_t answer;
301 aid_t req;
302
303 futex_down(&vfs_phone_futex);
304 async_serialize_start();
305 vfs_connect();
306
307 req = async_send_1(vfs_phone, VFS_WRITE, fildes, &answer);
308 rc = ipc_data_write_start(vfs_phone, (void *)buf, nbyte);
309 if (rc != EOK) {
310 async_wait_for(req, NULL);
311 async_serialize_end();
312 futex_up(&vfs_phone_futex);
313 return (ssize_t) rc;
314 }
315 async_wait_for(req, &rc);
316 async_serialize_end();
317 futex_up(&vfs_phone_futex);
318 if (rc == EOK)
319 return (ssize_t) IPC_GET_ARG1(answer);
320 else
321 return -1;
322}
323
324off_t lseek(int fildes, off_t offset, int whence)
325{
326 ipcarg_t rc;
327
328 futex_down(&vfs_phone_futex);
329 async_serialize_start();
330 vfs_connect();
331
332 ipcarg_t newoffs;
333 rc = async_req_3_1(vfs_phone, VFS_SEEK, fildes, offset, whence,
334 &newoffs);
335
336 async_serialize_end();
337 futex_up(&vfs_phone_futex);
338
339 if (rc != EOK)
340 return (off_t) -1;
341
342 return (off_t) newoffs;
343}
344
345int ftruncate(int fildes, off_t length)
346{
347 ipcarg_t rc;
348
349 futex_down(&vfs_phone_futex);
350 async_serialize_start();
351 vfs_connect();
352
353 rc = async_req_2_0(vfs_phone, VFS_TRUNCATE, fildes, length);
354 async_serialize_end();
355 futex_up(&vfs_phone_futex);
356 return (int) rc;
357}
358
359DIR *opendir(const char *dirname)
360{
361 DIR *dirp = malloc(sizeof(DIR));
362 if (!dirp)
363 return NULL;
364 dirp->fd = _open(dirname, L_DIRECTORY, 0);
365 if (dirp->fd < 0) {
366 free(dirp);
367 return NULL;
368 }
369 return dirp;
370}
371
372struct dirent *readdir(DIR *dirp)
373{
374 ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
375 if (len <= 0)
376 return NULL;
377 return &dirp->res;
378}
379
380void rewinddir(DIR *dirp)
381{
382 (void) lseek(dirp->fd, 0, SEEK_SET);
383}
384
385int closedir(DIR *dirp)
386{
387 (void) close(dirp->fd);
388 free(dirp);
389 return 0;
390}
391
392int mkdir(const char *path, mode_t mode)
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_1(vfs_phone, VFS_MKDIR, mode, 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
422static int _unlink(const char *path, int lflag)
423{
424 ipcarg_t rc;
425 aid_t req;
426
427 size_t pa_size;
428 char *pa = absolutize(path, &pa_size);
429 if (!pa)
430 return ENOMEM;
431
432 futex_down(&vfs_phone_futex);
433 async_serialize_start();
434 vfs_connect();
435
436 req = async_send_0(vfs_phone, VFS_UNLINK, NULL);
437 rc = ipc_data_write_start(vfs_phone, pa, pa_size);
438 if (rc != EOK) {
439 async_wait_for(req, NULL);
440 async_serialize_end();
441 futex_up(&vfs_phone_futex);
442 free(pa);
443 return (int) rc;
444 }
445 async_wait_for(req, &rc);
446 async_serialize_end();
447 futex_up(&vfs_phone_futex);
448 free(pa);
449 return rc;
450}
451
452int unlink(const char *path)
453{
454 return _unlink(path, L_NONE);
455}
456
457int rmdir(const char *path)
458{
459 return _unlink(path, L_DIRECTORY);
460}
461
462int rename(const char *old, const char *new)
463{
464 ipcarg_t rc;
465 aid_t req;
466
467 size_t olda_size;
468 char *olda = absolutize(old, &olda_size);
469 if (!olda)
470 return ENOMEM;
471
472 size_t newa_size;
473 char *newa = absolutize(new, &newa_size);
474 if (!newa) {
475 free(olda);
476 return ENOMEM;
477 }
478
479 futex_down(&vfs_phone_futex);
480 async_serialize_start();
481 vfs_connect();
482
483 req = async_send_0(vfs_phone, VFS_RENAME, NULL);
484 rc = ipc_data_write_start(vfs_phone, olda, olda_size);
485 if (rc != EOK) {
486 async_wait_for(req, NULL);
487 async_serialize_end();
488 futex_up(&vfs_phone_futex);
489 free(olda);
490 free(newa);
491 return (int) rc;
492 }
493 rc = ipc_data_write_start(vfs_phone, newa, newa_size);
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 }
502 async_wait_for(req, &rc);
503 async_serialize_end();
504 futex_up(&vfs_phone_futex);
505 free(olda);
506 free(newa);
507 return rc;
508}
509
510int chdir(const char *path)
511{
512 size_t pa_size;
513 char *pa = absolutize(path, &pa_size);
514 if (!pa)
515 return ENOMEM;
516
517 DIR *d = opendir(pa);
518 if (!d) {
519 free(pa);
520 return ENOENT;
521 }
522
523 futex_down(&cwd_futex);
524 if (cwd_dir) {
525 closedir(cwd_dir);
526 cwd_dir = NULL;
527 free(cwd_path);
528 cwd_path = NULL;
529 cwd_size = 0;
530 }
531 cwd_dir = d;
532 cwd_path = pa;
533 cwd_size = pa_size;
534 futex_up(&cwd_futex);
535 return EOK;
536}
537
538char *getcwd(char *buf, size_t size)
539{
540 if (!size)
541 return NULL;
542 futex_down(&cwd_futex);
543 if (size < cwd_size + 1) {
544 futex_up(&cwd_futex);
545 return NULL;
546 }
547 str_cpy(buf, size, cwd_path);
548 futex_up(&cwd_futex);
549 return buf;
550}
551
552/** @}
553 */
Note: See TracBrowser for help on using the repository browser.