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

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