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

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

Fix assorted warnings.

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