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         verify_area(buf, sizeof(struct statfs));
  35         error = namei(path,&inode);
  36         if (error)
  37                 return error;
  38         if (!inode->i_sb->s_op->statfs) {
  39                 iput(inode);
  40                 return -ENOSYS;
  41         }
  42         inode->i_sb->s_op->statfs(inode->i_sb, buf);
  43         iput(inode);
  44         return 0;
  45 }
  46 
  47 int sys_fstatfs(unsigned int fd, struct statfs * buf)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49         struct inode * inode;
  50         struct file * file;
  51 
  52         verify_area(buf, sizeof(struct statfs));
  53         if (fd >= NR_OPEN || !(file = current->filp[fd]))
  54                 return -EBADF;
  55         if (!(inode = file->f_inode))
  56                 return -ENOENT;
  57         if (!inode->i_sb->s_op->statfs)
  58                 return -ENOSYS;
  59         inode->i_sb->s_op->statfs(inode->i_sb, buf);
  60         return 0;
  61 }
  62 
  63 int sys_truncate(const char * path, unsigned int length)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65         struct inode * inode;
  66         int error;
  67 
  68         error = namei(path,&inode);
  69         if (error)
  70                 return error;
  71         if (S_ISDIR(inode->i_mode) || !permission(inode,MAY_WRITE)) {
  72                 iput(inode);
  73                 return -EACCES;
  74         }
  75         if (IS_RDONLY(inode)) {
  76                 iput(inode);
  77                 return -EROFS;
  78         }
  79         inode->i_size = length;
  80         if (inode->i_op && inode->i_op->truncate)
  81                 inode->i_op->truncate(inode);
  82         inode->i_atime = inode->i_mtime = CURRENT_TIME;
  83         inode->i_dirt = 1;
  84         error = notify_change(NOTIFY_SIZE, inode);
  85         iput(inode);
  86         return error;
  87 }
  88 
  89 int sys_ftruncate(unsigned int fd, unsigned int length)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         struct inode * inode;
  92         struct file * file;
  93 
  94         if (fd >= NR_OPEN || !(file = current->filp[fd]))
  95                 return -EBADF;
  96         if (!(inode = file->f_inode))
  97                 return -ENOENT;
  98         if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2))
  99                 return -EACCES;
 100         inode->i_size = length;
 101         if (inode->i_op && inode->i_op->truncate)
 102                 inode->i_op->truncate(inode);
 103         inode->i_atime = inode->i_mtime = CURRENT_TIME;
 104         inode->i_dirt = 1;
 105         return notify_change(NOTIFY_SIZE, inode);
 106 }
 107 
 108 /* If times==NULL, set access and modification to current time,
 109  * must be owner or have write permission.
 110  * Else, update from *times, must be owner or super user.
 111  */
 112 int sys_utime(char * filename, struct utimbuf * times)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114         struct inode * inode;
 115         long actime,modtime;
 116         int error;
 117 
 118         error = namei(filename,&inode);
 119         if (error)
 120                 return error;
 121         if (IS_RDONLY(inode)) {
 122                 iput(inode);
 123                 return -EROFS;
 124         }
 125         if (times) {
 126                 if ((current->euid != inode->i_uid) && !suser()) {
 127                         iput(inode);
 128                         return -EPERM;
 129                 }
 130                 actime = get_fs_long((unsigned long *) &times->actime);
 131                 modtime = get_fs_long((unsigned long *) &times->modtime);
 132         } else {
 133                 if ((current->euid != inode->i_uid) &&
 134                     !permission(inode,MAY_WRITE)) {
 135                         iput(inode);
 136                         return -EACCES;
 137                 }
 138                 actime = modtime = CURRENT_TIME;
 139         }
 140         inode->i_atime = actime;
 141         inode->i_mtime = modtime;
 142         inode->i_ctime = CURRENT_TIME;
 143         inode->i_dirt = 1;
 144         error = notify_change(NOTIFY_TIME, inode);
 145         iput(inode);
 146         return error;
 147 }
 148 
 149 /*
 150  * XXX should we use the real or effective uid?  BSD uses the real uid,
 151  * so as to make this call useful to setuid programs.
 152  */
 153 int sys_access(const char * filename,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 154 {
 155         struct inode * inode;
 156         int res, i_mode;
 157 
 158         mode &= 0007;
 159         res = namei(filename,&inode);
 160         if (res)
 161                 return res;
 162         i_mode = res = inode->i_mode & 0777;
 163         iput(inode);
 164         if (current->uid == inode->i_uid)
 165                 res >>= 6;
 166         else if (in_group_p(inode->i_gid))
 167                 res >>= 3;
 168         if ((res & 0007 & mode) == mode)
 169                 return 0;
 170         /*
 171          * XXX we are doing this test last because we really should be
 172          * swapping the effective with the real user id (temporarily),
 173          * and then calling suser() routine.  If we do call the
 174          * suser() routine, it needs to be called last. 
 175          */
 176         if ((!current->uid) &&
 177             (!(mode & 1) || (i_mode & 0111)))
 178                 return 0;
 179         return -EACCES;
 180 }
 181 
 182 int sys_chdir(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184         struct inode * inode;
 185         int error;
 186 
 187         error = namei(filename,&inode);
 188         if (error)
 189                 return error;
 190         if (!S_ISDIR(inode->i_mode)) {
 191                 iput(inode);
 192                 return -ENOTDIR;
 193         }
 194         if (!permission(inode,MAY_EXEC)) {
 195                 iput(inode);
 196                 return -EACCES;
 197         }
 198         iput(current->pwd);
 199         current->pwd = inode;
 200         return (0);
 201 }
 202 
 203 int sys_chroot(const char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 204 {
 205         struct inode * inode;
 206         int error;
 207 
 208         error = namei(filename,&inode);
 209         if (error)
 210                 return error;
 211         if (!S_ISDIR(inode->i_mode)) {
 212                 iput(inode);
 213                 return -ENOTDIR;
 214         }
 215         if (!suser()) {
 216                 iput(inode);
 217                 return -EPERM;
 218         }
 219         iput(current->root);
 220         current->root = inode;
 221         return (0);
 222 }
 223 
 224 int sys_fchmod(unsigned int fd, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226         struct inode * inode;
 227         struct file * file;
 228 
 229         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 230                 return -EBADF;
 231         if (!(inode = file->f_inode))
 232                 return -ENOENT;
 233         if ((current->euid != inode->i_uid) && !suser())
 234                 return -EPERM;
 235         if (IS_RDONLY(inode))
 236                 return -EROFS;
 237         inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
 238         if (!suser() && !in_group_p(inode->i_gid))
 239                 inode->i_mode &= ~S_ISGID;
 240         inode->i_ctime = CURRENT_TIME;
 241         inode->i_dirt = 1;
 242         return notify_change(NOTIFY_MODE, inode);
 243 }
 244 
 245 int sys_chmod(const char * filename, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247         struct inode * inode;
 248         int error;
 249 
 250         error = namei(filename,&inode);
 251         if (error)
 252                 return error;
 253         if ((current->euid != inode->i_uid) && !suser()) {
 254                 iput(inode);
 255                 return -EPERM;
 256         }
 257         if (IS_RDONLY(inode)) {
 258                 iput(inode);
 259                 return -EROFS;
 260         }
 261         inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
 262         if (!suser() && !in_group_p(inode->i_gid))
 263                 inode->i_mode &= ~S_ISGID;
 264         inode->i_ctime = CURRENT_TIME;
 265         inode->i_dirt = 1;
 266         error = notify_change(NOTIFY_MODE, inode);
 267         iput(inode);
 268         return error;
 269 }
 270 
 271 int sys_fchown(unsigned int fd, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 272 {
 273         struct inode * inode;
 274         struct file * file;
 275 
 276         if (fd >= NR_OPEN || !(file = current->filp[fd]))
 277                 return -EBADF;
 278         if (!(inode = file->f_inode))
 279                 return -ENOENT;
 280         if (IS_RDONLY(inode))
 281                 return -EROFS;
 282         if (user == (uid_t) -1)
 283                 user = inode->i_uid;
 284         if (group == (gid_t) -1)
 285                 group = inode->i_gid;
 286         if ((current->euid == inode->i_uid && user == inode->i_uid &&
 287              (in_group_p(group) || group == inode->i_gid)) ||
 288             suser()) {
 289                 inode->i_uid = user;
 290                 inode->i_gid = group;
 291                 inode->i_ctime = CURRENT_TIME;
 292                 inode->i_dirt = 1;
 293                 return notify_change(NOTIFY_UIDGID, inode);
 294         }
 295         return -EPERM;
 296 }
 297 
 298 int sys_chown(const char * filename, uid_t user, gid_t group)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300         struct inode * inode;
 301         int error;
 302 
 303         error = lnamei(filename,&inode);
 304         if (error)
 305                 return error;
 306         if (IS_RDONLY(inode)) {
 307                 iput(inode);
 308                 return -EROFS;
 309         }
 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                 error = notify_change(NOTIFY_UIDGID, inode);
 322                 iput(inode);
 323                 return error;
 324         }
 325         iput(inode);
 326         return -EPERM;
 327 }
 328 
 329 /*
 330  * Note that while the flag value (low two bits) for sys_open means:
 331  *      00 - read-only
 332  *      01 - write-only
 333  *      10 - read-write
 334  *      11 - special
 335  * it is changed into
 336  *      00 - no permissions needed
 337  *      01 - read-permission
 338  *      10 - write-permission
 339  *      11 - read-write
 340  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 341  * used by symlinks.
 342  */
 343 int sys_open(const char * filename,int flag,int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 344 {
 345         struct inode * inode;
 346         struct file * f;
 347         int i,fd;
 348 
 349         for(fd=0 ; fd<NR_OPEN ; fd++)
 350                 if (!current->filp[fd])
 351                         break;
 352         if (fd>=NR_OPEN)
 353                 return -EMFILE;
 354         FD_CLR(fd,&current->close_on_exec);
 355         f = get_empty_filp();
 356         if (!f)
 357                 return -ENFILE;
 358         current->filp[fd] = f;
 359         f->f_flags = flag;
 360         f->f_mode = (flag+1) & O_ACCMODE;
 361         if (f->f_mode)
 362                 flag++;
 363         if (flag & (O_TRUNC | O_CREAT))
 364                 flag |= 2;
 365         i = open_namei(filename,flag,mode,&inode,NULL);
 366         if (i) {
 367                 current->filp[fd]=NULL;
 368                 f->f_count--;
 369                 return i;
 370         }
 371         if (flag & O_TRUNC) {
 372                 inode->i_size = 0;
 373                 if (inode->i_op && inode->i_op->truncate)
 374                         inode->i_op->truncate(inode);
 375                 if ((i = notify_change(NOTIFY_SIZE, inode))) {
 376                         iput(inode);
 377                         current->filp[fd] = NULL;
 378                         f->f_count--;
 379                         return i;
 380                 }
 381         }
 382         if (!IS_RDONLY(inode)) {
 383                 inode->i_atime = CURRENT_TIME;
 384                 inode->i_dirt = 1;
 385         }
 386         f->f_inode = inode;
 387         f->f_pos = 0;
 388         f->f_reada = 0;
 389         f->f_op = NULL;
 390         if (inode->i_op)
 391                 f->f_op = inode->i_op->default_file_ops;
 392         if (f->f_op && f->f_op->open) {
 393                 i = f->f_op->open(inode,f);
 394                 if (i) {
 395                         iput(inode);
 396                         f->f_count--;
 397                         current->filp[fd]=NULL;
 398                         return i;
 399                 }
 400         }
 401         f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 402         return (fd);
 403 }
 404 
 405 int sys_creat(const char * pathname, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 406 {
 407         return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 408 }
 409 
 410 int close_fp(struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412         struct inode *inode;
 413 
 414         if (filp->f_count == 0) {
 415                 printk("Close: file count is 0\n");
 416                 return 0;
 417         }
 418         inode = filp->f_inode;
 419         if (inode && S_ISREG(inode->i_mode))
 420                 fcntl_remove_locks(current, filp);
 421         if (filp->f_count > 1) {
 422                 filp->f_count--;
 423                 return 0;
 424         }
 425         if (filp->f_op && filp->f_op->release)
 426                 filp->f_op->release(inode,filp);
 427         filp->f_count--;
 428         filp->f_inode = NULL;
 429         iput(inode);
 430         return 0;
 431 }
 432 
 433 int sys_close(unsigned int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 434 {       
 435         struct file * filp;
 436 
 437         if (fd >= NR_OPEN)
 438                 return -EINVAL;
 439         FD_CLR(fd, &current->close_on_exec);
 440         if (!(filp = current->filp[fd]))
 441                 return -EINVAL;
 442         current->filp[fd] = NULL;
 443         return (close_fp (filp));
 444 }
 445 
 446 /*
 447  * This routine simulates a hangup on the tty, to arrange that users
 448  * are given clean terminals at login time.
 449  */
 450 int sys_vhangup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 451 {
 452         struct tty_struct *tty;
 453 
 454         if (!suser())
 455                 return -EPERM;
 456         /* See if there is a controlling tty. */
 457         if (current->tty < 0)
 458                 return 0;
 459         tty = TTY_TABLE(MINOR(current->tty));
 460         tty_hangup(tty);
 461         return 0;
 462 }

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