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

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

cstyle

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