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

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

Simplify the libc procedure needed to convert a user-supplied path to an
absolute canonical path.

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