OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [open.c] - Blame information for rev 1627

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1627 jcastillo
/*
2
 *  linux/fs/open.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
 
7
/*
8
 * uClinux revisions for NO_MM
9
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
10
 *                     The Silver Hammer Group, Ltd.
11
 */
12
 
13
#include <linux/vfs.h>
14
#include <linux/types.h>
15
#include <linux/utime.h>
16
#include <linux/errno.h>
17
#include <linux/fcntl.h>
18
#include <linux/stat.h>
19
#include <linux/string.h>
20
#include <linux/sched.h>
21
#include <linux/kernel.h>
22
#include <linux/signal.h>
23
#include <linux/tty.h>
24
#include <linux/time.h>
25
#include <linux/mm.h>
26
#include <linux/file.h>
27
 
28
#include <asm/segment.h>
29
#include <asm/bitops.h>
30
 
31
asmlinkage int sys_statfs(const char * path, struct statfs * buf)
32
{
33
        struct inode * inode;
34
        int error;
35
 
36
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
37
        if (error)
38
                return error;
39
        error = namei(path,&inode);
40
        if (error)
41
                return error;
42
        if (!inode->i_sb->s_op->statfs) {
43
                iput(inode);
44
                return -ENOSYS;
45
        }
46
        inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
47
        iput(inode);
48
        return 0;
49
}
50
 
51
asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
52
{
53
        struct inode * inode;
54
        struct file * file;
55
        int error;
56
 
57
        error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
58
        if (error)
59
                return error;
60
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
61
                return -EBADF;
62
        if (!(inode = file->f_inode))
63
                return -ENOENT;
64
        if (!inode->i_sb)
65
                return -ENODEV;
66
        if (!inode->i_sb->s_op->statfs)
67
                return -ENOSYS;
68
        inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
69
        return 0;
70
}
71
 
72
int do_truncate(struct inode *inode, unsigned long length)
73
{
74
        int error;
75
        struct iattr newattrs;
76
 
77
        /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */
78
        if ((off_t) length < 0)
79
                return -EINVAL;
80
 
81
        down(&inode->i_sem);
82
        newattrs.ia_size = length;
83
        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
84
        error = notify_change(inode, &newattrs);
85
        if (!error) {
86
                /* truncate virtual mappings of this file */
87
#ifndef NO_MM
88
                vmtruncate(inode, length);
89
#endif /* !NO_MM */
90
                if (inode->i_op && inode->i_op->truncate)
91
                        inode->i_op->truncate(inode);
92
        }
93
        up(&inode->i_sem);
94
        return error;
95
}
96
 
97
asmlinkage int sys_truncate(const char * path, unsigned long length)
98
{
99
        struct inode * inode;
100
        int error;
101
 
102
        error = namei(path,&inode);
103
        if (error)
104
                return error;
105
 
106
        error = -EACCES;
107
        if (S_ISDIR(inode->i_mode))
108
                goto out;
109
 
110
        error = permission(inode,MAY_WRITE);
111
        if (error)
112
                goto out;
113
 
114
        error = -EROFS;
115
        if (IS_RDONLY(inode))
116
                goto out;
117
 
118
        error = -EPERM;
119
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
120
                goto out;
121
 
122
        error = get_write_access(inode);
123
        if (error)
124
                goto out;
125
 
126
        error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
127
                                  length < inode->i_size ? length : inode->i_size,
128
                                  abs(inode->i_size - length));
129
        if (!error) {
130
                if (inode->i_sb && inode->i_sb->dq_op)
131
                        inode->i_sb->dq_op->initialize(inode, -1);
132
                error = do_truncate(inode, length);
133
        }
134
        put_write_access(inode);
135
out:
136
        iput(inode);
137
        return error;
138
}
139
 
140
asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
141
{
142
        struct inode * inode;
143
        struct file * file;
144
        int error;
145
 
146
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
147
                return -EBADF;
148
        if (!(inode = file->f_inode))
149
                return -ENOENT;
150
        if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
151
                return -EACCES;
152
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
153
                return -EPERM;
154
        error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
155
                                  length < inode->i_size ? length : inode->i_size,
156
                                  abs(inode->i_size - length));
157
        if (!error)
158
                error = do_truncate(inode, length);
159
        return error;
160
}
161
 
162
#ifndef __alpha__
163
 
164
/*
165
 * sys_utime() can be implemented in user-level using sys_utimes().
166
 * Is this for backwards compatibility?  If so, why not move it
167
 * into the appropriate arch directory (for those architectures that
168
 * need it).
169
 */
170
 
171
/* If times==NULL, set access and modification to current time,
172
 * must be owner or have write permission.
173
 * Else, update from *times, must be owner or super user.
174
 */
175
asmlinkage int sys_utime(char * filename, struct utimbuf * times)
176
{
177
        int error;
178
        struct inode * inode;
179
        struct iattr newattrs;
180
 
181
        error = namei(filename,&inode);
182
        if (error)
183
                return error;
184
        if (IS_RDONLY(inode)) {
185
                iput(inode);
186
                return -EROFS;
187
        }
188
        /* Don't worry, the checks are done in inode_change_ok() */
189
        newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
190
        if (times) {
191
                error = verify_area(VERIFY_READ, times, sizeof(*times));
192
                if (error) {
193
                        iput(inode);
194
                        return error;
195
                }
196
                newattrs.ia_atime = get_user(&times->actime);
197
                newattrs.ia_mtime = get_user(&times->modtime);
198
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
199
        } else {
200
                if (current->fsuid != inode->i_uid &&
201
                    (error = permission(inode,MAY_WRITE)) != 0) {
202
                        iput(inode);
203
                        return error;
204
                }
205
        }
206
        error = notify_change(inode, &newattrs);
207
        iput(inode);
208
        return error;
209
}
210
 
211
#endif
212
 
213
/* If times==NULL, set access and modification to current time,
214
 * must be owner or have write permission.
215
 * Else, update from *times, must be owner or super user.
216
 */
217
asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
218
{
219
        int error;
220
        struct inode * inode;
221
        struct iattr newattrs;
222
 
223
        error = namei(filename,&inode);
224
        if (error)
225
                return error;
226
        if (IS_RDONLY(inode)) {
227
                iput(inode);
228
                return -EROFS;
229
        }
230
        /* Don't worry, the checks are done in inode_change_ok() */
231
        newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
232
        if (utimes) {
233
                struct timeval times[2];
234
                error = verify_area(VERIFY_READ, utimes, sizeof(times));
235
                if (error) {
236
                        iput(inode);
237
                        return error;
238
                }
239
                memcpy_fromfs(&times, utimes, sizeof(times));
240
                newattrs.ia_atime = times[0].tv_sec;
241
                newattrs.ia_mtime = times[1].tv_sec;
242
                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
243
        } else {
244
                if ((error = permission(inode,MAY_WRITE)) != 0) {
245
                        iput(inode);
246
                        return error;
247
                }
248
        }
249
        error = notify_change(inode, &newattrs);
250
        iput(inode);
251
        return error;
252
}
253
 
254
/*
255
 * access() needs to use the real uid/gid, not the effective uid/gid.
256
 * We do this by temporarily setting fsuid/fsgid to the wanted values
257
 */
258
asmlinkage int sys_access(const char * filename, int mode)
259
{
260
        struct inode * inode;
261
        int old_fsuid, old_fsgid;
262
        int res;
263
 
264
        if (mode != (mode & S_IRWXO))   /* where's F_OK, X_OK, W_OK, R_OK? */
265
                return -EINVAL;
266
        old_fsuid = current->fsuid;
267
        old_fsgid = current->fsgid;
268
        current->fsuid = current->uid;
269
        current->fsgid = current->gid;
270
        res = namei(filename,&inode);
271
        if (!res) {
272
                res = permission(inode, mode);
273
                iput(inode);
274
        }
275
        current->fsuid = old_fsuid;
276
        current->fsgid = old_fsgid;
277
        return res;
278
}
279
 
280
asmlinkage int sys_chdir(const char * filename)
281
{
282
        struct inode * inode;
283
        int error;
284
 
285
        error = namei(filename,&inode);
286
        if (error)
287
                return error;
288
        if (!S_ISDIR(inode->i_mode)) {
289
                iput(inode);
290
                return -ENOTDIR;
291
        }
292
        if ((error = permission(inode,MAY_EXEC)) != 0) {
293
                iput(inode);
294
                return error;
295
        }
296
        iput(current->fs->pwd);
297
        current->fs->pwd = inode;
298
        return (0);
299
}
300
 
301
asmlinkage int sys_fchdir(unsigned int fd)
302
{
303
        struct inode * inode;
304
        struct file * file;
305
        int error;
306
 
307
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
308
                return -EBADF;
309
        if (!(inode = file->f_inode))
310
                return -ENOENT;
311
        if (!S_ISDIR(inode->i_mode))
312
                return -ENOTDIR;
313
        if ((error = permission(inode,MAY_EXEC)) != 0)
314
                return error;
315
        iput(current->fs->pwd);
316
        current->fs->pwd = inode;
317
        inode->i_count++;
318
        return (0);
319
}
320
 
321
asmlinkage int sys_chroot(const char * filename)
322
{
323
        struct inode * inode;
324
        int error;
325
 
326
        error = namei(filename,&inode);
327
        if (error)
328
                return error;
329
        if (!S_ISDIR(inode->i_mode)) {
330
                iput(inode);
331
                return -ENOTDIR;
332
        }
333
        if (!fsuser()) {
334
                iput(inode);
335
                return -EPERM;
336
        }
337
        iput(current->fs->root);
338
        current->fs->root = inode;
339
        return (0);
340
}
341
 
342
asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
343
{
344
        struct inode * inode;
345
        struct file * file;
346
        struct iattr newattrs;
347
 
348
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
349
                return -EBADF;
350
        if (!(inode = file->f_inode))
351
                return -ENOENT;
352
        if (IS_RDONLY(inode))
353
                return -EROFS;
354
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
355
                return -EPERM;
356
        if (mode == (mode_t) -1)
357
                mode = inode->i_mode;
358
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
359
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
360
        inode->i_dirt = 1;
361
        return notify_change(inode, &newattrs);
362
}
363
 
364
asmlinkage int sys_chmod(const char * filename, mode_t mode)
365
{
366
        struct inode * inode;
367
        int error;
368
        struct iattr newattrs;
369
 
370
        error = namei(filename,&inode);
371
        if (error)
372
                return error;
373
        if (IS_RDONLY(inode)) {
374
                iput(inode);
375
                return -EROFS;
376
        }
377
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
378
                iput(inode);
379
                return -EPERM;
380
        }
381
        if (mode == (mode_t) -1)
382
                mode = inode->i_mode;
383
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
384
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
385
        inode->i_dirt = 1;
386
        error = notify_change(inode, &newattrs);
387
        iput(inode);
388
        return error;
389
}
390
 
391
asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
392
{
393
        struct inode * inode;
394
        struct file * file;
395
        struct iattr newattrs;
396
        int error;
397
 
398
        if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
399
                return -EBADF;
400
        if (!(inode = file->f_inode))
401
                return -ENOENT;
402
        if (IS_RDONLY(inode))
403
                return -EROFS;
404
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
405
                return -EPERM;
406
        if (user == (uid_t) -1)
407
                user = inode->i_uid;
408
        if (group == (gid_t) -1)
409
                group = inode->i_gid;
410
        newattrs.ia_mode = inode->i_mode;
411
        newattrs.ia_uid = user;
412
        newattrs.ia_gid = group;
413
        newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
414
        /*
415
         * If the owner has been changed, remove the setuid bit
416
         */
417
        if (inode->i_mode & S_ISUID) {
418
                newattrs.ia_mode &= ~S_ISUID;
419
                newattrs.ia_valid |= ATTR_MODE;
420
        }
421
        /*
422
         * If the group has been changed, remove the setgid bit
423
         *
424
         * Don't remove the setgid bit if no group execute bit.
425
         * This is a file marked for mandatory locking.
426
         */
427
        if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
428
                newattrs.ia_mode &= ~S_ISGID;
429
                newattrs.ia_valid |= ATTR_MODE;
430
        }
431
        inode->i_dirt = 1;
432
        if (inode->i_sb && inode->i_sb->dq_op) {
433
                inode->i_sb->dq_op->initialize(inode, -1);
434
                if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
435
                        return -EDQUOT;
436
                error = notify_change(inode, &newattrs);
437
                if (error)
438
                        inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
439
        } else
440
                error = notify_change(inode, &newattrs);
441
        return error;
442
}
443
 
444
asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
445
{
446
        struct inode * inode;
447
        int error;
448
        struct iattr newattrs;
449
 
450
        error = lnamei(filename,&inode);
451
        if (error)
452
                return error;
453
        if (IS_RDONLY(inode)) {
454
                iput(inode);
455
                return -EROFS;
456
        }
457
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
458
                iput(inode);
459
                return -EPERM;
460
        }
461
        if (user == (uid_t) -1)
462
                user = inode->i_uid;
463
        if (group == (gid_t) -1)
464
                group = inode->i_gid;
465
        newattrs.ia_mode = inode->i_mode;
466
        newattrs.ia_uid = user;
467
        newattrs.ia_gid = group;
468
        newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
469
        /*
470
         * If the owner has been changed, remove the setuid bit
471
         */
472
        if (inode->i_mode & S_ISUID) {
473
                newattrs.ia_mode &= ~S_ISUID;
474
                newattrs.ia_valid |= ATTR_MODE;
475
        }
476
        /*
477
         * If the group has been changed, remove the setgid bit
478
         *
479
         * Don't remove the setgid bit if no group execute bit.
480
         * This is a file marked for mandatory locking.
481
         */
482
        if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) {
483
                newattrs.ia_mode &= ~S_ISGID;
484
                newattrs.ia_valid |= ATTR_MODE;
485
        }
486
        inode->i_dirt = 1;
487
        if (inode->i_sb->dq_op) {
488
                inode->i_sb->dq_op->initialize(inode, -1);
489
                if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
490
                        return -EDQUOT;
491
                error = notify_change(inode, &newattrs);
492
                if (error)
493
                        inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
494
        } else
495
                error = notify_change(inode, &newattrs);
496
        iput(inode);
497
        return(error);
498
}
499
 
500
/*
501
 * Note that while the flag value (low two bits) for sys_open means:
502
 *      00 - read-only
503
 *      01 - write-only
504
 *      10 - read-write
505
 *      11 - special
506
 * it is changed into
507
 *      00 - no permissions needed
508
 *      01 - read-permission
509
 *      10 - write-permission
510
 *      11 - read-write
511
 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
512
 * used by symlinks.
513
 */
514
static int do_open(const char * filename,int flags,int mode, int fd)
515
{
516
        struct inode * inode;
517
        struct file * f;
518
        int flag,error;
519
 
520
        f = get_empty_filp();
521
 
522
        if (!f)
523
                return -ENFILE;
524
        f->f_flags = flag = flags;
525
        f->f_mode = (flag+1) & O_ACCMODE;
526
        if (f->f_mode)
527
                flag++;
528
        if (flag & O_TRUNC)
529
                flag |= 2;
530
        error = open_namei(filename,flag,mode,&inode,NULL);
531
        if (error)
532
                goto cleanup_file;
533
        if (f->f_mode & FMODE_WRITE) {
534
                error = get_write_access(inode);
535
                if (error)
536
                        goto cleanup_inode;
537
        }
538
 
539
        f->f_inode = inode;
540
        f->f_pos = 0;
541
        f->f_reada = 0;
542
        f->f_op = NULL;
543
        if (inode->i_op)
544
                f->f_op = inode->i_op->default_file_ops;
545
        if (f->f_op && f->f_op->open) {
546
                error = f->f_op->open(inode,f);
547
                if (error)
548
                        goto cleanup_all;
549
        }
550
        f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
551
 
552
        current->files->fd[fd] = f;
553
        return 0;
554
 
555
cleanup_all:
556
        if (f->f_mode & FMODE_WRITE)
557
                put_write_access(inode);
558
cleanup_inode:
559
        iput(inode);
560
cleanup_file:
561
        f->f_count--;
562
        return error;
563
}
564
 
565
/*
566
 * Find a empty file descriptor entry, and mark it busy
567
 */
568
int get_unused_fd(void)
569
{
570
        int fd;
571
        struct files_struct * files = current->files;
572
 
573
        fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
574
        if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) {
575
                FD_SET(fd, &files->open_fds);
576
                FD_CLR(fd, &files->close_on_exec);
577
                return fd;
578
        }
579
        return -EMFILE;
580
}
581
 
582
inline void put_unused_fd(int fd)
583
{
584
        FD_CLR(fd, &current->files->open_fds);
585
}
586
 
587
asmlinkage int sys_open(const char * filename,int flags,int mode)
588
{
589
        char * tmp;
590
        int fd, error;
591
 
592
        fd = get_unused_fd();
593
        if (fd < 0)
594
                return fd;
595
        error = getname(filename, &tmp);
596
        if (!error) {
597
                error = do_open(tmp,flags,mode, fd);
598
                putname(tmp);
599
 
600
                if (!error)
601
                        return fd;
602
        }
603
 
604
        put_unused_fd(fd);
605
        return error;
606
}
607
 
608
#ifndef __alpha__
609
 
610
/*
611
 * For backward compatibility?  Maybe this should be moved
612
 * into arch/i386 instead?
613
 */
614
asmlinkage int sys_creat(const char * pathname, int mode)
615
{
616
        return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
617
}
618
 
619
#endif
620
 
621
void __fput(struct file *filp, struct inode *inode)
622
{
623
        if (filp->f_op && filp->f_op->release)
624
                filp->f_op->release(inode,filp);
625
        filp->f_inode = NULL;
626
        if (filp->f_mode & FMODE_WRITE)
627
                put_write_access(inode);
628
        iput(inode);
629
}
630
 
631
int close_fp(struct file *filp)
632
{
633
        struct inode *inode;
634
 
635
        if (filp->f_count == 0) {
636
                printk("VFS: Close: file count is 0\n");
637
                return 0;
638
        }
639
        inode = filp->f_inode;
640
        if (inode)
641
                locks_remove_locks(current, filp);
642
        fput(filp, inode);
643
        return 0;
644
}
645
 
646
asmlinkage int sys_close(unsigned int fd)
647
{
648
        int error;
649
        struct file * filp;
650
        struct files_struct * files;
651
 
652
        files = current->files;
653
        error = -EBADF;
654
        if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) {
655
                put_unused_fd(fd);
656
                FD_CLR(fd, &files->close_on_exec);
657
                files->fd[fd] = NULL;
658
                error = close_fp(filp);
659
        }
660
        return error;
661
}
662
 
663
/*
664
 * This routine simulates a hangup on the tty, to arrange that users
665
 * are given clean terminals at login time.
666
 */
667
asmlinkage int sys_vhangup(void)
668
{
669
        if (!suser())
670
                return -EPERM;
671
        /* If there is a controlling tty, hang it up */
672
        if (current->tty)
673
                tty_vhangup(current->tty);
674
        return 0;
675
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.