Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / usr / server / fs / vfs / vfs_syscalls.c @ 03e9c04a

History | View | Annotate | Download (13.8 KB)

1
/*
2
 * Copyright (c) 2005-2007, Kohsuke Ohtani
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
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29

    
30
/*
31
 * vfs_syscalls.c - everything in this file is a routine implementing
32
 *                  a VFS system call.
33
 */
34

    
35
#include <sys/prex.h>
36
#include <sys/stat.h>
37
#include <sys/vnode.h>
38
#include <sys/file.h>
39
#include <sys/mount.h>
40
#include <sys/dirent.h>
41
#include <sys/list.h>
42
#include <sys/buf.h>
43

    
44
#include <limits.h>
45
#include <unistd.h>
46
#include <stdlib.h>
47
#include <string.h>
48
#include <stdio.h>
49
#include <errno.h>
50
#include <fcntl.h>
51

    
52
#include "vfs.h"
53

    
54
int
55
sys_open(char *path, int flags, mode_t mode, file_t *pfp)
56
{
57
        vnode_t vp, dvp;
58
        file_t fp;
59
        char *filename;
60
        int error;
61

    
62
        DPRINTF(VFSDB_SYSCALL, ("sys_open: path=%s flags=%x mode=%x\n",
63
                                path, flags, mode));
64

    
65
        flags = FFLAGS(flags);
66
        if  ((flags & (FREAD | FWRITE)) == 0)
67
                return EINVAL;
68
        if (flags & O_CREAT) {
69
                error = namei(path, &vp);
70
                if (error == ENOENT) {
71
                        /* Create new file. */
72
                        if ((error = lookup(path, &dvp, &filename)) != 0)
73
                                return error;
74
                        if ((error = vn_access(dvp, VWRITE)) != 0) {
75
                                vput(dvp);
76
                                return error;
77
                        }
78
                        mode &= ~S_IFMT;
79
                        mode |= S_IFREG;
80
                        error = VOP_CREATE(dvp, filename, mode);
81
                        vput(dvp);
82
                        if (error)
83
                                return error;
84
                        if ((error = namei(path, &vp)) != 0)
85
                                return error;
86
                        flags &= ~O_TRUNC;
87
                } else if (error) {
88
                        return error;
89
                } else {
90
                        /* File already exits */
91
                        if (flags & O_EXCL) {
92
                                vput(vp);
93
                                return EEXIST;
94
                        }
95
                        flags &= ~O_CREAT;
96
                }
97
        } else {
98
                /* Open */
99
                if ((error = namei(path, &vp)) != 0)
100
                        return error;
101
        }
102
        if ((flags & O_CREAT) == 0) {
103
                if (flags & FWRITE || flags & O_TRUNC) {
104
                        if ((error = vn_access(vp, VWRITE)) != 0) {
105
                                vput(vp);
106
                                return error;
107
                        }
108
                        if (vp->v_type == VDIR) {
109
                                /* Openning directory with writable. */
110
                                vput(vp);
111
                                return EISDIR;
112
                        }
113
                }
114
        }
115
        /* Process truncate request */
116
        if (flags & O_TRUNC) {
117
                if (!(flags & FWRITE) || (vp->v_type == VDIR)) {
118
                        vput(vp);
119
                        return EINVAL;
120
                }
121
                if ((error = VOP_TRUNCATE(vp, 0)) != 0) {
122
                        vput(vp);
123
                        return error;
124
                }
125
        }
126
        /* Setup file structure */
127
        if (!(fp = malloc(sizeof(struct file)))) {
128
                vput(vp);
129
                return ENOMEM;
130
        }
131
        /* Request to file system */
132
        if ((error = VOP_OPEN(vp, flags)) != 0) {
133
                free(fp);
134
                vput(vp);
135
                return error;
136
        }
137
        memset(fp, 0, sizeof(struct file));
138
        fp->f_vnode = vp;
139
        fp->f_flags = flags;
140
        fp->f_offset = 0;
141
        fp->f_count = 1;
142
        *pfp = fp;
143
        vn_unlock(vp);
144
        return 0;
145
}
146

    
147
int
148
sys_close(file_t fp)
149
{
150
        vnode_t vp;
151
        int error;
152

    
153
        DPRINTF(VFSDB_SYSCALL, ("sys_close: fp=%x count=%d\n",
154
                                (u_int)fp, fp->f_count));
155

    
156
        if (fp->f_count <= 0)
157
                sys_panic("sys_close");
158

    
159
        vp = fp->f_vnode;
160
        if (--fp->f_count > 0) {
161
                vrele(vp);
162
                return 0;
163
        }
164
        vn_lock(vp);
165
        if ((error = VOP_CLOSE(vp, fp)) != 0) {
166
                vn_unlock(vp);
167
                return error;
168
        }
169
        vput(vp);
170
        free(fp);
171
        return 0;
172
}
173

    
174
int
175
sys_read(file_t fp, void *buf, size_t size, size_t *count)
176
{
177
        vnode_t vp;
178
        int error;
179

    
180
        DPRINTF(VFSDB_SYSCALL, ("sys_read: fp=%x buf=%x size=%d\n",
181
                                (u_int)fp, (u_int)buf, size));
182

    
183
        if ((fp->f_flags & FREAD) == 0)
184
                return EBADF;
185
        if (size == 0) {
186
                *count = 0;
187
                return 0;
188
        }
189
        vp = fp->f_vnode;
190
        vn_lock(vp);
191
        error = VOP_READ(vp, fp, buf, size, count);
192
        vn_unlock(vp);
193
        return error;
194
}
195

    
196
int
197
sys_write(file_t fp, void *buf, size_t size, size_t *count)
198
{
199
        vnode_t vp;
200
        int error;
201

    
202
        DPRINTF(VFSDB_SYSCALL, ("sys_write: fp=%x buf=%x size=%d\n",
203
                                (u_int)fp, (u_int)buf, size));
204

    
205
        if ((fp->f_flags & FWRITE) == 0)
206
                return EBADF;
207
        if (size == 0) {
208
                *count = 0;
209
                return 0;
210
        }
211
        vp = fp->f_vnode;
212
        vn_lock(vp);
213
        error = VOP_WRITE(vp, fp, buf, size, count);
214
        vn_unlock(vp);
215
        return error;
216
}
217

    
218
int
219
sys_lseek(file_t fp, off_t off, int type, off_t *origin)
220
{
221
        vnode_t vp;
222

    
223
        DPRINTF(VFSDB_SYSCALL, ("sys_seek: fp=%x off=%d type=%d\n",
224
                                (u_int)fp, (u_int)off, type));
225

    
226
        vp = fp->f_vnode;
227
        vn_lock(vp);
228
        switch (type) {
229
        case SEEK_SET:
230
                if (off < 0)
231
                        off = 0;
232
                if (off > (off_t)vp->v_size)
233
                        off = vp->v_size;
234
                break;
235
        case SEEK_CUR:
236
                if (fp->f_offset + off > (off_t)vp->v_size)
237
                        off = vp->v_size;
238
                else if (fp->f_offset + off < 0)
239
                        off = 0;
240
                else
241
                        off = fp->f_offset + off;
242
                break;
243
        case SEEK_END:
244
                if (off > 0)
245
                        off = vp->v_size;
246
                else if ((int)vp->v_size + off < 0)
247
                        off = 0;
248
                else
249
                        off = vp->v_size + off;
250
                break;
251
        default:
252
                vn_unlock(vp);
253
                return EINVAL;
254
        }
255
        /* Request to check the file offset */
256
        if (VOP_SEEK(vp, fp, fp->f_offset, off) != 0) {
257
                vn_unlock(vp);
258
                return EINVAL;
259
        }
260
        *origin = off;
261
        fp->f_offset = off;
262
        vn_unlock(vp);
263
        return 0;
264
}
265

    
266
int
267
sys_ioctl(file_t fp, u_long request, void *buf)
268
{
269
        vnode_t vp;
270
        int error;
271

    
272
        DPRINTF(VFSDB_SYSCALL, ("sys_ioctl: fp=%x request=%x\n", fp, request));
273

    
274
        if ((fp->f_flags & (FREAD | FWRITE)) == 0)
275
                return EBADF;
276

    
277
        vp = fp->f_vnode;
278
        vn_lock(vp);
279
        error = VOP_IOCTL(vp, fp, request, buf);
280
        vn_unlock(vp);
281
        DPRINTF(VFSDB_SYSCALL, ("sys_ioctl: comp error=%d\n", error));
282
        return error;
283
}
284

    
285
int
286
sys_fsync(file_t fp)
287
{
288
        vnode_t vp;
289
        int error;
290

    
291
        DPRINTF(VFSDB_SYSCALL, ("sys_fsync: fp=%x\n", fp));
292

    
293
        if ((fp->f_flags & FWRITE) == 0)
294
                return EBADF;
295

    
296
        vp = fp->f_vnode;
297
        vn_lock(vp);
298
        error = VOP_FSYNC(vp, fp);
299
        vn_unlock(vp);
300
        return error;
301
}
302

    
303
int
304
sys_fstat(file_t fp, struct stat *st)
305
{
306
        vnode_t vp;
307
        int error = 0;
308

    
309
        DPRINTF(VFSDB_SYSCALL, ("sys_fstat: fp=%x\n", fp));
310

    
311
        vp = fp->f_vnode;
312
        vn_lock(vp);
313
        error = vn_stat(vp, st);
314
        vn_unlock(vp);
315
        return error;
316
}
317

    
318
/*
319
 * Return 0 if directory is empty
320
 */
321
static int
322
check_dir_empty(char *path)
323
{
324
        int error;
325
        file_t fp;
326
        struct dirent dir;
327

    
328
        DPRINTF(VFSDB_SYSCALL, ("check_dir_empty\n"));
329

    
330
        if ((error = sys_opendir(path, &fp)) != 0)
331
                return error;
332
        do {
333
                error = sys_readdir(fp, &dir);
334
                if (error != 0 && error != EACCES)
335
                        break;
336
        } while (!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, ".."));
337

    
338
        sys_closedir(fp);
339

    
340
        if (error == ENOENT)
341
                return 0;
342
        else if (error == 0)
343
                return EEXIST;
344
        return error;
345
}
346

    
347
int
348
sys_opendir(char *path, file_t *file)
349
{
350
        vnode_t dvp;
351
        file_t fp;
352
        int error;
353

    
354
        DPRINTF(VFSDB_SYSCALL, ("sys_opendir: path=%s\n", path));
355

    
356
        if ((error = sys_open(path, O_RDONLY, 0, &fp)) != 0)
357
                return error;
358

    
359
        dvp = fp->f_vnode;
360
        vn_lock(dvp);
361
        if (dvp->v_type != VDIR) {
362
                vn_unlock(dvp);
363
                sys_close(fp);
364
                return ENOTDIR;
365
        }
366
        vn_unlock(dvp);
367

    
368
        *file = fp;
369
        return 0;
370
}
371

    
372
int
373
sys_closedir(file_t fp)
374
{
375
        vnode_t dvp;
376
        int error;
377

    
378
        DPRINTF(VFSDB_SYSCALL, ("sys_closedir: fp=%x\n", fp));
379

    
380
        dvp = fp->f_vnode;
381
        vn_lock(dvp);
382
        if (dvp->v_type != VDIR) {
383
                vn_unlock(dvp);
384
                return EBADF;
385
        }
386
        vn_unlock(dvp);
387
        error = sys_close(fp);
388
        return error;
389
}
390

    
391
int
392
sys_readdir(file_t fp, struct dirent *dir)
393
{
394
        vnode_t dvp;
395
        int error;
396

    
397
        DPRINTF(VFSDB_SYSCALL, ("sys_readdir: fp=%x\n", fp));
398

    
399
        dvp = fp->f_vnode;
400
        vn_lock(dvp);
401
        if (dvp->v_type != VDIR) {
402
                vn_unlock(dvp);
403
                return EBADF;
404
        }
405
        error = VOP_READDIR(dvp, fp, dir);
406
        DPRINTF(VFSDB_SYSCALL, ("sys_readdir: error=%d path=%s\n",
407
                                error, dir->d_name));
408
        vn_unlock(dvp);
409
        return error;
410
}
411

    
412
int
413
sys_rewinddir(file_t fp)
414
{
415
        vnode_t dvp;
416

    
417
        dvp = fp->f_vnode;
418
        vn_lock(dvp);
419
        if (dvp->v_type != VDIR) {
420
                vn_unlock(dvp);
421
                return EBADF;
422
        }
423
        fp->f_offset = 0;
424
        vn_unlock(dvp);
425
        return 0;
426
}
427

    
428
int
429
sys_seekdir(file_t fp, long loc)
430
{
431
        vnode_t dvp;
432

    
433
        dvp = fp->f_vnode;
434
        vn_lock(dvp);
435
        if (dvp->v_type != VDIR) {
436
                vn_unlock(dvp);
437
                return EBADF;
438
        }
439
        fp->f_offset = (off_t)loc;
440
        vn_unlock(dvp);
441
        return 0;
442
}
443

    
444
int
445
sys_telldir(file_t fp, long *loc)
446
{
447
        vnode_t dvp;
448

    
449
        dvp = fp->f_vnode;
450
        vn_lock(dvp);
451
        if (dvp->v_type != VDIR) {
452
                vn_unlock(dvp);
453
                return EBADF;
454
        }
455
        *loc = (long)fp->f_offset;
456
        vn_unlock(dvp);
457
        return 0;
458
}
459

    
460
int
461
sys_mkdir(char *path, mode_t mode)
462
{
463
        char *name;
464
        vnode_t vp, dvp;
465
        int error;
466

    
467
        DPRINTF(VFSDB_SYSCALL, ("sys_mkdir: path=%s mode=%d\n",        path, mode));
468

    
469
        if ((error = namei(path, &vp)) == 0) {
470
                /* File already exists */
471
                vput(vp);
472
                return EEXIST;
473
        }
474
        /* Notice: vp is invalid here! */
475

    
476
        if ((error = lookup(path, &dvp, &name)) != 0) {
477
                /* Directory already exists */
478
                return error;
479
        }
480
        if ((error = vn_access(dvp, VWRITE)) != 0)
481
                goto out;
482
        mode &= ~S_IFMT;
483
        mode |= S_IFDIR;
484

    
485
        error = VOP_MKDIR(dvp, name, mode);
486
 out:
487
        vput(dvp);
488
        return error;
489
}
490

    
491
int
492
sys_rmdir(char *path)
493
{
494
        vnode_t vp, dvp;
495
        int error;
496
        char *name;
497

    
498
        DPRINTF(VFSDB_SYSCALL, ("sys_rmdir: path=%s\n", path));
499

    
500
        if ((error = check_dir_empty(path)) != 0)
501
                return error;
502
        if ((error = namei(path, &vp)) != 0)
503
                return error;
504
        if ((error = vn_access(vp, VWRITE)) != 0)
505
                goto out;
506
        if (vp->v_type != VDIR) {
507
                error = ENOTDIR;
508
                goto out;
509
        }
510
        if (vp->v_flags & VROOT || vcount(vp) >= 2) {
511
                error = EBUSY;
512
                goto out;
513
        }
514
        if ((error = lookup(path, &dvp, &name)) != 0)
515
                goto out;
516

    
517
        error = VOP_RMDIR(dvp, vp, name);
518
        vn_unlock(vp);
519
        vgone(vp);
520
        vput(dvp);
521
        return error;
522

    
523
 out:
524
        vput(vp);
525
        return error;
526
}
527

    
528
int
529
sys_mknod(char *path, mode_t mode)
530
{
531
        char *name;
532
        vnode_t vp, dvp;
533
        int error;
534

    
535
        DPRINTF(VFSDB_SYSCALL, ("sys_mknod: path=%s mode=%d\n",        path, mode));
536

    
537
        switch (mode & S_IFMT) {
538
        case S_IFREG:
539
        case S_IFDIR:
540
        case S_IFIFO:
541
        case S_IFSOCK:
542
                /* OK */
543
                break;
544
        default:
545
                return EINVAL;
546
        }
547

    
548
        if ((error = namei(path, &vp)) == 0) {
549
                vput(vp);
550
                return EEXIST;
551
        }
552

    
553
        if ((error = lookup(path, &dvp, &name)) != 0)
554
                return error;
555
        if ((error = vn_access(dvp, VWRITE)) != 0)
556
                goto out;
557
        if (S_ISDIR(mode))
558
                error = VOP_MKDIR(dvp, name, mode);
559
        else
560
                error = VOP_CREATE(dvp, name, mode);
561
 out:
562
        vput(dvp);
563
        return error;
564
}
565

    
566
int
567
sys_rename(char *src, char *dest)
568
{
569
        vnode_t vp1, vp2 = 0, dvp1, dvp2;
570
        char *sname, *dname;
571
        int error;
572
        size_t len;
573
        char root[] = "/";
574

    
575
        DPRINTF(VFSDB_SYSCALL, ("sys_rename: src=%s dest=%s\n", src, dest));
576

    
577
        if ((error = namei(src, &vp1)) != 0)
578
                return error;
579
        if ((error = vn_access(vp1, VWRITE)) != 0)
580
                goto err1;
581

    
582
        /* If source and dest are the same, do nothing */
583
        if (!strncmp(src, dest, PATH_MAX))
584
                goto err1;
585

    
586
        /* Check if target is directory of source */
587
        len = strlen(dest);
588
        if (!strncmp(src, dest, len)) {
589
                error = EINVAL;
590
                goto err1;
591
        }
592
        /* Is the source busy ? */
593
        if (vcount(vp1) >= 2) {
594
                error = EBUSY;
595
                goto err1;
596
        }
597
        /* Check type of source & target */
598
        error = namei(dest, &vp2);
599
        if (error == 0) {
600
                /* target exists */
601
                if (vp1->v_type == VDIR && vp2->v_type != VDIR) {
602
                        error = ENOTDIR;
603
                        goto err2;
604
                } else if (vp1->v_type != VDIR && vp2->v_type == VDIR) {
605
                        error = EISDIR;
606
                        goto err2;
607
                }
608
                if (vp2->v_type == VDIR && check_dir_empty(dest)) {
609
                        error = EEXIST;
610
                        goto err2;
611
                }
612

    
613
                if (vcount(vp2) >= 2) {
614
                        error = EBUSY;
615
                        goto err2;
616
                }
617
        }
618

    
619
        dname = strrchr(dest, '/');
620
        if (dname == NULL) {
621
                error = ENOTDIR;
622
                goto err2;
623
        }
624
        if (dname == dest)
625
                dest = root;
626

    
627
        *dname = 0;
628
        dname++;
629

    
630
        if ((error = lookup(src, &dvp1, &sname)) != 0)
631
                goto err2;
632

    
633
        if ((error = namei(dest, &dvp2)) != 0)
634
                goto err3;
635

    
636
        /* The source and dest must be same file system */
637
        if (dvp1->v_mount != dvp2->v_mount) {
638
                error = EXDEV;
639
                goto err4;
640
        }
641
        error = VOP_RENAME(dvp1, vp1, sname, dvp2, vp2, dname);
642
 err4:
643
        vput(dvp2);
644
 err3:
645
        vput(dvp1);
646
 err2:
647
        if (vp2)
648
                vput(vp2);
649
 err1:
650
        vput(vp1);
651
        return error;
652
}
653

    
654
int
655
sys_unlink(char *path)
656
{
657
        char *name;
658
        vnode_t vp, dvp;
659
        int error;
660

    
661
        DPRINTF(VFSDB_SYSCALL, ("sys_unlink: path=%s\n", path));
662

    
663
        if ((error = namei(path, &vp)) != 0)
664
                return error;
665
        if ((error = vn_access(vp, VWRITE)) != 0)
666
                goto out;
667
        if (vp->v_type == VDIR) {
668
                error = EPERM;
669
                goto out;
670
        }
671
        /* XXX: Need to allow unlink for opened file. */
672
        if (vp->v_flags & VROOT || vcount(vp) >= 2) {
673
                error = EBUSY;
674
                goto out;
675
        }
676
        if ((error = lookup(path, &dvp, &name)) != 0)
677
                goto out;
678

    
679
        error = VOP_REMOVE(dvp, vp, name);
680

    
681
        vn_unlock(vp);
682
        vgone(vp);
683
        vput(dvp);
684
        return 0;
685
 out:
686
        vput(vp);
687
        return error;
688
}
689

    
690
int
691
sys_access(char *path, int mode)
692
{
693
        vnode_t vp;
694
        int error, flags;
695

    
696
        DPRINTF(VFSDB_SYSCALL, ("sys_access: path=%s mode=%x\n", path, mode));
697

    
698
        /* If F_OK is set, we return here if file is not found. */
699
        if ((error = namei(path, &vp)) != 0)
700
                return error;
701

    
702
        flags = 0;
703
        if (mode & R_OK)
704
                flags |= VREAD;
705
        if (mode & W_OK)
706
                flags |= VWRITE;
707
        if (mode & X_OK)
708
                flags |= VEXEC;
709

    
710
        error = vn_access(vp, flags);
711

    
712
        vput(vp);
713
        return error;
714
}
715

    
716
int
717
sys_stat(char *path, struct stat *st)
718
{
719
        vnode_t vp;
720
        int error;
721

    
722
        DPRINTF(VFSDB_SYSCALL, ("sys_stat: path=%s\n", path));
723

    
724
        if ((error = namei(path, &vp)) != 0)
725
                return error;
726
        error = vn_stat(vp, st);
727
        vput(vp);
728
        return error;
729
}
730

    
731
int
732
sys_truncate(char *path, off_t length)
733
{
734
        return 0;
735
}
736

    
737
int
738
sys_ftruncate(file_t fp, off_t length)
739
{
740
        return 0;
741
}
742

    
743
int
744
sys_fchdir(file_t fp, char *cwd)
745
{
746
        vnode_t dvp;
747

    
748
        dvp = fp->f_vnode;
749
        vn_lock(dvp);
750
        if (dvp->v_type != VDIR) {
751
                vn_unlock(dvp);
752
                return EBADF;
753
        }
754
        strlcpy(cwd, dvp->v_path, PATH_MAX);
755
        vn_unlock(dvp);
756
        return 0;
757
}