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

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