root/fs/open.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_statfs
  2. sys_fstatfs
  3. do_truncate
  4. sys_truncate
  5. sys_ftruncate
  6. sys_utime
  7. sys_utimes
  8. sys_access
  9. sys_chdir
  10. sys_fchdir
  11. sys_chroot
  12. sys_fchmod
  13. sys_chmod
  14. sys_fchown
  15. sys_chown
  16. do_open
  17. sys_open
  18. sys_creat
  19. close_fp
  20. sys_close
  21. sys_vhangup

   1 /*
   2  *  linux/fs/open.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/vfs.h>
   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>
  19 #include <linux/mm.h>
  20 
  21 #include <asm/segment.h>
  22 
  23 asmlinkage int sys_statfs(const char * path, struct statfs * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25         struct inode * inode;
  26         int error;
  27 
  28         error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
  29         if (error)
  30                 return error;
  31         error = namei(path,&inode);
  32         if (error)
  33                 return error;
  34         if (!inode->i_sb->s_op->statfs) {
  35                 iput(inode);
  36                 return -ENOSYS;
  37         }
  38         inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
  39         iput(inode);
  40         return 0;
  41 }
  42 
  43 asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45         struct inode * inode;
  46         struct file * file;
  47         int error;
  48 
  49         error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
  50         if (error)
  51                 return error;
  52         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
  53                 return -EBADF;
  54         if (!(inode = file->f_inode))
  55                 return -ENOENT;
  56         if (!inode->i_sb->s_op->statfs)
  57                 return -ENOSYS;
  58         inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
  59         return 0;
  60 }
  61 
  62 int do_truncate(struct inode *inode, unsigned long length)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64         int error;
  65         struct iattr newattrs;
  66 
  67         down(&inode->i_sem);
  68         newattrs.ia_size = length;
  69         newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
  70         error = notify_change(inode, &newattrs);
  71         if (!error) {
  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);
  76         }
  77         up(&inode->i_sem);
  78         return error;
  79 }
  80 
  81 asmlinkage int sys_truncate(const char * path, unsigned long length)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83         struct inode * inode;
  84         int error;
  85 
  86         error = namei(path,&inode);
  87         if (error)
  88                 return error;
  89         if (S_ISDIR(inode->i_mode)) {
  90                 iput(inode);
  91                 return -EACCES;
  92         }
  93         if ((error = permission(inode,MAY_WRITE)) != 0) {
  94                 iput(inode);
  95                 return error;
  96         }
  97         if (IS_RDONLY(inode)) {
  98                 iput(inode);
  99                 return -EROFS;
 100         }
 101         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
 102                 iput(inode);
 103                 return -EPERM;
 104         }
 105         error = get_write_access(inode);
 106         if (error) {
 107                 iput(inode);
 108                 return error;
 109         }
 110         error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
 111                                   length < inode->i_size ? length : inode->i_size,
 112                                   abs(inode->i_size - length));
 113         if (error)
 114                 return error;
 115         error = do_truncate(inode, length);
 116         put_write_access(inode);
 117         iput(inode);
 118         return error;
 119 }
 120 
 121 asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         struct inode * inode;
 124         struct file * file;
 125         int error;
 126 
 127         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 128                 return -EBADF;
 129         if (!(inode = file->f_inode))
 130                 return -ENOENT;
 131         if (S_ISDIR(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
 132                 return -EACCES;
 133         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 134                 return -EPERM;
 135         error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
 136                                   length < inode->i_size ? length : inode->i_size,
 137                                   abs(inode->i_size - length));
 138         if (error)
 139                 return error;
 140         return do_truncate(inode, length);
 141 }
 142 
 143 #ifndef __alpha__
 144 
 145 /*
 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
 149  * need it).
 150  */
 151 
 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.
 155  */
 156 asmlinkage int sys_utime(char * filename, struct utimbuf * times)
     /* [previous][next][first][last][top][bottom][index][help] */
 157 {
 158         int error;
 159         struct inode * inode;
 160         struct iattr newattrs;
 161 
 162         error = namei(filename,&inode);
 163         if (error)
 164                 return error;
 165         if (IS_RDONLY(inode)) {
 166                 iput(inode);
 167                 return -EROFS;
 168         }
 169         /* Don't worry, the checks are done in inode_change_ok() */
 170         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 171         if (times) {
 172                 error = verify_area(VERIFY_READ, times, sizeof(*times));
 173                 if (error) {
 174                         iput(inode);
 175                         return error;
 176                 }
 177                 newattrs.ia_atime = get_user(&times->actime);
 178                 newattrs.ia_mtime = get_user(&times->modtime);
 179                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 180         } else {
 181                 if ((error = permission(inode,MAY_WRITE)) != 0) {
 182                         iput(inode);
 183                         return error;
 184                 }
 185         }
 186         error = notify_change(inode, &newattrs);
 187         iput(inode);
 188         return error;
 189 }
 190 
 191 #endif
 192 
 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.
 196  */
 197 asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199         int error;
 200         struct inode * inode;
 201         struct iattr newattrs;
 202 
 203         error = namei(filename,&inode);
 204         if (error)
 205                 return error;
 206         if (IS_RDONLY(inode)) {
 207                 iput(inode);
 208                 return -EROFS;
 209         }
 210         /* Don't worry, the checks are done in inode_change_ok() */
 211         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 212         if (utimes) {
 213                 struct timeval times[2];
 214                 error = verify_area(VERIFY_READ, utimes, sizeof(times));
 215                 if (error) {
 216                         iput(inode);
 217                         return error;
 218                 }
 219                 memcpy_fromfs(&times, 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;
 223         } else {
 224                 if ((error = permission(inode,MAY_WRITE)) != 0) {
 225                         iput(inode);
 226                         return error;
 227                 }
 228         }
 229         error = notify_change(inode, &newattrs);
 230         iput(inode);
 231         return error;
 232 }
 233 
 234 /*
 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
 237  */
 238 asmlinkage int sys_access(const char * filename, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 239 {
 240         struct inode * inode;
 241         int old_fsuid, old_fsgid;
 242         int res;
 243 
 244         if (mode != (mode & S_IRWXO))   /* where's F_OK, X_OK, W_OK, R_OK? */
 245                 return -EINVAL;
 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);
 251         if (!res) {
 252                 res = permission(inode, mode);
 253                 iput(inode);
 254         }
 255         current->fsuid = old_fsuid;
 256         current->fsgid = old_fsgid;
 257         return res;
 258 }
 259 
 260 asmlinkage int sys_chdir(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262         struct inode * inode;
 263         int error;
 264 
 265         error = namei(filename,&inode);
 266         if (error)
 267                 return error;
 268         if (!S_ISDIR(inode->i_mode)) {
 269                 iput(inode);
 270                 return -ENOTDIR;
 271         }
 272         if ((error = permission(inode,MAY_EXEC)) != 0) {
 273                 iput(inode);
 274                 return error;
 275         }
 276         iput(current->fs->pwd);
 277         current->fs->pwd = inode;
 278         return (0);
 279 }
 280 
 281 asmlinkage int sys_fchdir(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283         struct inode * inode;
 284         struct file * file;
 285         int error;
 286 
 287         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 288                 return -EBADF;
 289         if (!(inode = file->f_inode))
 290                 return -ENOENT;
 291         if (!S_ISDIR(inode->i_mode))
 292                 return -ENOTDIR;
 293         if ((error = permission(inode,MAY_EXEC)) != 0)
 294                 return error;
 295         iput(current->fs->pwd);
 296         current->fs->pwd = inode;
 297         inode->i_count++;
 298         return (0);
 299 }
 300 
 301 asmlinkage int sys_chroot(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 302 {
 303         struct inode * inode;
 304         int error;
 305 
 306         error = namei(filename,&inode);
 307         if (error)
 308                 return error;
 309         if (!S_ISDIR(inode->i_mode)) {
 310                 iput(inode);
 311                 return -ENOTDIR;
 312         }
 313         if (!fsuser()) {
 314                 iput(inode);
 315                 return -EPERM;
 316         }
 317         iput(current->fs->root);
 318         current->fs->root = inode;
 319         return (0);
 320 }
 321 
 322 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 323 {
 324         struct inode * inode;
 325         struct file * file;
 326         struct iattr newattrs;
 327 
 328         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 329                 return -EBADF;
 330         if (!(inode = file->f_inode))
 331                 return -ENOENT;
 332         if (IS_RDONLY(inode))
 333                 return -EROFS;
 334         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 335                 return -EPERM;
 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;
 340         inode->i_dirt = 1;
 341         return notify_change(inode, &newattrs);
 342 }
 343 
 344 asmlinkage int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346         struct inode * inode;
 347         int error;
 348         struct iattr newattrs;
 349 
 350         error = namei(filename,&inode);
 351         if (error)
 352                 return error;
 353         if (IS_RDONLY(inode)) {
 354                 iput(inode);
 355                 return -EROFS;
 356         }
 357         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
 358                 iput(inode);
 359                 return -EPERM;
 360         }
 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;
 365         inode->i_dirt = 1;
 366         error = notify_change(inode, &newattrs);
 367         iput(inode);
 368         return error;
 369 }
 370 
 371 asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373         struct inode * inode;
 374         struct file * file;
 375         struct iattr newattrs;
 376         int error;
 377 
 378         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 379                 return -EBADF;
 380         if (!(inode = file->f_inode))
 381                 return -ENOENT;
 382         if (IS_RDONLY(inode))
 383                 return -EROFS;
 384         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 385                 return -EPERM;
 386         if (user == (uid_t) -1)
 387                 user = inode->i_uid;
 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;
 394         /*
 395          * If the owner has been changed, remove the setuid bit
 396          */
 397         if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
 398                 newattrs.ia_mode &= ~S_ISUID;
 399                 newattrs.ia_valid |= ATTR_MODE;
 400         }
 401         /*
 402          * If the group has been changed, remove the setgid bit
 403          *
 404          * Don't remove the setgid bit if no group execute bit.
 405          * This is a file marked for mandatory locking.
 406          */
 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;
 411         }
 412         inode->i_dirt = 1;
 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))
 416                         return -EDQUOT;
 417                 error = notify_change(inode, &newattrs);
 418                 if (error)
 419                         inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 420         } else
 421                 error = notify_change(inode, &newattrs);
 422         return error;
 423 }
 424 
 425 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 426 {
 427         struct inode * inode;
 428         int error;
 429         struct iattr newattrs;
 430 
 431         error = lnamei(filename,&inode);
 432         if (error)
 433                 return error;
 434         if (IS_RDONLY(inode)) {
 435                 iput(inode);
 436                 return -EROFS;
 437         }
 438         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
 439                 iput(inode);
 440                 return -EPERM;
 441         }
 442         if (user == (uid_t) -1)
 443                 user = inode->i_uid;
 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;
 450         /*
 451          * If the owner has been changed, remove the setuid bit
 452          */
 453         if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
 454                 newattrs.ia_mode &= ~S_ISUID;
 455                 newattrs.ia_valid |= ATTR_MODE;
 456         }
 457         /*
 458          * If the group has been changed, remove the setgid bit
 459          *
 460          * Don't remove the setgid bit if no group execute bit.
 461          * This is a file marked for mandatory locking.
 462          */
 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;
 467         }
 468         inode->i_dirt = 1;
 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))
 472                         return -EDQUOT;
 473                 error = notify_change(inode, &newattrs);
 474                 if (error)
 475                         inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 476         } else
 477                 error = notify_change(inode, &newattrs);
 478         iput(inode);
 479         return(error);
 480 }
 481 
 482 /*
 483  * Note that while the flag value (low two bits) for sys_open means:
 484  *      00 - read-only
 485  *      01 - write-only
 486  *      10 - read-write
 487  *      11 - special
 488  * it is changed into
 489  *      00 - no permissions needed
 490  *      01 - read-permission
 491  *      10 - write-permission
 492  *      11 - read-write
 493  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 494  * used by symlinks.
 495  */
 496 int do_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 497 {
 498         struct inode * inode;
 499         struct file * f;
 500         int flag,error,fd;
 501 
 502         f = get_empty_filp();
 503         if (!f)
 504                 return -ENFILE;
 505         f->f_flags = flag = flags;
 506         f->f_mode = (flag+1) & O_ACCMODE;
 507         if (f->f_mode)
 508                 flag++;
 509         if (flag & (O_TRUNC | O_CREAT))
 510                 flag |= 2;
 511         error = open_namei(filename,flag,mode,&inode,NULL);
 512         if (error)
 513                 goto cleanup_file;
 514         if (f->f_mode & FMODE_WRITE) {
 515                 error = get_write_access(inode);
 516                 if (error)
 517                         goto cleanup_inode;
 518         }
 519 
 520         f->f_inode = inode;
 521         f->f_pos = 0;
 522         f->f_reada = 0;
 523         f->f_op = NULL;
 524         if (inode->i_op)
 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);
 528                 if (error)
 529                         goto cleanup_all;
 530         }
 531         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 532 
 533         /*
 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.
 537          */
 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,&current->files->close_on_exec);
 542                         return fd;
 543                 }
 544         }
 545         error = -EMFILE;
 546         if (f->f_op && f->f_op->release)
 547                 f->f_op->release(inode,f);
 548 cleanup_all:
 549         if (f->f_mode & FMODE_WRITE)
 550                 put_write_access(inode);
 551 cleanup_inode:
 552         iput(inode);
 553 cleanup_file:
 554         f->f_count--;
 555         return error;
 556 }
 557 
 558 asmlinkage int sys_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 559 {
 560         char * tmp;
 561         int error;
 562 
 563         error = getname(filename, &tmp);
 564         if (error)
 565                 return error;
 566         error = do_open(tmp,flags,mode);
 567         putname(tmp);
 568         return error;
 569 }
 570 
 571 #ifndef __alpha__
 572 
 573 /*
 574  * For backward compatibility?  Maybe this should be moved
 575  * into arch/i386 instead?
 576  */
 577 asmlinkage int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 578 {
 579         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 580 }
 581 
 582 #endif
 583 
 584 int close_fp(struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 585 {
 586         struct inode *inode;
 587 
 588         if (filp->f_count == 0) {
 589                 printk("VFS: Close: file count is 0\n");
 590                 return 0;
 591         }
 592         inode = filp->f_inode;
 593         if (inode)
 594                 locks_remove_locks(current, filp);
 595         if (filp->f_count > 1) {
 596                 filp->f_count--;
 597                 return 0;
 598         }
 599         if (filp->f_op && filp->f_op->release)
 600                 filp->f_op->release(inode,filp);
 601         filp->f_count--;
 602         filp->f_inode = NULL;
 603         if (filp->f_mode & FMODE_WRITE)
 604                 put_write_access(inode);
 605         iput(inode);
 606         return 0;
 607 }
 608 
 609 asmlinkage int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 610 {       
 611         struct file * filp;
 612 
 613         if (fd >= NR_OPEN)
 614                 return -EBADF;
 615         FD_CLR(fd, &current->files->close_on_exec);
 616         if (!(filp = current->files->fd[fd]))
 617                 return -EBADF;
 618         current->files->fd[fd] = NULL;
 619         return (close_fp (filp));
 620 }
 621 
 622 /*
 623  * This routine simulates a hangup on the tty, to arrange that users
 624  * are given clean terminals at login time.
 625  */
 626 asmlinkage int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 627 {
 628         if (!suser())
 629                 return -EPERM;
 630         /* If there is a controlling tty, hang it up */
 631         if (current->tty)
 632                 tty_vhangup(current->tty);
 633         return 0;
 634 }

/* [previous][next][first][last][top][bottom][index][help] */