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> 21 #include <asm/segment.h> 23 asmlinkage
intsys_statfs(const char* path
,struct statfs
* buf
) 28 error
=verify_area(VERIFY_WRITE
, buf
,sizeof(struct statfs
)); 31 error
=namei(path
,&inode
); 34 if(!inode
->i_sb
->s_op
->statfs
) { 38 inode
->i_sb
->s_op
->statfs(inode
->i_sb
, buf
,sizeof(struct statfs
)); 43 asmlinkage
intsys_fstatfs(unsigned int fd
,struct statfs
* buf
) 49 error
=verify_area(VERIFY_WRITE
, buf
,sizeof(struct statfs
)); 52 if(fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
])) 54 if(!(inode
= file
->f_inode
)) 56 if(!inode
->i_sb
->s_op
->statfs
) 58 inode
->i_sb
->s_op
->statfs(inode
->i_sb
, buf
,sizeof(struct statfs
)); 62 intdo_truncate(struct inode
*inode
,unsigned long length
) 65 struct iattr newattrs
; 68 newattrs
.ia_size
= length
; 69 newattrs
.ia_valid
= ATTR_SIZE
| ATTR_CTIME
; 70 error
=notify_change(inode
, &newattrs
); 72 /* truncate virtual mappings of this file */ 73 vmtruncate(inode
, length
); 74 if(inode
->i_op
&& inode
->i_op
->truncate
) 75 inode
->i_op
->truncate(inode
); 81 asmlinkage
intsys_truncate(const char* path
,unsigned long length
) 86 error
=namei(path
,&inode
); 89 if(S_ISDIR(inode
->i_mode
)) { 93 if((error
=permission(inode
,MAY_WRITE
)) !=0) { 97 if(IS_RDONLY(inode
)) { 101 if(IS_IMMUTABLE(inode
) ||IS_APPEND(inode
)) { 105 error
=get_write_access(inode
); 110 error
=locks_verify(FLOCK_VERIFY_WRITE
, inode
, NULL
, 111 length
< inode
->i_size
? length
: inode
->i_size
, 112 abs(inode
->i_size
- length
)); 115 error
=do_truncate(inode
, length
); 116 put_write_access(inode
); 121 asmlinkage
intsys_ftruncate(unsigned int fd
,unsigned long length
) 123 struct inode
* inode
; 127 if(fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
])) 129 if(!(inode
= file
->f_inode
)) 131 if(S_ISDIR(inode
->i_mode
) || !(file
->f_mode
& FMODE_WRITE
)) 133 if(IS_IMMUTABLE(inode
) ||IS_APPEND(inode
)) 135 error
=locks_verify(FLOCK_VERIFY_WRITE
, inode
, file
, 136 length
< inode
->i_size
? length
: inode
->i_size
, 137 abs(inode
->i_size
- length
)); 140 returndo_truncate(inode
, length
); 146 * sys_utime() can be implemented in user-level using sys_utimes(). 147 * Is this for backwards compatibility? If so, why not move it 148 * into the appropriate arch directory (for those architectures that 152 /* If times==NULL, set access and modification to current time, 153 * must be owner or have write permission. 154 * Else, update from *times, must be owner or super user. 156 asmlinkage
intsys_utime(char* filename
,struct utimbuf
* times
) 159 struct inode
* inode
; 160 struct iattr newattrs
; 162 error
=namei(filename
,&inode
); 165 if(IS_RDONLY(inode
)) { 169 /* Don't worry, the checks are done in inode_change_ok() */ 170 newattrs
.ia_valid
= ATTR_CTIME
| ATTR_MTIME
| ATTR_ATIME
; 172 error
=verify_area(VERIFY_READ
, times
,sizeof(*times
)); 177 newattrs
.ia_atime
=get_user(×
->actime
); 178 newattrs
.ia_mtime
=get_user(×
->modtime
); 179 newattrs
.ia_valid
|= ATTR_ATIME_SET
| ATTR_MTIME_SET
; 181 if((error
=permission(inode
,MAY_WRITE
)) !=0) { 186 error
=notify_change(inode
, &newattrs
); 193 /* If times==NULL, set access and modification to current time, 194 * must be owner or have write permission. 195 * Else, update from *times, must be owner or super user. 197 asmlinkage
intsys_utimes(char* filename
,struct timeval
* utimes
) 200 struct inode
* inode
; 201 struct iattr newattrs
; 203 error
=namei(filename
,&inode
); 206 if(IS_RDONLY(inode
)) { 210 /* Don't worry, the checks are done in inode_change_ok() */ 211 newattrs
.ia_valid
= ATTR_CTIME
| ATTR_MTIME
| ATTR_ATIME
; 213 struct timeval times
[2]; 214 error
=verify_area(VERIFY_READ
, utimes
,sizeof(times
)); 219 memcpy_fromfs(×
, utimes
,sizeof(times
)); 220 newattrs
.ia_atime
= times
[0].tv_sec
; 221 newattrs
.ia_mtime
= times
[1].tv_sec
; 222 newattrs
.ia_valid
|= ATTR_ATIME_SET
| ATTR_MTIME_SET
; 224 if((error
=permission(inode
,MAY_WRITE
)) !=0) { 229 error
=notify_change(inode
, &newattrs
); 235 * access() needs to use the real uid/gid, not the effective uid/gid. 236 * We do this by temporarily setting fsuid/fsgid to the wanted values 238 asmlinkage
intsys_access(const char* filename
,int mode
) 240 struct inode
* inode
; 241 int old_fsuid
, old_fsgid
; 244 if(mode
!= (mode
& S_IRWXO
))/* where's F_OK, X_OK, W_OK, R_OK? */ 246 old_fsuid
= current
->fsuid
; 247 old_fsgid
= current
->fsgid
; 248 current
->fsuid
= current
->uid
; 249 current
->fsgid
= current
->gid
; 250 res
=namei(filename
,&inode
); 252 res
=permission(inode
, mode
); 255 current
->fsuid
= old_fsuid
; 256 current
->fsgid
= old_fsgid
; 260 asmlinkage
intsys_chdir(const char* filename
) 262 struct inode
* inode
; 265 error
=namei(filename
,&inode
); 268 if(!S_ISDIR(inode
->i_mode
)) { 272 if((error
=permission(inode
,MAY_EXEC
)) !=0) { 276 iput(current
->fs
->pwd
); 277 current
->fs
->pwd
= inode
; 281 asmlinkage
intsys_fchdir(unsigned int fd
) 283 struct inode
* inode
; 287 if(fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
])) 289 if(!(inode
= file
->f_inode
)) 291 if(!S_ISDIR(inode
->i_mode
)) 293 if((error
=permission(inode
,MAY_EXEC
)) !=0) 295 iput(current
->fs
->pwd
); 296 current
->fs
->pwd
= inode
; 301 asmlinkage
intsys_chroot(const char* filename
) 303 struct inode
* inode
; 306 error
=namei(filename
,&inode
); 309 if(!S_ISDIR(inode
->i_mode
)) { 317 iput(current
->fs
->root
); 318 current
->fs
->root
= inode
; 322 asmlinkage
intsys_fchmod(unsigned int fd
, mode_t mode
) 324 struct inode
* inode
; 326 struct iattr newattrs
; 328 if(fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
])) 330 if(!(inode
= file
->f_inode
)) 334 if(IS_IMMUTABLE(inode
) ||IS_APPEND(inode
)) 336 if(mode
== (mode_t
) -1) 337 mode
= inode
->i_mode
; 338 newattrs
.ia_mode
= (mode
& S_IALLUGO
) | (inode
->i_mode
& ~S_IALLUGO
); 339 newattrs
.ia_valid
= ATTR_MODE
| ATTR_CTIME
; 341 returnnotify_change(inode
, &newattrs
); 344 asmlinkage
intsys_chmod(const char* filename
, mode_t mode
) 346 struct inode
* inode
; 348 struct iattr newattrs
; 350 error
=namei(filename
,&inode
); 353 if(IS_RDONLY(inode
)) { 357 if(IS_IMMUTABLE(inode
) ||IS_APPEND(inode
)) { 361 if(mode
== (mode_t
) -1) 362 mode
= inode
->i_mode
; 363 newattrs
.ia_mode
= (mode
& S_IALLUGO
) | (inode
->i_mode
& ~S_IALLUGO
); 364 newattrs
.ia_valid
= ATTR_MODE
| ATTR_CTIME
; 366 error
=notify_change(inode
, &newattrs
); 371 asmlinkage
intsys_fchown(unsigned int fd
, uid_t user
, gid_t group
) 373 struct inode
* inode
; 375 struct iattr newattrs
; 378 if(fd
>= NR_OPEN
|| !(file
= current
->files
->fd
[fd
])) 380 if(!(inode
= file
->f_inode
)) 384 if(IS_IMMUTABLE(inode
) ||IS_APPEND(inode
)) 386 if(user
== (uid_t
) -1) 388 if(group
== (gid_t
) -1) 389 group
= inode
->i_gid
; 390 newattrs
.ia_mode
= inode
->i_mode
; 391 newattrs
.ia_uid
= user
; 392 newattrs
.ia_gid
= group
; 393 newattrs
.ia_valid
= ATTR_UID
| ATTR_GID
| ATTR_CTIME
; 395 * If the owner has been changed, remove the setuid bit 397 if(user
!= inode
->i_uid
&& (inode
->i_mode
& S_ISUID
)) { 398 newattrs
.ia_mode
&= ~S_ISUID
; 399 newattrs
.ia_valid
|= ATTR_MODE
; 402 * If the group has been changed, remove the setgid bit 404 * Don't remove the setgid bit if no group execute bit. 405 * This is a file marked for mandatory locking. 407 if(group
!= inode
->i_gid
&& 408 ((inode
->i_mode
& (S_ISGID
| S_IXGRP
)) == (S_ISGID
| S_IXGRP
))) { 409 newattrs
.ia_mode
&= ~S_ISGID
; 410 newattrs
.ia_valid
|= ATTR_MODE
; 413 if(inode
->i_sb
&& inode
->i_sb
->dq_op
) { 414 inode
->i_sb
->dq_op
->initialize(inode
, -1); 415 if(inode
->i_sb
->dq_op
->transfer(inode
, &newattrs
,0)) 417 error
=notify_change(inode
, &newattrs
); 419 inode
->i_sb
->dq_op
->transfer(inode
, &newattrs
,1); 421 error
=notify_change(inode
, &newattrs
); 425 asmlinkage
intsys_chown(const char* filename
, uid_t user
, gid_t group
) 427 struct inode
* inode
; 429 struct iattr newattrs
; 431 error
=lnamei(filename
,&inode
); 434 if(IS_RDONLY(inode
)) { 438 if(IS_IMMUTABLE(inode
) ||IS_APPEND(inode
)) { 442 if(user
== (uid_t
) -1) 444 if(group
== (gid_t
) -1) 445 group
= inode
->i_gid
; 446 newattrs
.ia_mode
= inode
->i_mode
; 447 newattrs
.ia_uid
= user
; 448 newattrs
.ia_gid
= group
; 449 newattrs
.ia_valid
= ATTR_UID
| ATTR_GID
| ATTR_CTIME
; 451 * If the owner has been changed, remove the setuid bit 453 if(user
!= inode
->i_uid
&& (inode
->i_mode
& S_ISUID
)) { 454 newattrs
.ia_mode
&= ~S_ISUID
; 455 newattrs
.ia_valid
|= ATTR_MODE
; 458 * If the group has been changed, remove the setgid bit 460 * Don't remove the setgid bit if no group execute bit. 461 * This is a file marked for mandatory locking. 463 if(group
!= inode
->i_gid
&& 464 ((inode
->i_mode
& (S_ISGID
| S_IXGRP
)) == (S_ISGID
| S_IXGRP
))) { 465 newattrs
.ia_mode
&= ~S_ISGID
; 466 newattrs
.ia_valid
|= ATTR_MODE
; 469 if(inode
->i_sb
->dq_op
) { 470 inode
->i_sb
->dq_op
->initialize(inode
, -1); 471 if(inode
->i_sb
->dq_op
->transfer(inode
, &newattrs
,0)) 473 error
=notify_change(inode
, &newattrs
); 475 inode
->i_sb
->dq_op
->transfer(inode
, &newattrs
,1); 477 error
=notify_change(inode
, &newattrs
); 483 * Note that while the flag value (low two bits) for sys_open means: 489 * 00 - no permissions needed 490 * 01 - read-permission 491 * 10 - write-permission 493 * for the internal routines (ie open_namei()/follow_link() etc). 00 is 496 intdo_open(const char* filename
,int flags
,int mode
) 498 struct inode
* inode
; 505 f
->f_flags
= flag
= flags
; 506 f
->f_mode
= (flag
+1) & O_ACCMODE
; 509 if(flag
& (O_TRUNC
| O_CREAT
)) 511 error
=open_namei(filename
,flag
,mode
,&inode
,NULL
); 514 if(f
->f_mode
& FMODE_WRITE
) { 515 error
=get_write_access(inode
); 525 f
->f_op
= inode
->i_op
->default_file_ops
; 526 if(f
->f_op
&& f
->f_op
->open
) { 527 error
= f
->f_op
->open(inode
,f
); 531 f
->f_flags
&= ~(O_CREAT
| O_EXCL
| O_NOCTTY
| O_TRUNC
); 534 * We have to do this last, because we mustn't export 535 * an incomplete fd to other processes which may share 536 * the same file table with us. 538 for(fd
=0; fd
< NR_OPEN
&& fd
< current
->rlim
[RLIMIT_NOFILE
].rlim_cur
; fd
++) { 539 if(!current
->files
->fd
[fd
]) { 540 current
->files
->fd
[fd
] = f
; 541 FD_CLR(fd
,¤t
->files
->close_on_exec
); 546 if(f
->f_op
&& f
->f_op
->release
) 547 f
->f_op
->release(inode
,f
); 549 if(f
->f_mode
& FMODE_WRITE
) 550 put_write_access(inode
); 558 asmlinkage
intsys_open(const char* filename
,int flags
,int mode
) 563 error
=getname(filename
, &tmp
); 566 error
=do_open(tmp
,flags
,mode
); 574 * For backward compatibility? Maybe this should be moved 575 * into arch/i386 instead? 577 asmlinkage
intsys_creat(const char* pathname
,int mode
) 579 returnsys_open(pathname
, O_CREAT
| O_WRONLY
| O_TRUNC
, mode
); 584 intclose_fp(struct file
*filp
) 588 if(filp
->f_count
==0) { 589 printk("VFS: Close: file count is 0\n"); 592 inode
= filp
->f_inode
; 594 locks_remove_locks(current
, filp
); 595 if(filp
->f_count
>1) { 599 if(filp
->f_op
&& filp
->f_op
->release
) 600 filp
->f_op
->release(inode
,filp
); 602 filp
->f_inode
= NULL
; 603 if(filp
->f_mode
& FMODE_WRITE
) 604 put_write_access(inode
); 609 asmlinkage
intsys_close(unsigned int fd
) 615 FD_CLR(fd
, ¤t
->files
->close_on_exec
); 616 if(!(filp
= current
->files
->fd
[fd
])) 618 current
->files
->fd
[fd
] = NULL
; 619 return(close_fp(filp
)); 623 * This routine simulates a hangup on the tty, to arrange that users 624 * are given clean terminals at login time. 626 asmlinkage
intsys_vhangup(void) 630 /* If there is a controlling tty, hang it up */ 632 tty_vhangup(current
->tty
);