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 /* 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         int error;
 141         struct inode * inode;
 142         struct iattr newattrs;
 143 
 144         error = namei(filename,&inode);
 145         if (error)
 146                 return error;
 147         if (IS_RDONLY(inode)) {
 148                 iput(inode);
 149                 return -EROFS;
 150         }
 151         /* Don't worry, the checks are done in inode_change_ok() */
 152         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 153         if (times) {
 154                 error = verify_area(VERIFY_READ, times, sizeof(*times));
 155                 if (error) {
 156                         iput(inode);
 157                         return error;
 158                 }
 159                 newattrs.ia_atime = get_user(&times->actime);
 160                 newattrs.ia_mtime = get_user(&times->modtime);
 161                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 162         } else {
 163                 if ((error = permission(inode,MAY_WRITE)) != 0) {
 164                         iput(inode);
 165                         return error;
 166                 }
 167         }
 168         error = notify_change(inode, &newattrs);
 169         iput(inode);
 170         return error;
 171 }
 172 
 173 /* If times==NULL, set access and modification to current time,
 174  * must be owner or have write permission.
 175  * Else, update from *times, must be owner or super user.
 176  */
 177 asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179         int error;
 180         struct inode * inode;
 181         struct iattr newattrs;
 182 
 183         error = namei(filename,&inode);
 184         if (error)
 185                 return error;
 186         if (IS_RDONLY(inode)) {
 187                 iput(inode);
 188                 return -EROFS;
 189         }
 190         /* Don't worry, the checks are done in inode_change_ok() */
 191         newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 192         if (utimes) {
 193                 struct timeval times[2];
 194                 error = verify_area(VERIFY_READ, utimes, sizeof(times));
 195                 if (error) {
 196                         iput(inode);
 197                         return error;
 198                 }
 199                 memcpy_fromfs(&times, utimes, sizeof(times));
 200                 newattrs.ia_atime = times[0].tv_sec;
 201                 newattrs.ia_mtime = times[1].tv_sec;
 202                 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 203         } else {
 204                 if ((error = permission(inode,MAY_WRITE)) != 0) {
 205                         iput(inode);
 206                         return error;
 207                 }
 208         }
 209         error = notify_change(inode, &newattrs);
 210         iput(inode);
 211         return error;
 212 }
 213 
 214 /*
 215  * access() needs to use the real uid/gid, not the effective uid/gid.
 216  * We do this by temporarily setting fsuid/fsgid to the wanted values
 217  */
 218 asmlinkage int sys_access(const char * filename, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 219 {
 220         struct inode * inode;
 221         int old_fsuid, old_fsgid;
 222         int res;
 223 
 224         if (mode != (mode & S_IRWXO))   /* where's F_OK, X_OK, W_OK, R_OK? */
 225                 return -EINVAL;
 226         old_fsuid = current->fsuid;
 227         old_fsgid = current->fsgid;
 228         current->fsuid = current->uid;
 229         current->fsgid = current->gid;
 230         res = namei(filename,&inode);
 231         if (!res) {
 232                 res = permission(inode, mode);
 233                 iput(inode);
 234         }
 235         current->fsuid = old_fsuid;
 236         current->fsgid = old_fsgid;
 237         return res;
 238 }
 239 
 240 asmlinkage int sys_chdir(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 241 {
 242         struct inode * inode;
 243         int error;
 244 
 245         error = namei(filename,&inode);
 246         if (error)
 247                 return error;
 248         if (!S_ISDIR(inode->i_mode)) {
 249                 iput(inode);
 250                 return -ENOTDIR;
 251         }
 252         if ((error = permission(inode,MAY_EXEC)) != 0) {
 253                 iput(inode);
 254                 return error;
 255         }
 256         iput(current->fs->pwd);
 257         current->fs->pwd = inode;
 258         return (0);
 259 }
 260 
 261 asmlinkage int sys_fchdir(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263         struct inode * inode;
 264         struct file * file;
 265         int error;
 266 
 267         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 268                 return -EBADF;
 269         if (!(inode = file->f_inode))
 270                 return -ENOENT;
 271         if (!S_ISDIR(inode->i_mode))
 272                 return -ENOTDIR;
 273         if ((error = permission(inode,MAY_EXEC)) != 0)
 274                 return error;
 275         iput(current->fs->pwd);
 276         current->fs->pwd = inode;
 277         inode->i_count++;
 278         return (0);
 279 }
 280 
 281 asmlinkage int sys_chroot(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 282 {
 283         struct inode * inode;
 284         int error;
 285 
 286         error = namei(filename,&inode);
 287         if (error)
 288                 return error;
 289         if (!S_ISDIR(inode->i_mode)) {
 290                 iput(inode);
 291                 return -ENOTDIR;
 292         }
 293         if (!fsuser()) {
 294                 iput(inode);
 295                 return -EPERM;
 296         }
 297         iput(current->fs->root);
 298         current->fs->root = inode;
 299         return (0);
 300 }
 301 
 302 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 303 {
 304         struct inode * inode;
 305         struct file * file;
 306         struct iattr newattrs;
 307 
 308         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 309                 return -EBADF;
 310         if (!(inode = file->f_inode))
 311                 return -ENOENT;
 312         if (IS_RDONLY(inode))
 313                 return -EROFS;
 314         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 315                 return -EPERM;
 316         if (mode == (mode_t) -1)
 317                 mode = inode->i_mode;
 318         newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 319         newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 320         inode->i_dirt = 1;
 321         return notify_change(inode, &newattrs);
 322 }
 323 
 324 asmlinkage int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 325 {
 326         struct inode * inode;
 327         int error;
 328         struct iattr newattrs;
 329 
 330         error = namei(filename,&inode);
 331         if (error)
 332                 return error;
 333         if (IS_RDONLY(inode)) {
 334                 iput(inode);
 335                 return -EROFS;
 336         }
 337         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
 338                 iput(inode);
 339                 return -EPERM;
 340         }
 341         if (mode == (mode_t) -1)
 342                 mode = inode->i_mode;
 343         newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 344         newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 345         inode->i_dirt = 1;
 346         error = notify_change(inode, &newattrs);
 347         iput(inode);
 348         return error;
 349 }
 350 
 351 asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 352 {
 353         struct inode * inode;
 354         struct file * file;
 355         struct iattr newattrs;
 356         int error;
 357 
 358         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 359                 return -EBADF;
 360         if (!(inode = file->f_inode))
 361                 return -ENOENT;
 362         if (IS_RDONLY(inode))
 363                 return -EROFS;
 364         if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 365                 return -EPERM;
 366         if (user == (uid_t) -1)
 367                 user = inode->i_uid;
 368         if (group == (gid_t) -1)
 369                 group = inode->i_gid;
 370         newattrs.ia_mode = inode->i_mode;
 371         newattrs.ia_uid = user;
 372         newattrs.ia_gid = group;
 373         newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
 374         /*
 375          * If the owner has been changed, remove the setuid bit
 376          */
 377         if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
 378                 newattrs.ia_mode &= ~S_ISUID;
 379                 newattrs.ia_valid |= ATTR_MODE;
 380         }
 381         /*
 382          * If the group has been changed, remove the setgid bit
 383          */
 384         if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
 385                 newattrs.ia_mode &= ~S_ISGID;
 386                 newattrs.ia_valid |= ATTR_MODE;
 387         }
 388         inode->i_dirt = 1;
 389         if (inode->i_sb && inode->i_sb->dq_op) {
 390                 inode->i_sb->dq_op->initialize(inode, -1);
 391                 if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
 392                         return -EDQUOT;
 393                 error = notify_change(inode, &newattrs);
 394                 if (error)
 395                         inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 396         } else
 397                 error = notify_change(inode, &newattrs);
 398         return error;
 399 }
 400 
 401 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 402 {
 403         struct inode * inode;
 404         int error;
 405         struct iattr newattrs;
 406 
 407         error = lnamei(filename,&inode);
 408         if (error)
 409                 return error;
 410         if (IS_RDONLY(inode)) {
 411                 iput(inode);
 412                 return -EROFS;
 413         }
 414         if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
 415                 iput(inode);
 416                 return -EPERM;
 417         }
 418         if (user == (uid_t) -1)
 419                 user = inode->i_uid;
 420         if (group == (gid_t) -1)
 421                 group = inode->i_gid;
 422         newattrs.ia_mode = inode->i_mode;
 423         newattrs.ia_uid = user;
 424         newattrs.ia_gid = group;
 425         newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
 426         /*
 427          * If the owner has been changed, remove the setuid bit
 428          */
 429         if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
 430                 newattrs.ia_mode &= ~S_ISUID;
 431                 newattrs.ia_valid |= ATTR_MODE;
 432         }
 433         /*
 434          * If the group has been changed, remove the setgid bit
 435          */
 436         if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
 437                 newattrs.ia_mode &= ~S_ISGID;
 438                 newattrs.ia_valid |= ATTR_MODE;
 439         }
 440         inode->i_dirt = 1;
 441         if (inode->i_sb->dq_op) {
 442                 inode->i_sb->dq_op->initialize(inode, -1);
 443                 if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
 444                         return -EDQUOT;
 445                 error = notify_change(inode, &newattrs);
 446                 if (error)
 447                         inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 448         } else
 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         f = get_empty_filp();
 475         if (!f)
 476                 return -ENFILE;
 477         f->f_flags = flag = flags;
 478         f->f_mode = (flag+1) & O_ACCMODE;
 479         if (f->f_mode)
 480                 flag++;
 481         if (flag & (O_TRUNC | O_CREAT))
 482                 flag |= 2;
 483         error = open_namei(filename,flag,mode,&inode,NULL);
 484         if (error)
 485                 goto cleanup_file;
 486         if (f->f_mode & FMODE_WRITE) {
 487                 error = get_write_access(inode);
 488                 if (error)
 489                         goto cleanup_inode;
 490         }
 491 
 492         f->f_inode = inode;
 493         f->f_pos = 0;
 494         f->f_reada = 0;
 495         f->f_op = NULL;
 496         if (inode->i_op)
 497                 f->f_op = inode->i_op->default_file_ops;
 498         if (f->f_op && f->f_op->open) {
 499                 error = f->f_op->open(inode,f);
 500                 if (error)
 501                         goto cleanup_all;
 502         }
 503         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 504 
 505         /*
 506          * We have to do this last, because we mustn't export
 507          * an incomplete fd to other processes which may share
 508          * the same file table with us.
 509          */
 510         for(fd = 0; fd < NR_OPEN && fd < current->rlim[RLIMIT_NOFILE].rlim_cur; fd++) {
 511                 if (!current->files->fd[fd]) {
 512                         current->files->fd[fd] = f;
 513                         FD_CLR(fd,&current->files->close_on_exec);
 514                         return fd;
 515                 }
 516         }
 517         error = -EMFILE;
 518         if (f->f_op && f->f_op->release)
 519                 f->f_op->release(inode,f);
 520 cleanup_all:
 521         if (f->f_mode & FMODE_WRITE)
 522                 put_write_access(inode);
 523 cleanup_inode:
 524         iput(inode);
 525 cleanup_file:
 526         f->f_count--;
 527         return error;
 528 }
 529 
 530 asmlinkage int sys_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 531 {
 532         char * tmp;
 533         int error;
 534 
 535         error = getname(filename, &tmp);
 536         if (error)
 537                 return error;
 538         error = do_open(tmp,flags,mode);
 539         putname(tmp);
 540         return error;
 541 }
 542 
 543 asmlinkage int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 544 {
 545         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 546 }
 547 
 548 int close_fp(struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 549 {
 550         struct inode *inode;
 551 
 552         if (filp->f_count == 0) {
 553                 printk("VFS: Close: file count is 0\n");
 554                 return 0;
 555         }
 556         inode = filp->f_inode;
 557         if (inode)
 558                 locks_remove_locks(current, filp);
 559         if (filp->f_count > 1) {
 560                 filp->f_count--;
 561                 return 0;
 562         }
 563         if (filp->f_op && filp->f_op->release)
 564                 filp->f_op->release(inode,filp);
 565         filp->f_count--;
 566         filp->f_inode = NULL;
 567         if (filp->f_mode & FMODE_WRITE)
 568                 put_write_access(inode);
 569         iput(inode);
 570         return 0;
 571 }
 572 
 573 asmlinkage int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {       
 575         struct file * filp;
 576 
 577         if (fd >= NR_OPEN)
 578                 return -EBADF;
 579         FD_CLR(fd, &current->files->close_on_exec);
 580         if (!(filp = current->files->fd[fd]))
 581                 return -EBADF;
 582         current->files->fd[fd] = NULL;
 583         return (close_fp (filp));
 584 }
 585 
 586 /*
 587  * This routine simulates a hangup on the tty, to arrange that users
 588  * are given clean terminals at login time.
 589  */
 590 asmlinkage int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 591 {
 592         if (!suser())
 593                 return -EPERM;
 594         /* If there is a controlling tty, hang it up */
 595         if (current->tty)
 596                 tty_vhangup(current->tty);
 597         return 0;
 598 }

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