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

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