root/fs/open.c

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

DEFINITIONS

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

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