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

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