Subversion Repositories HelenOS

Rev

Rev 3305 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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