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->filp[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->filp[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->euid != inode->i_uid) && !suser()) {
 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->euid != 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  * XXX we should use the real ids for checking _all_ components of the
 156  * path.  Now we only use them for the final component of the path.
 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 res, i_mode;
 162 
 163         if (mode != (mode & S_IRWXO))   /* where's F_OK, X_OK, W_OK, R_OK? */
 164                 return -EINVAL;
 165         res = namei(filename,&inode);
 166         if (res)
 167                 return res;
 168         i_mode = inode->i_mode;
 169         res = i_mode & S_IRWXUGO;
 170         if (current->uid == inode->i_uid)
 171                 res >>= 6;              /* needs cleaning? */
 172         else if (in_group_p(inode->i_gid))
 173                 res >>= 3;              /* needs cleaning? */
 174         iput(inode);
 175         if ((res & mode) == mode)
 176                 return 0;
 177         /*
 178          * XXX we are doing this test last because we really should be
 179          * swapping the effective with the real user id (temporarily),
 180          * and then calling suser() routine.  If we do call the
 181          * suser() routine, it needs to be called last. 
 182          *
 183          * XXX nope.  suser() is inappropriate and swapping the ids while
 184          * decomposing the path would be racy.
 185          */
 186         if ((!current->uid) &&
 187             (S_ISDIR(i_mode) || !(mode & S_IXOTH) || (i_mode & S_IXUGO)))
 188                 return 0;
 189         return -EACCES;
 190 }
 191 
 192 asmlinkage int sys_chdir(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         struct inode * inode;
 195         int error;
 196 
 197         error = namei(filename,&inode);
 198         if (error)
 199                 return error;
 200         if (!S_ISDIR(inode->i_mode)) {
 201                 iput(inode);
 202                 return -ENOTDIR;
 203         }
 204         if (!permission(inode,MAY_EXEC)) {
 205                 iput(inode);
 206                 return -EACCES;
 207         }
 208         iput(current->pwd);
 209         current->pwd = inode;
 210         return (0);
 211 }
 212 
 213 asmlinkage int sys_fchdir(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215         struct inode * inode;
 216         struct file * file;
 217 
 218         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 219                 return -EBADF;
 220         if (!(inode = file->f_inode))
 221                 return -ENOENT;
 222         if (!S_ISDIR(inode->i_mode))
 223                 return -ENOTDIR;
 224         if (!permission(inode,MAY_EXEC))
 225                 return -EACCES;
 226         iput(current->pwd);
 227         current->pwd = inode;
 228         return (0);
 229 }
 230 
 231 asmlinkage int sys_chroot(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 232 {
 233         struct inode * inode;
 234         int error;
 235 
 236         error = namei(filename,&inode);
 237         if (error)
 238                 return error;
 239         if (!S_ISDIR(inode->i_mode)) {
 240                 iput(inode);
 241                 return -ENOTDIR;
 242         }
 243         if (!suser()) {
 244                 iput(inode);
 245                 return -EPERM;
 246         }
 247         iput(current->root);
 248         current->root = inode;
 249         return (0);
 250 }
 251 
 252 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254         struct inode * inode;
 255         struct file * file;
 256 
 257         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 258                 return -EBADF;
 259         if (!(inode = file->f_inode))
 260                 return -ENOENT;
 261         if ((current->euid != inode->i_uid) && !suser())
 262                 return -EPERM;
 263         if (IS_RDONLY(inode))
 264                 return -EROFS;
 265         inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 266         if (!suser() && !in_group_p(inode->i_gid))
 267                 inode->i_mode &= ~S_ISGID;
 268         inode->i_ctime = CURRENT_TIME;
 269         inode->i_dirt = 1;
 270         return notify_change(NOTIFY_MODE, inode);
 271 }
 272 
 273 asmlinkage int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275         struct inode * inode;
 276         int error;
 277 
 278         error = namei(filename,&inode);
 279         if (error)
 280                 return error;
 281         if ((current->euid != inode->i_uid) && !suser()) {
 282                 iput(inode);
 283                 return -EPERM;
 284         }
 285         if (IS_RDONLY(inode)) {
 286                 iput(inode);
 287                 return -EROFS;
 288         }
 289         inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 290         if (!suser() && !in_group_p(inode->i_gid))
 291                 inode->i_mode &= ~S_ISGID;
 292         inode->i_ctime = CURRENT_TIME;
 293         inode->i_dirt = 1;
 294         error = notify_change(NOTIFY_MODE, inode);
 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 
 304         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 305                 return -EBADF;
 306         if (!(inode = file->f_inode))
 307                 return -ENOENT;
 308         if (IS_RDONLY(inode))
 309                 return -EROFS;
 310         if (user == (uid_t) -1)
 311                 user = inode->i_uid;
 312         if (group == (gid_t) -1)
 313                 group = inode->i_gid;
 314         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 315              (in_group_p(group) || group == inode->i_gid)) ||
 316             suser()) {
 317                 inode->i_uid = user;
 318                 inode->i_gid = group;
 319                 inode->i_ctime = CURRENT_TIME;
 320                 inode->i_dirt = 1;
 321                 return notify_change(NOTIFY_UIDGID, inode);
 322         }
 323         return -EPERM;
 324 }
 325 
 326 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 327 {
 328         struct inode * inode;
 329         int error;
 330 
 331         error = lnamei(filename,&inode);
 332         if (error)
 333                 return error;
 334         if (IS_RDONLY(inode)) {
 335                 iput(inode);
 336                 return -EROFS;
 337         }
 338         if (user == (uid_t) -1)
 339                 user = inode->i_uid;
 340         if (group == (gid_t) -1)
 341                 group = inode->i_gid;
 342         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 343              (in_group_p(group) || group == inode->i_gid)) ||
 344             suser()) {
 345                 inode->i_uid = user;
 346                 inode->i_gid = group;
 347                 inode->i_ctime = CURRENT_TIME;
 348                 inode->i_dirt = 1;
 349                 error = notify_change(NOTIFY_UIDGID, inode);
 350                 iput(inode);
 351                 return error;
 352         }
 353         iput(inode);
 354         return -EPERM;
 355 }
 356 
 357 /*
 358  * Note that while the flag value (low two bits) for sys_open means:
 359  *      00 - read-only
 360  *      01 - write-only
 361  *      10 - read-write
 362  *      11 - special
 363  * it is changed into
 364  *      00 - no permissions needed
 365  *      01 - read-permission
 366  *      10 - write-permission
 367  *      11 - read-write
 368  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 369  * used by symlinks.
 370  */
 371 int do_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373         struct inode * inode;
 374         struct file * f;
 375         int flag,error,fd;
 376 
 377         for(fd=0 ; fd<NR_OPEN ; fd++)
 378                 if (!current->filp[fd])
 379                         break;
 380         if (fd>=NR_OPEN)
 381                 return -EMFILE;
 382         FD_CLR(fd,&current->close_on_exec);
 383         f = get_empty_filp();
 384         if (!f)
 385                 return -ENFILE;
 386         current->filp[fd] = f;
 387         f->f_flags = flag = flags;
 388         f->f_mode = (flag+1) & O_ACCMODE;
 389         if (f->f_mode)
 390                 flag++;
 391         if (flag & (O_TRUNC | O_CREAT))
 392                 flag |= 2;
 393         error = open_namei(filename,flag,mode,&inode,NULL);
 394         if (error) {
 395                 current->filp[fd]=NULL;
 396                 f->f_count--;
 397                 return error;
 398         }
 399 
 400         f->f_inode = inode;
 401         f->f_pos = 0;
 402         f->f_reada = 0;
 403         f->f_op = NULL;
 404         if (inode->i_op)
 405                 f->f_op = inode->i_op->default_file_ops;
 406         if (f->f_op && f->f_op->open) {
 407                 error = f->f_op->open(inode,f);
 408                 if (error) {
 409                         iput(inode);
 410                         f->f_count--;
 411                         current->filp[fd]=NULL;
 412                         return error;
 413                 }
 414         }
 415         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 416         return (fd);
 417 }
 418 
 419 asmlinkage int sys_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 420 {
 421         char * tmp;
 422         int error;
 423 
 424         error = getname(filename, &tmp);
 425         if (error)
 426                 return error;
 427         error = do_open(tmp,flags,mode);
 428         putname(tmp);
 429         return error;
 430 }
 431 
 432 asmlinkage int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 433 {
 434         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 435 }
 436 
 437 int close_fp(struct file *filp, unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439         struct inode *inode;
 440 
 441         if (filp->f_count == 0) {
 442                 printk("VFS: Close: file count is 0\n");
 443                 return 0;
 444         }
 445         inode = filp->f_inode;
 446         if (inode && S_ISREG(inode->i_mode))
 447                 fcntl_remove_locks(current, filp, fd);
 448         if (filp->f_count > 1) {
 449                 filp->f_count--;
 450                 return 0;
 451         }
 452         if (filp->f_op && filp->f_op->release)
 453                 filp->f_op->release(inode,filp);
 454         filp->f_count--;
 455         filp->f_inode = NULL;
 456         iput(inode);
 457         return 0;
 458 }
 459 
 460 asmlinkage int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 461 {       
 462         struct file * filp;
 463 
 464         if (fd >= NR_OPEN)
 465                 return -EBADF;
 466         FD_CLR(fd, &current->close_on_exec);
 467         if (!(filp = current->filp[fd]))
 468                 return -EBADF;
 469         current->filp[fd] = NULL;
 470         return (close_fp (filp, fd));
 471 }
 472 
 473 /*
 474  * This routine simulates a hangup on the tty, to arrange that users
 475  * are given clean terminals at login time.
 476  */
 477 asmlinkage int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 478 {
 479         struct tty_struct *tty;
 480 
 481         if (!suser())
 482                 return -EPERM;
 483         /* See if there is a controlling tty. */
 484         if (current->tty < 0)
 485                 return 0;
 486         tty = TTY_TABLE(MINOR(current->tty));
 487         tty_vhangup(tty);
 488         return 0;
 489 }

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