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

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