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

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

mkdir() and _unlink() should return the real return code.

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