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

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