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

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