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

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