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

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