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) || !permission(inode,MAY_WRITE)) {
  78                 iput(inode);
  79                 return -EACCES;
  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_fs_long((unsigned long *) &times->actime);
 156                 modtime = get_fs_long((unsigned long *) &times->modtime);
 157                 newattrs.ia_ctime = CURRENT_TIME;
 158                 flags = ATTR_ATIME_SET | ATTR_MTIME_SET;
 159         } else {
 160                 if (!permission(inode,MAY_WRITE)) {
 161                         iput(inode);
 162                         return -EACCES;
 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 /*
 176  * access() needs to use the real uid/gid, not the effective uid/gid.
 177  * We do this by temporarily setting fsuid/fsgid to the wanted values
 178  */
 179 asmlinkage int sys_access(const char * filename, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181         struct inode * inode;
 182         int old_fsuid, old_fsgid;
 183         int res;
 184 
 185         if (mode != (mode & S_IRWXO))   /* where's F_OK, X_OK, W_OK, R_OK? */
 186                 return -EINVAL;
 187         old_fsuid = current->fsuid;
 188         old_fsgid = current->fsgid;
 189         current->fsuid = current->uid;
 190         current->fsgid = current->gid;
 191         res = namei(filename,&inode);
 192         if (!res) {
 193                 if (!permission(inode, mode))
 194                         res = -EACCES;
 195                 iput(inode);
 196         }
 197         current->fsuid = old_fsuid;
 198         current->fsgid = old_fsgid;
 199         return res;
 200 }
 201 
 202 asmlinkage int sys_chdir(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204         struct inode * inode;
 205         int error;
 206 
 207         error = namei(filename,&inode);
 208         if (error)
 209                 return error;
 210         if (!S_ISDIR(inode->i_mode)) {
 211                 iput(inode);
 212                 return -ENOTDIR;
 213         }
 214         if (!permission(inode,MAY_EXEC)) {
 215                 iput(inode);
 216                 return -EACCES;
 217         }
 218         iput(current->fs->pwd);
 219         current->fs->pwd = inode;
 220         return (0);
 221 }
 222 
 223 asmlinkage int sys_fchdir(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225         struct inode * inode;
 226         struct file * file;
 227 
 228         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 229                 return -EBADF;
 230         if (!(inode = file->f_inode))
 231                 return -ENOENT;
 232         if (!S_ISDIR(inode->i_mode))
 233                 return -ENOTDIR;
 234         if (!permission(inode,MAY_EXEC))
 235                 return -EACCES;
 236         iput(current->fs->pwd);
 237         current->fs->pwd = inode;
 238         inode->i_count++;
 239         return (0);
 240 }
 241 
 242 asmlinkage int sys_chroot(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244         struct inode * inode;
 245         int error;
 246 
 247         error = namei(filename,&inode);
 248         if (error)
 249                 return error;
 250         if (!S_ISDIR(inode->i_mode)) {
 251                 iput(inode);
 252                 return -ENOTDIR;
 253         }
 254         if (!fsuser()) {
 255                 iput(inode);
 256                 return -EPERM;
 257         }
 258         iput(current->fs->root);
 259         current->fs->root = inode;
 260         return (0);
 261 }
 262 
 263 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265         struct inode * inode;
 266         struct file * file;
 267         struct iattr newattrs;
 268 
 269         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 270                 return -EBADF;
 271         if (!(inode = file->f_inode))
 272                 return -ENOENT;
 273         if (IS_RDONLY(inode))
 274                 return -EROFS;
 275         if (mode == (mode_t) -1)
 276                 mode = inode->i_mode;
 277         newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 278         newattrs.ia_ctime = CURRENT_TIME;
 279         newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 280         inode->i_dirt = 1;
 281         return notify_change(inode, &newattrs);
 282 }
 283 
 284 asmlinkage int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286         struct inode * inode;
 287         int error;
 288         struct iattr newattrs;
 289 
 290         error = namei(filename,&inode);
 291         if (error)
 292                 return error;
 293         if (IS_RDONLY(inode)) {
 294                 iput(inode);
 295                 return -EROFS;
 296         }
 297         if (mode == (mode_t) -1)
 298                 mode = inode->i_mode;
 299         newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 300         newattrs.ia_ctime = CURRENT_TIME;
 301         newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 302         inode->i_dirt = 1;
 303         error = notify_change(inode, &newattrs);
 304         iput(inode);
 305         return error;
 306 }
 307 
 308 asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310         struct inode * inode;
 311         struct file * file;
 312         struct iattr newattrs;
 313 
 314         if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 315                 return -EBADF;
 316         if (!(inode = file->f_inode))
 317                 return -ENOENT;
 318         if (IS_RDONLY(inode))
 319                 return -EROFS;
 320         if (user == (uid_t) -1)
 321                 user = inode->i_uid;
 322         if (group == (gid_t) -1)
 323                 group = inode->i_gid;
 324         newattrs.ia_mode = inode->i_mode;
 325         newattrs.ia_uid = user;
 326         newattrs.ia_gid = group;
 327         newattrs.ia_ctime = CURRENT_TIME;
 328         newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
 329         /*
 330          * If the owner has been changed, remove the setuid bit
 331          */
 332         if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
 333                 newattrs.ia_mode &= ~S_ISUID;
 334                 newattrs.ia_valid |= ATTR_MODE;
 335         }
 336         /*
 337          * If the group has been changed, remove the setgid bit
 338          */
 339         if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
 340                 newattrs.ia_mode &= ~S_ISGID;
 341                 newattrs.ia_valid |= ATTR_MODE;
 342         }
 343         inode->i_dirt = 1;
 344         return notify_change(inode, &newattrs);
 345 }
 346 
 347 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 348 {
 349         struct inode * inode;
 350         int error;
 351         struct iattr newattrs;
 352 
 353         error = lnamei(filename,&inode);
 354         if (error)
 355                 return error;
 356         if (IS_RDONLY(inode)) {
 357                 iput(inode);
 358                 return -EROFS;
 359         }
 360         if (user == (uid_t) -1)
 361                 user = inode->i_uid;
 362         if (group == (gid_t) -1)
 363                 group = inode->i_gid;
 364         newattrs.ia_mode = inode->i_mode;
 365         newattrs.ia_uid = user;
 366         newattrs.ia_gid = group;
 367         newattrs.ia_ctime = CURRENT_TIME;
 368         newattrs.ia_valid =  ATTR_UID | ATTR_GID | ATTR_CTIME;
 369         /*
 370          * If the owner has been changed, remove the setuid bit
 371          */
 372         if (user != inode->i_uid && (inode->i_mode & S_ISUID)) {
 373                 newattrs.ia_mode &= ~S_ISUID;
 374                 newattrs.ia_valid |= ATTR_MODE;
 375         }
 376         /*
 377          * If the group has been changed, remove the setgid bit
 378          */
 379         if (group != inode->i_gid && (inode->i_mode & S_ISGID)) {
 380                 newattrs.ia_mode &= ~S_ISGID;
 381                 newattrs.ia_valid |= ATTR_MODE;
 382         }
 383         inode->i_dirt = 1;
 384         error = notify_change(inode, &newattrs);
 385         iput(inode);
 386         return(error);
 387 }
 388 
 389 /*
 390  * Note that while the flag value (low two bits) for sys_open means:
 391  *      00 - read-only
 392  *      01 - write-only
 393  *      10 - read-write
 394  *      11 - special
 395  * it is changed into
 396  *      00 - no permissions needed
 397  *      01 - read-permission
 398  *      10 - write-permission
 399  *      11 - read-write
 400  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 401  * used by symlinks.
 402  */
 403 int do_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405         struct inode * inode;
 406         struct file * f;
 407         int flag,error,fd;
 408 
 409         for(fd=0 ; fd<NR_OPEN ; fd++)
 410                 if (!current->files->fd[fd])
 411                         break;
 412         if (fd>=NR_OPEN)
 413                 return -EMFILE;
 414         FD_CLR(fd,&current->files->close_on_exec);
 415         f = get_empty_filp();
 416         if (!f)
 417                 return -ENFILE;
 418         current->files->fd[fd] = f;
 419         f->f_flags = flag = flags;
 420         f->f_mode = (flag+1) & O_ACCMODE;
 421         if (f->f_mode)
 422                 flag++;
 423         if (flag & (O_TRUNC | O_CREAT))
 424                 flag |= 2;
 425         error = open_namei(filename,flag,mode,&inode,NULL);
 426         if (!error && (f->f_mode & 2)) {
 427                 error = get_write_access(inode);
 428                 if (error)
 429                         iput(inode);
 430         }
 431         if (error) {
 432                 current->files->fd[fd]=NULL;
 433                 f->f_count--;
 434                 return error;
 435         }
 436 
 437         f->f_inode = inode;
 438         f->f_pos = 0;
 439         f->f_reada = 0;
 440         f->f_op = NULL;
 441         if (inode->i_op)
 442                 f->f_op = inode->i_op->default_file_ops;
 443         if (f->f_op && f->f_op->open) {
 444                 error = f->f_op->open(inode,f);
 445                 if (error) {
 446                         if (f->f_mode & 2) put_write_access(inode);
 447                         iput(inode);
 448                         f->f_count--;
 449                         current->files->fd[fd]=NULL;
 450                         return error;
 451                 }
 452         }
 453         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 454         return (fd);
 455 }
 456 
 457 asmlinkage int sys_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 458 {
 459         char * tmp;
 460         int error;
 461 
 462         error = getname(filename, &tmp);
 463         if (error)
 464                 return error;
 465         error = do_open(tmp,flags,mode);
 466         putname(tmp);
 467         return error;
 468 }
 469 
 470 asmlinkage int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 471 {
 472         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 473 }
 474 
 475 int close_fp(struct file *filp, unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 476 {
 477         struct inode *inode;
 478 
 479         if (filp->f_count == 0) {
 480                 printk("VFS: Close: file count is 0\n");
 481                 return 0;
 482         }
 483         inode = filp->f_inode;
 484         if (inode)
 485                 fcntl_remove_locks(current, filp, fd);
 486         if (filp->f_count > 1) {
 487                 filp->f_count--;
 488                 return 0;
 489         }
 490         if (filp->f_op && filp->f_op->release)
 491                 filp->f_op->release(inode,filp);
 492         filp->f_count--;
 493         filp->f_inode = NULL;
 494         if (filp->f_mode & 2) put_write_access(inode);
 495         iput(inode);
 496         return 0;
 497 }
 498 
 499 asmlinkage int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 500 {       
 501         struct file * filp;
 502 
 503         if (fd >= NR_OPEN)
 504                 return -EBADF;
 505         FD_CLR(fd, &current->files->close_on_exec);
 506         if (!(filp = current->files->fd[fd]))
 507                 return -EBADF;
 508         current->files->fd[fd] = NULL;
 509         return (close_fp (filp, fd));
 510 }
 511 
 512 /*
 513  * This routine simulates a hangup on the tty, to arrange that users
 514  * are given clean terminals at login time.
 515  */
 516 asmlinkage int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 517 {
 518         if (!suser())
 519                 return -EPERM;
 520         /* If there is a controlling tty, hang it up */
 521         if (current->tty)
 522                 tty_vhangup(current->tty);
 523         return 0;
 524 }

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