4 * Copyright (C) 1991, 1992 Linus Torvalds
8 #include <linux/types.h>
9 #include <linux/utime.h>
10 #include <linux/errno.h>
11 #include <linux/fcntl.h>
12 #include <linux/stat.h>
13 #include <linux/string.h>
14 #include <linux/sched.h>
15 #include <linux/kernel.h>
16 #include <linux/signal.h>
17 #include <linux/tty.h>
18 #include <linux/time.h>
20 #include <linux/file.h>
21 #include <linux/smp.h>
22 #include <linux/smp_lock.h>
24 #include <asm/uaccess.h>
25 #include <asm/bitops.h>
27 asmlinkage
int sys_statfs(const char * path
, struct statfs
* buf
)
29 struct dentry
* dentry
;
34 error
= PTR_ERR(dentry
);
35 if (!IS_ERR(dentry
)) {
36 struct inode
* inode
= dentry
->d_inode
;
39 if (inode
->i_sb
->s_op
->statfs
)
40 error
= inode
->i_sb
->s_op
->statfs(inode
->i_sb
, buf
, sizeof(struct statfs
));
48 asmlinkage
int sys_fstatfs(unsigned int fd
, struct statfs
* buf
)
51 struct dentry
* dentry
;
56 if (fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
]))
58 else if (!(dentry
= file
->f_dentry
))
60 else if (!(inode
= dentry
->d_inode
))
62 else if (!inode
->i_sb
)
64 else if (!inode
->i_sb
->s_op
->statfs
)
67 error
= inode
->i_sb
->s_op
->statfs(inode
->i_sb
, buf
, sizeof(struct statfs
));
72 int do_truncate(struct dentry
*dentry
, unsigned long length
)
74 struct inode
*inode
= dentry
->d_inode
;
76 struct iattr newattrs
;
79 newattrs
.ia_size
= length
;
80 newattrs
.ia_valid
= ATTR_SIZE
| ATTR_CTIME
;
81 error
= notify_change(dentry
, &newattrs
);
83 /* truncate virtual mappings of this file */
84 vmtruncate(inode
, length
);
85 if (inode
->i_op
&& inode
->i_op
->truncate
)
86 inode
->i_op
->truncate(inode
);
92 asmlinkage
int sys_truncate(const char * path
, unsigned long length
)
94 struct dentry
* dentry
;
101 error
= PTR_ERR(dentry
);
104 inode
= dentry
->d_inode
;
107 if (S_ISDIR(inode
->i_mode
))
110 error
= permission(inode
,MAY_WRITE
);
115 if (IS_RDONLY(inode
))
119 if (IS_IMMUTABLE(inode
) || IS_APPEND(inode
))
122 error
= get_write_access(inode
);
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
));
130 if (inode
->i_sb
&& inode
->i_sb
->dq_op
)
131 inode
->i_sb
->dq_op
->initialize(inode
, -1);
132 error
= do_truncate(dentry
, length
);
134 put_write_access(inode
);
142 asmlinkage
int sys_ftruncate(unsigned int fd
, unsigned long length
)
144 struct inode
* inode
;
145 struct dentry
*dentry
;
150 if (fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
]))
152 else if (!(dentry
= file
->f_dentry
))
154 else if (!(inode
= dentry
->d_inode
))
156 else if (S_ISDIR(inode
->i_mode
) || !(file
->f_mode
& FMODE_WRITE
))
158 else if (IS_IMMUTABLE(inode
) || IS_APPEND(inode
))
161 error
= locks_verify_area(FLOCK_VERIFY_WRITE
, inode
, file
,
162 length
<inode
->i_size
? length
: inode
->i_size
,
163 abs(inode
->i_size
- length
));
165 error
= do_truncate(dentry
, length
);
174 * sys_utime() can be implemented in user-level using sys_utimes().
175 * Is this for backwards compatibility? If so, why not move it
176 * into the appropriate arch directory (for those architectures that
180 /* If times==NULL, set access and modification to current time,
181 * must be owner or have write permission.
182 * Else, update from *times, must be owner or super user.
184 asmlinkage
int sys_utime(char * filename
, struct utimbuf
* times
)
187 struct dentry
* dentry
;
188 struct inode
* inode
;
189 struct iattr newattrs
;
192 dentry
= namei(filename
);
194 error
= PTR_ERR(dentry
);
197 inode
= dentry
->d_inode
;
200 if (IS_RDONLY(inode
))
203 /* Don't worry, the checks are done in inode_change_ok() */
204 newattrs
.ia_valid
= ATTR_CTIME
| ATTR_MTIME
| ATTR_ATIME
;
206 error
= get_user(newattrs
.ia_atime
, ×
->actime
);
208 error
= get_user(newattrs
.ia_mtime
, ×
->modtime
);
212 newattrs
.ia_valid
|= ATTR_ATIME_SET
| ATTR_MTIME_SET
;
214 if (current
->fsuid
!= inode
->i_uid
&&
215 (error
= permission(inode
,MAY_WRITE
)) != 0)
218 error
= notify_change(dentry
, &newattrs
);
228 /* If times==NULL, set access and modification to current time,
229 * must be owner or have write permission.
230 * Else, update from *times, must be owner or super user.
232 asmlinkage
int sys_utimes(char * filename
, struct timeval
* utimes
)
235 struct dentry
* dentry
;
236 struct inode
* inode
;
237 struct iattr newattrs
;
240 dentry
= namei(filename
);
242 error
= PTR_ERR(dentry
);
245 inode
= dentry
->d_inode
;
248 if (IS_RDONLY(inode
))
251 /* Don't worry, the checks are done in inode_change_ok() */
252 newattrs
.ia_valid
= ATTR_CTIME
| ATTR_MTIME
| ATTR_ATIME
;
254 struct timeval times
[2];
256 if (copy_from_user(×
, utimes
, sizeof(times
)))
258 newattrs
.ia_atime
= times
[0].tv_sec
;
259 newattrs
.ia_mtime
= times
[1].tv_sec
;
260 newattrs
.ia_valid
|= ATTR_ATIME_SET
| ATTR_MTIME_SET
;
262 if ((error
= permission(inode
,MAY_WRITE
)) != 0)
265 error
= notify_change(dentry
, &newattrs
);
274 * access() needs to use the real uid/gid, not the effective uid/gid.
275 * We do this by temporarily setting fsuid/fsgid to the wanted values
277 asmlinkage
int sys_access(const char * filename
, int mode
)
279 struct dentry
* dentry
;
280 int old_fsuid
, old_fsgid
;
284 if (mode
!= (mode
& S_IRWXO
)) /* where's F_OK, X_OK, W_OK, R_OK? */
286 old_fsuid
= current
->fsuid
;
287 old_fsgid
= current
->fsgid
;
288 current
->fsuid
= current
->uid
;
289 current
->fsgid
= current
->gid
;
291 dentry
= namei(filename
);
292 res
= PTR_ERR(dentry
);
293 if (!IS_ERR(dentry
)) {
294 res
= permission(dentry
->d_inode
, mode
);
298 current
->fsuid
= old_fsuid
;
299 current
->fsgid
= old_fsgid
;
305 asmlinkage
int sys_chdir(const char * filename
)
309 struct dentry
*dentry
, *tmp
;
313 dentry
= namei(filename
);
314 error
= PTR_ERR(dentry
);
318 inode
= dentry
->d_inode
;
321 if (!S_ISDIR(inode
->i_mode
))
324 error
= permission(inode
,MAY_EXEC
);
328 /* exchange dentries */
329 tmp
= current
->fs
->pwd
;
330 current
->fs
->pwd
= dentry
;
340 asmlinkage
int sys_fchdir(unsigned int fd
)
343 struct dentry
*dentry
;
350 if (fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
]))
354 if (!(dentry
= file
->f_dentry
))
356 if (!(inode
= dentry
->d_inode
))
360 if (!S_ISDIR(inode
->i_mode
))
363 error
= permission(inode
,MAY_EXEC
);
370 tmp
= current
->fs
->pwd
;
371 current
->fs
->pwd
= dget(dentry
);
379 asmlinkage
int sys_chroot(const char * filename
)
383 struct dentry
*dentry
, *tmp
;
387 dentry
= namei(filename
);
388 error
= PTR_ERR(dentry
);
392 inode
= dentry
->d_inode
;
395 if (!S_ISDIR(inode
->i_mode
))
398 error
= permission(inode
,MAY_EXEC
);
406 /* exchange dentries */
407 tmp
= current
->fs
->root
;
408 current
->fs
->root
= dentry
;
419 asmlinkage
int sys_fchmod(unsigned int fd
, mode_t mode
)
421 struct inode
* inode
;
422 struct dentry
* dentry
;
424 struct iattr newattrs
;
428 if (fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
]))
431 if (!(dentry
= file
->f_dentry
))
433 if (!(inode
= dentry
->d_inode
))
436 if (IS_RDONLY(inode
))
439 if (IS_IMMUTABLE(inode
) || IS_APPEND(inode
))
441 if (mode
== (mode_t
) -1)
442 mode
= inode
->i_mode
;
443 newattrs
.ia_mode
= (mode
& S_IALLUGO
) | (inode
->i_mode
& ~S_IALLUGO
);
444 newattrs
.ia_valid
= ATTR_MODE
| ATTR_CTIME
;
445 err
= notify_change(dentry
, &newattrs
);
451 asmlinkage
int sys_chmod(const char * filename
, mode_t mode
)
453 struct dentry
* dentry
;
454 struct inode
* inode
;
456 struct iattr newattrs
;
459 dentry
= namei(filename
);
461 error
= PTR_ERR(dentry
);
464 inode
= dentry
->d_inode
;
467 if (IS_RDONLY(inode
))
471 if (IS_IMMUTABLE(inode
) || IS_APPEND(inode
))
474 if (mode
== (mode_t
) -1)
475 mode
= inode
->i_mode
;
476 newattrs
.ia_mode
= (mode
& S_IALLUGO
) | (inode
->i_mode
& ~S_IALLUGO
);
477 newattrs
.ia_valid
= ATTR_MODE
| ATTR_CTIME
;
478 error
= notify_change(dentry
, &newattrs
);
487 static int chown_common(struct dentry
* dentry
, uid_t user
, gid_t group
)
489 struct inode
* inode
;
490 struct iattr newattrs
;
494 if (!(inode
= dentry
->d_inode
)) {
495 printk("chown_common: NULL inode\n");
499 if (IS_RDONLY(inode
))
502 if (IS_IMMUTABLE(inode
) || IS_APPEND(inode
))
504 if (user
== (uid_t
) -1)
506 if (group
== (gid_t
) -1)
507 group
= inode
->i_gid
;
508 newattrs
.ia_mode
= inode
->i_mode
;
509 newattrs
.ia_uid
= user
;
510 newattrs
.ia_gid
= group
;
511 newattrs
.ia_valid
= ATTR_UID
| ATTR_GID
| ATTR_CTIME
;
513 * If the owner has been changed, remove the setuid bit
515 if (inode
->i_mode
& S_ISUID
) {
516 newattrs
.ia_mode
&= ~S_ISUID
;
517 newattrs
.ia_valid
|= ATTR_MODE
;
520 * If the group has been changed, remove the setgid bit
522 * Don't remove the setgid bit if no group execute bit.
523 * This is a file marked for mandatory locking.
525 if (((inode
->i_mode
& (S_ISGID
| S_IXGRP
)) == (S_ISGID
| S_IXGRP
))) {
526 newattrs
.ia_mode
&= ~S_ISGID
;
527 newattrs
.ia_valid
|= ATTR_MODE
;
529 if (inode
->i_sb
&& inode
->i_sb
->dq_op
) {
530 inode
->i_sb
->dq_op
->initialize(inode
, -1);
532 if (inode
->i_sb
->dq_op
->transfer(inode
, &newattrs
, 0))
534 error
= notify_change(dentry
, &newattrs
);
536 inode
->i_sb
->dq_op
->transfer(inode
, &newattrs
, 1);
538 error
= notify_change(dentry
, &newattrs
);
543 asmlinkage
int sys_chown(const char * filename
, uid_t user
, gid_t group
)
545 struct dentry
* dentry
;
549 dentry
= namei(filename
);
551 error
= PTR_ERR(dentry
);
552 if (!IS_ERR(dentry
)) {
553 error
= chown_common(dentry
, user
, group
);
560 asmlinkage
int sys_lchown(const char * filename
, uid_t user
, gid_t group
)
562 struct dentry
* dentry
;
566 dentry
= lnamei(filename
);
568 error
= PTR_ERR(dentry
);
569 if (!IS_ERR(dentry
)) {
570 error
= chown_common(dentry
, user
, group
);
577 asmlinkage
int sys_fchown(unsigned int fd
, uid_t user
, gid_t group
)
579 struct dentry
* dentry
;
584 if (fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
]))
587 if (!(dentry
= file
->f_dentry
))
590 error
= chown_common(dentry
, user
, group
);
598 * Note that while the flag value (low two bits) for sys_open means:
604 * 00 - no permissions needed
605 * 01 - read-permission
606 * 10 - write-permission
608 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
611 static int do_open(const char * filename
,int flags
,int mode
, int fd
)
613 struct inode
* inode
;
614 struct dentry
* dentry
;
618 f
= get_empty_filp();
621 f
->f_flags
= flag
= flags
;
622 f
->f_mode
= (flag
+1) & O_ACCMODE
;
627 dentry
= open_namei(filename
,flag
,mode
);
628 error
= PTR_ERR(dentry
);
631 inode
= dentry
->d_inode
;
632 if (f
->f_mode
& FMODE_WRITE
) {
633 error
= get_write_access(inode
);
638 f
->f_dentry
= dentry
;
643 f
->f_op
= inode
->i_op
->default_file_ops
;
644 if (f
->f_op
&& f
->f_op
->open
) {
645 error
= f
->f_op
->open(inode
,f
);
649 f
->f_flags
&= ~(O_CREAT
| O_EXCL
| O_NOCTTY
| O_TRUNC
);
651 current
->files
->fd
[fd
] = f
;
655 if (f
->f_mode
& FMODE_WRITE
)
656 put_write_access(inode
);
665 * Find an empty file descriptor entry, and mark it busy
667 int get_unused_fd(void)
670 struct files_struct
* files
= current
->files
;
672 fd
= find_first_zero_bit(&files
->open_fds
, NR_OPEN
);
673 if (fd
< current
->rlim
[RLIMIT_NOFILE
].rlim_cur
) {
674 FD_SET(fd
, &files
->open_fds
);
675 FD_CLR(fd
, &files
->close_on_exec
);
681 inline void put_unused_fd(int fd
)
683 FD_CLR(fd
, ¤t
->files
->open_fds
);
686 asmlinkage
int sys_open(const char * filename
,int flags
,int mode
)
692 error
= get_unused_fd();
697 tmp
= getname(filename
);
698 error
= PTR_ERR(tmp
);
700 error
= do_open(tmp
,flags
,mode
,fd
);
716 * For backward compatibility? Maybe this should be moved
717 * into arch/i386 instead?
719 asmlinkage
int sys_creat(const char * pathname
, int mode
)
724 ret
= sys_open(pathname
, O_CREAT
| O_WRONLY
| O_TRUNC
, mode
);
731 int __fput(struct file
*filp
)
734 struct dentry
* dentry
= filp
->f_dentry
;
735 struct inode
* inode
= dentry
->d_inode
;
737 if (filp
->f_op
&& filp
->f_op
->release
)
738 error
= filp
->f_op
->release(inode
, filp
);
739 filp
->f_dentry
= NULL
;
740 if (filp
->f_mode
& FMODE_WRITE
)
741 put_write_access(inode
);
746 int close_fp(struct file
*filp
)
748 struct dentry
*dentry
;
751 if (filp
->f_count
== 0) {
752 printk("VFS: Close: file count is 0\n");
755 dentry
= filp
->f_dentry
;
756 inode
= dentry
->d_inode
;
758 locks_remove_locks(current
, filp
);
762 asmlinkage
int sys_close(unsigned int fd
)
766 struct files_struct
* files
;
769 files
= current
->files
;
771 if (fd
< NR_OPEN
&& (filp
= files
->fd
[fd
]) != NULL
) {
773 FD_CLR(fd
, &files
->close_on_exec
);
774 files
->fd
[fd
] = NULL
;
775 error
= close_fp(filp
);
782 * This routine simulates a hangup on the tty, to arrange that users
783 * are given clean terminals at login time.
785 asmlinkage
int sys_vhangup(void)
792 /* If there is a controlling tty, hang it up */
794 tty_vhangup(current
->tty
);