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         inode->i_count++;
 229         return (0);
 230 }
 231 
 232 asmlinkage int sys_chroot(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         struct inode * inode;
 235         int error;
 236 
 237         error = namei(filename,&inode);
 238         if (error)
 239                 return error;
 240         if (!S_ISDIR(inode->i_mode)) {
 241                 iput(inode);
 242                 return -ENOTDIR;
 243         }
 244         if (!suser()) {
 245                 iput(inode);
 246                 return -EPERM;
 247         }
 248         iput(current->root);
 249         current->root = inode;
 250         return (0);
 251 }
 252 
 253 asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255         struct inode * inode;
 256         struct file * file;
 257 
 258         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 259                 return -EBADF;
 260         if (!(inode = file->f_inode))
 261                 return -ENOENT;
 262         if ((current->euid != inode->i_uid) && !suser())
 263                 return -EPERM;
 264         if (IS_RDONLY(inode))
 265                 return -EROFS;
 266         if (mode == (mode_t) -1)
 267                 mode = inode->i_mode;
 268         inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 269         if (!suser() && !in_group_p(inode->i_gid))
 270                 inode->i_mode &= ~S_ISGID;
 271         inode->i_ctime = CURRENT_TIME;
 272         inode->i_dirt = 1;
 273         return notify_change(NOTIFY_MODE, inode);
 274 }
 275 
 276 asmlinkage int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 277 {
 278         struct inode * inode;
 279         int error;
 280 
 281         error = namei(filename,&inode);
 282         if (error)
 283                 return error;
 284         if ((current->euid != inode->i_uid) && !suser()) {
 285                 iput(inode);
 286                 return -EPERM;
 287         }
 288         if (IS_RDONLY(inode)) {
 289                 iput(inode);
 290                 return -EROFS;
 291         }
 292         if (mode == (mode_t) -1)
 293                 mode = inode->i_mode;
 294         inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 295         if (!suser() && !in_group_p(inode->i_gid))
 296                 inode->i_mode &= ~S_ISGID;
 297         inode->i_ctime = CURRENT_TIME;
 298         inode->i_dirt = 1;
 299         error = notify_change(NOTIFY_MODE, inode);
 300         iput(inode);
 301         return error;
 302 }
 303 
 304 asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 305 {
 306         struct inode * inode;
 307         struct file * file;
 308 
 309         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 310                 return -EBADF;
 311         if (!(inode = file->f_inode))
 312                 return -ENOENT;
 313         if (IS_RDONLY(inode))
 314                 return -EROFS;
 315         if (user == (uid_t) -1)
 316                 user = inode->i_uid;
 317         if (group == (gid_t) -1)
 318                 group = inode->i_gid;
 319         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 320              (in_group_p(group) || group == inode->i_gid)) ||
 321             suser()) {
 322                 inode->i_uid = user;
 323                 inode->i_gid = group;
 324                 inode->i_ctime = CURRENT_TIME;
 325                 inode->i_dirt = 1;
 326                 return notify_change(NOTIFY_UIDGID, inode);
 327         }
 328         return -EPERM;
 329 }
 330 
 331 asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 332 {
 333         struct inode * inode;
 334         int error;
 335 
 336         error = lnamei(filename,&inode);
 337         if (error)
 338                 return error;
 339         if (IS_RDONLY(inode)) {
 340                 iput(inode);
 341                 return -EROFS;
 342         }
 343         if (user == (uid_t) -1)
 344                 user = inode->i_uid;
 345         if (group == (gid_t) -1)
 346                 group = inode->i_gid;
 347         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 348              (in_group_p(group) || group == inode->i_gid)) ||
 349             suser()) {
 350                 inode->i_uid = user;
 351                 inode->i_gid = group;
 352                 inode->i_ctime = CURRENT_TIME;
 353                 inode->i_dirt = 1;
 354                 error = notify_change(NOTIFY_UIDGID, inode);
 355                 iput(inode);
 356                 return error;
 357         }
 358         iput(inode);
 359         return -EPERM;
 360 }
 361 
 362 /*
 363  * Note that while the flag value (low two bits) for sys_open means:
 364  *      00 - read-only
 365  *      01 - write-only
 366  *      10 - read-write
 367  *      11 - special
 368  * it is changed into
 369  *      00 - no permissions needed
 370  *      01 - read-permission
 371  *      10 - write-permission
 372  *      11 - read-write
 373  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 374  * used by symlinks.
 375  */
 376 int do_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 377 {
 378         struct inode * inode;
 379         struct file * f;
 380         int flag,error,fd;
 381 
 382         for(fd=0 ; fd<NR_OPEN ; fd++)
 383                 if (!current->filp[fd])
 384                         break;
 385         if (fd>=NR_OPEN)
 386                 return -EMFILE;
 387         FD_CLR(fd,&current->close_on_exec);
 388         f = get_empty_filp();
 389         if (!f)
 390                 return -ENFILE;
 391         current->filp[fd] = f;
 392         f->f_flags = flag = flags;
 393         f->f_mode = (flag+1) & O_ACCMODE;
 394         if (f->f_mode)
 395                 flag++;
 396         if (flag & (O_TRUNC | O_CREAT))
 397                 flag |= 2;
 398         error = open_namei(filename,flag,mode,&inode,NULL);
 399         if (error) {
 400                 current->filp[fd]=NULL;
 401                 f->f_count--;
 402                 return error;
 403         }
 404 
 405         f->f_inode = inode;
 406         f->f_pos = 0;
 407         f->f_reada = 0;
 408         f->f_op = NULL;
 409         if (inode->i_op)
 410                 f->f_op = inode->i_op->default_file_ops;
 411         if (f->f_op && f->f_op->open) {
 412                 error = f->f_op->open(inode,f);
 413                 if (error) {
 414                         iput(inode);
 415                         f->f_count--;
 416                         current->filp[fd]=NULL;
 417                         return error;
 418                 }
 419         }
 420         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 421         return (fd);
 422 }
 423 
 424 asmlinkage int sys_open(const char * filename,int flags,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426         char * tmp;
 427         int error;
 428 
 429         error = getname(filename, &tmp);
 430         if (error)
 431                 return error;
 432         error = do_open(tmp,flags,mode);
 433         putname(tmp);
 434         return error;
 435 }
 436 
 437 asmlinkage int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 440 }
 441 
 442 int close_fp(struct file *filp, unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 443 {
 444         struct inode *inode;
 445 
 446         if (filp->f_count == 0) {
 447                 printk("VFS: Close: file count is 0\n");
 448                 return 0;
 449         }
 450         inode = filp->f_inode;
 451         if (inode && S_ISREG(inode->i_mode))
 452                 fcntl_remove_locks(current, filp, fd);
 453         if (filp->f_count > 1) {
 454                 filp->f_count--;
 455                 return 0;
 456         }
 457         if (filp->f_op && filp->f_op->release)
 458                 filp->f_op->release(inode,filp);
 459         filp->f_count--;
 460         filp->f_inode = NULL;
 461         iput(inode);
 462         return 0;
 463 }
 464 
 465 asmlinkage int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 466 {       
 467         struct file * filp;
 468 
 469         if (fd >= NR_OPEN)
 470                 return -EBADF;
 471         FD_CLR(fd, &current->close_on_exec);
 472         if (!(filp = current->filp[fd]))
 473                 return -EBADF;
 474         current->filp[fd] = NULL;
 475         return (close_fp (filp, fd));
 476 }
 477 
 478 /*
 479  * This routine simulates a hangup on the tty, to arrange that users
 480  * are given clean terminals at login time.
 481  */
 482 asmlinkage int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 483 {
 484         struct tty_struct *tty;
 485 
 486         if (!suser())
 487                 return -EPERM;
 488         /* See if there is a controlling tty. */
 489         if (current->tty < 0)
 490                 return 0;
 491         tty = TTY_TABLE(MINOR(current->tty));
 492         tty_vhangup(tty);
 493         return 0;
 494 }

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