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. sys_open
  15. sys_creat
  16. close_fp
  17. sys_close
  18. 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 *);
  23 
  24 int sys_ustat(int dev, struct ustat * ubuf)
     /* [previous][next][first][last][top][bottom][index][help] */
  25 {
  26         return -ENOSYS;
  27 }
  28 
  29 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 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 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_atime = 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 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_atime = 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 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 compenent of the path.
 157  */
 158 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 & 0007))      /* 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 & 0777;
 170         if (current->uid == inode->i_uid)
 171                 res >>= 6;
 172         else if (in_group_p(inode->i_gid))
 173                 res >>= 3;
 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 & 1) || (i_mode & 0111)))
 188                 return 0;
 189         return -EACCES;
 190 }
 191 
 192 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 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 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 & 07777) | (inode->i_mode & ~07777);
 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 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 & 07777) | (inode->i_mode & ~07777);
 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 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 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 sys_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         char * tmp;
 358         int flag,error,fd;
 359 
 360         for(fd=0 ; fd<NR_OPEN ; fd++)
 361                 if (!current->filp[fd])
 362                         break;
 363         if (fd>=NR_OPEN)
 364                 return -EMFILE;
 365         FD_CLR(fd,&current->close_on_exec);
 366         f = get_empty_filp();
 367         if (!f)
 368                 return -ENFILE;
 369         current->filp[fd] = f;
 370         f->f_flags = flag = flags;
 371         f->f_mode = (flag+1) & O_ACCMODE;
 372         if (f->f_mode)
 373                 flag++;
 374         if (flag & (O_TRUNC | O_CREAT))
 375                 flag |= 2;
 376         error = getname(filename,&tmp);
 377         if (!error) {
 378                 error = open_namei(tmp,flag,mode,&inode,NULL);
 379                 putname(tmp);
 380         }
 381         if (error) {
 382                 current->filp[fd]=NULL;
 383                 f->f_count--;
 384                 return error;
 385         }
 386         if (flag & O_TRUNC) {
 387                 inode->i_size = 0;
 388                 if (inode->i_op && inode->i_op->truncate)
 389                         inode->i_op->truncate(inode);
 390                 if ((error = notify_change(NOTIFY_SIZE, inode))) {
 391                         iput(inode);
 392                         current->filp[fd] = NULL;
 393                         f->f_count--;
 394                         return error;
 395                 }
 396                 inode->i_dirt = 1;
 397         }
 398         f->f_inode = inode;
 399         f->f_pos = 0;
 400         f->f_reada = 0;
 401         f->f_op = NULL;
 402         if (inode->i_op)
 403                 f->f_op = inode->i_op->default_file_ops;
 404         if (f->f_op && f->f_op->open) {
 405                 error = f->f_op->open(inode,f);
 406                 if (error) {
 407                         iput(inode);
 408                         f->f_count--;
 409                         current->filp[fd]=NULL;
 410                         return error;
 411                 }
 412         }
 413         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 414         return (fd);
 415 }
 416 
 417 int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 418 {
 419         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 420 }
 421 
 422 int close_fp(struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 423 {
 424         struct inode *inode;
 425 
 426         if (filp->f_count == 0) {
 427                 printk("VFS: Close: file count is 0\n");
 428                 return 0;
 429         }
 430         inode = filp->f_inode;
 431         if (inode && S_ISREG(inode->i_mode))
 432                 fcntl_remove_locks(current, filp);
 433         if (filp->f_count > 1) {
 434                 filp->f_count--;
 435                 return 0;
 436         }
 437         if (filp->f_op && filp->f_op->release)
 438                 filp->f_op->release(inode,filp);
 439         filp->f_count--;
 440         filp->f_inode = NULL;
 441         iput(inode);
 442         return 0;
 443 }
 444 
 445 int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 446 {       
 447         struct file * filp;
 448 
 449         if (fd >= NR_OPEN)
 450                 return -EBADF;
 451         FD_CLR(fd, &current->close_on_exec);
 452         if (!(filp = current->filp[fd]))
 453                 return -EBADF;
 454         current->filp[fd] = NULL;
 455         return (close_fp (filp));
 456 }
 457 
 458 /*
 459  * This routine simulates a hangup on the tty, to arrange that users
 460  * are given clean terminals at login time.
 461  */
 462 int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 463 {
 464         struct tty_struct *tty;
 465 
 466         if (!suser())
 467                 return -EPERM;
 468         /* See if there is a controlling tty. */
 469         if (current->tty < 0)
 470                 return 0;
 471         tty = TTY_TABLE(MINOR(current->tty));
 472         tty_vhangup(tty);
 473         return 0;
 474 }

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