linux-bk/fs/open.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/open.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#include <linux/string.h>
   8#include <linux/mm.h>
   9#include <linux/utime.h>
  10#include <linux/file.h>
  11#include <linux/smp_lock.h>
  12#include <linux/quotaops.h>
  13#include <linux/dnotify.h>
  14#include <linux/module.h>
  15#include <linux/slab.h>
  16#include <linux/tty.h>
  17#include <linux/iobuf.h>
  18#include <linux/namei.h>
  19#include <linux/backing-dev.h>
  20#include <linux/security.h>
  21
  22#include <asm/uaccess.h>
  23
  24#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
  25
  26int vfs_statfs(struct super_block *sb, struct statfs *buf)
  27{
  28        int retval = -ENODEV;
  29
  30        if (sb) {
  31                retval = -ENOSYS;
  32                if (sb->s_op && sb->s_op->statfs) {
  33                        memset(buf, 0, sizeof(struct statfs));
  34                        retval = security_ops->sb_statfs(sb);
  35                        if (retval)
  36                                return retval;
  37                        retval = sb->s_op->statfs(sb, buf);
  38                }
  39        }
  40        return retval;
  41}
  42
  43
  44asmlinkage long sys_statfs(const char * path, struct statfs * buf)
  45{
  46        struct nameidata nd;
  47        int error;
  48
  49        error = user_path_walk(path, &nd);
  50        if (!error) {
  51                struct statfs tmp;
  52                error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
  53                if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
  54                        error = -EFAULT;
  55                path_release(&nd);
  56        }
  57        return error;
  58}
  59
  60asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf)
  61{
  62        struct file * file;
  63        struct statfs tmp;
  64        int error;
  65
  66        error = -EBADF;
  67        file = fget(fd);
  68        if (!file)
  69                goto out;
  70        error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
  71        if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
  72                error = -EFAULT;
  73        fput(file);
  74out:
  75        return error;
  76}
  77
  78int do_truncate(struct dentry *dentry, loff_t length)
  79{
  80        int err;
  81        struct iattr newattrs;
  82
  83        /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
  84        if (length < 0)
  85                return -EINVAL;
  86
  87        newattrs.ia_size = length;
  88        newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
  89        down(&dentry->d_inode->i_sem);
  90        err = notify_change(dentry, &newattrs);
  91        up(&dentry->d_inode->i_sem);
  92        return err;
  93}
  94
  95static inline long do_sys_truncate(const char * path, loff_t length)
  96{
  97        struct nameidata nd;
  98        struct inode * inode;
  99        int error;
 100
 101        error = -EINVAL;
 102        if (length < 0) /* sorry, but loff_t says... */
 103                goto out;
 104
 105        error = user_path_walk(path, &nd);
 106        if (error)
 107                goto out;
 108        inode = nd.dentry->d_inode;
 109
 110        /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
 111        error = -EISDIR;
 112        if (S_ISDIR(inode->i_mode))
 113                goto dput_and_out;
 114
 115        error = -EINVAL;
 116        if (!S_ISREG(inode->i_mode))
 117                goto dput_and_out;
 118
 119        error = permission(inode,MAY_WRITE);
 120        if (error)
 121                goto dput_and_out;
 122
 123        error = -EROFS;
 124        if (IS_RDONLY(inode))
 125                goto dput_and_out;
 126
 127        error = -EPERM;
 128        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 129                goto dput_and_out;
 130
 131        /*
 132         * Make sure that there are no leases.
 133         */
 134        error = get_lease(inode, FMODE_WRITE);
 135        if (error)
 136                goto dput_and_out;
 137
 138        error = get_write_access(inode);
 139        if (error)
 140                goto dput_and_out;
 141
 142        error = locks_verify_truncate(inode, NULL, length);
 143        if (!error) {
 144                DQUOT_INIT(inode);
 145                error = do_truncate(nd.dentry, length);
 146        }
 147        put_write_access(inode);
 148
 149dput_and_out:
 150        path_release(&nd);
 151out:
 152        return error;
 153}
 154
 155asmlinkage long sys_truncate(const char * path, unsigned long length)
 156{
 157        /* on 32-bit boxen it will cut the range 2^31--2^32-1 off */
 158        return do_sys_truncate(path, (long)length);
 159}
 160
 161static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 162{
 163        struct inode * inode;
 164        struct dentry *dentry;
 165        struct file * file;
 166        int error;
 167
 168        error = -EINVAL;
 169        if (length < 0)
 170                goto out;
 171        error = -EBADF;
 172        file = fget(fd);
 173        if (!file)
 174                goto out;
 175
 176        /* explicitly opened as large or we are on 64-bit box */
 177        if (file->f_flags & O_LARGEFILE)
 178                small = 0;
 179
 180        dentry = file->f_dentry;
 181        inode = dentry->d_inode;
 182        error = -EINVAL;
 183        if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
 184                goto out_putf;
 185
 186        error = -EINVAL;
 187        /* Cannot ftruncate over 2^31 bytes without large file support */
 188        if (small && length > MAX_NON_LFS)
 189                goto out_putf;
 190
 191        error = -EPERM;
 192        if (IS_APPEND(inode))
 193                goto out_putf;
 194
 195        error = locks_verify_truncate(inode, file, length);
 196        if (!error)
 197                error = do_truncate(dentry, length);
 198out_putf:
 199        fput(file);
 200out:
 201        return error;
 202}
 203
 204asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
 205{
 206        return do_sys_ftruncate(fd, length, 1);
 207}
 208
 209/* LFS versions of truncate are only needed on 32 bit machines */
 210#if BITS_PER_LONG == 32
 211asmlinkage long sys_truncate64(const char * path, loff_t length)
 212{
 213        return do_sys_truncate(path, length);
 214}
 215
 216asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
 217{
 218        return do_sys_ftruncate(fd, length, 0);
 219}
 220#endif
 221
 222#if !(defined(__alpha__) || defined(__ia64__))
 223
 224/*
 225 * sys_utime() can be implemented in user-level using sys_utimes().
 226 * Is this for backwards compatibility?  If so, why not move it
 227 * into the appropriate arch directory (for those architectures that
 228 * need it).
 229 */
 230
 231/* If times==NULL, set access and modification to current time,
 232 * must be owner or have write permission.
 233 * Else, update from *times, must be owner or super user.
 234 */
 235asmlinkage long sys_utime(char * filename, struct utimbuf * times)
 236{
 237        int error;
 238        struct nameidata nd;
 239        struct inode * inode;
 240        struct iattr newattrs;
 241
 242        error = user_path_walk(filename, &nd);
 243        if (error)
 244                goto out;
 245        inode = nd.dentry->d_inode;
 246
 247        error = -EROFS;
 248        if (IS_RDONLY(inode))
 249                goto dput_and_out;
 250
 251        /* Don't worry, the checks are done in inode_change_ok() */
 252        newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 253        if (times) {
 254                error = get_user(newattrs.ia_atime, &times->actime);
 255                if (!error) 
 256                        error = get_user(newattrs.ia_mtime, &times->modtime);
 257                if (error)
 258                        goto dput_and_out;
 259
 260                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 261        } else {
 262                if (current->fsuid != inode->i_uid &&
 263                    (error = permission(inode,MAY_WRITE)) != 0)
 264                        goto dput_and_out;
 265        }
 266        down(&inode->i_sem);
 267        error = notify_change(nd.dentry, &newattrs);
 268        up(&inode->i_sem);
 269dput_and_out:
 270        path_release(&nd);
 271out:
 272        return error;
 273}
 274
 275#endif
 276
 277/* If times==NULL, set access and modification to current time,
 278 * must be owner or have write permission.
 279 * Else, update from *times, must be owner or super user.
 280 */
 281asmlinkage long sys_utimes(char * filename, struct timeval * utimes)
 282{
 283        int error;
 284        struct nameidata nd;
 285        struct inode * inode;
 286        struct iattr newattrs;
 287
 288        error = user_path_walk(filename, &nd);
 289
 290        if (error)
 291                goto out;
 292        inode = nd.dentry->d_inode;
 293
 294        error = -EROFS;
 295        if (IS_RDONLY(inode))
 296                goto dput_and_out;
 297
 298        /* Don't worry, the checks are done in inode_change_ok() */
 299        newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 300        if (utimes) {
 301                struct timeval times[2];
 302                error = -EFAULT;
 303                if (copy_from_user(&times, utimes, sizeof(times)))
 304                        goto dput_and_out;
 305                newattrs.ia_atime = times[0].tv_sec;
 306                newattrs.ia_mtime = times[1].tv_sec;
 307                newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 308        } else {
 309                if (current->fsuid != inode->i_uid &&
 310                    (error = permission(inode,MAY_WRITE)) != 0)
 311                        goto dput_and_out;
 312        }
 313        down(&inode->i_sem);
 314        error = notify_change(nd.dentry, &newattrs);
 315        up(&inode->i_sem);
 316dput_and_out:
 317        path_release(&nd);
 318out:
 319        return error;
 320}
 321
 322/*
 323 * access() needs to use the real uid/gid, not the effective uid/gid.
 324 * We do this by temporarily clearing all FS-related capabilities and
 325 * switching the fsuid/fsgid around to the real ones.
 326 */
 327asmlinkage long sys_access(const char * filename, int mode)
 328{
 329        struct nameidata nd;
 330        int old_fsuid, old_fsgid;
 331        kernel_cap_t old_cap;
 332        int res;
 333
 334        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
 335                return -EINVAL;
 336
 337        old_fsuid = current->fsuid;
 338        old_fsgid = current->fsgid;
 339        old_cap = current->cap_effective;
 340
 341        current->fsuid = current->uid;
 342        current->fsgid = current->gid;
 343
 344        /*
 345         * Clear the capabilities if we switch to a non-root user
 346         *
 347         * FIXME: There is a race here against sys_capset.  The
 348         * capabilities can change yet we will restore the old
 349         * value below.  We should hold task_capabilities_lock,
 350         * but we cannot because user_path_walk can sleep.
 351         */
 352        if (current->uid)
 353                cap_clear(current->cap_effective);
 354        else
 355                current->cap_effective = current->cap_permitted;
 356
 357        res = user_path_walk(filename, &nd);
 358        if (!res) {
 359                res = permission(nd.dentry->d_inode, mode);
 360                /* SuS v2 requires we report a read only fs too */
 361                if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
 362                   && !special_file(nd.dentry->d_inode->i_mode))
 363                        res = -EROFS;
 364                path_release(&nd);
 365        }
 366
 367        current->fsuid = old_fsuid;
 368        current->fsgid = old_fsgid;
 369        current->cap_effective = old_cap;
 370
 371        return res;
 372}
 373
 374asmlinkage long sys_chdir(const char * filename)
 375{
 376        struct nameidata nd;
 377        int error;
 378
 379        error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
 380        if (error)
 381                goto out;
 382
 383        error = permission(nd.dentry->d_inode,MAY_EXEC);
 384        if (error)
 385                goto dput_and_out;
 386
 387        set_fs_pwd(current->fs, nd.mnt, nd.dentry);
 388
 389dput_and_out:
 390        path_release(&nd);
 391out:
 392        return error;
 393}
 394
 395asmlinkage long sys_fchdir(unsigned int fd)
 396{
 397        struct file *file;
 398        struct dentry *dentry;
 399        struct inode *inode;
 400        struct vfsmount *mnt;
 401        int error;
 402
 403        error = -EBADF;
 404        file = fget(fd);
 405        if (!file)
 406                goto out;
 407
 408        dentry = file->f_dentry;
 409        mnt = file->f_vfsmnt;
 410        inode = dentry->d_inode;
 411
 412        error = -ENOTDIR;
 413        if (!S_ISDIR(inode->i_mode))
 414                goto out_putf;
 415
 416        error = permission(inode, MAY_EXEC);
 417        if (!error)
 418                set_fs_pwd(current->fs, mnt, dentry);
 419out_putf:
 420        fput(file);
 421out:
 422        return error;
 423}
 424
 425asmlinkage long sys_chroot(const char * filename)
 426{
 427        struct nameidata nd;
 428        int error;
 429
 430        error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
 431        if (error)
 432                goto out;
 433
 434        error = permission(nd.dentry->d_inode,MAY_EXEC);
 435        if (error)
 436                goto dput_and_out;
 437
 438        error = -EPERM;
 439        if (!capable(CAP_SYS_CHROOT))
 440                goto dput_and_out;
 441
 442        set_fs_root(current->fs, nd.mnt, nd.dentry);
 443        set_fs_altroot();
 444        error = 0;
 445dput_and_out:
 446        path_release(&nd);
 447out:
 448        return error;
 449}
 450
 451asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
 452{
 453        struct inode * inode;
 454        struct dentry * dentry;
 455        struct file * file;
 456        int err = -EBADF;
 457        struct iattr newattrs;
 458
 459        file = fget(fd);
 460        if (!file)
 461                goto out;
 462
 463        dentry = file->f_dentry;
 464        inode = dentry->d_inode;
 465
 466        err = -EROFS;
 467        if (IS_RDONLY(inode))
 468                goto out_putf;
 469        err = -EPERM;
 470        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 471                goto out_putf;
 472        down(&inode->i_sem);
 473        if (mode == (mode_t) -1)
 474                mode = inode->i_mode;
 475        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 476        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 477        err = notify_change(dentry, &newattrs);
 478        up(&inode->i_sem);
 479
 480out_putf:
 481        fput(file);
 482out:
 483        return err;
 484}
 485
 486asmlinkage long sys_chmod(const char * filename, mode_t mode)
 487{
 488        struct nameidata nd;
 489        struct inode * inode;
 490        int error;
 491        struct iattr newattrs;
 492
 493        error = user_path_walk(filename, &nd);
 494        if (error)
 495                goto out;
 496        inode = nd.dentry->d_inode;
 497
 498        error = -EROFS;
 499        if (IS_RDONLY(inode))
 500                goto dput_and_out;
 501
 502        error = -EPERM;
 503        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 504                goto dput_and_out;
 505
 506        down(&inode->i_sem);
 507        if (mode == (mode_t) -1)
 508                mode = inode->i_mode;
 509        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 510        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 511        error = notify_change(nd.dentry, &newattrs);
 512        up(&inode->i_sem);
 513
 514dput_and_out:
 515        path_release(&nd);
 516out:
 517        return error;
 518}
 519
 520static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
 521{
 522        struct inode * inode;
 523        int error;
 524        struct iattr newattrs;
 525
 526        error = -ENOENT;
 527        if (!(inode = dentry->d_inode)) {
 528                printk(KERN_ERR "chown_common: NULL inode\n");
 529                goto out;
 530        }
 531        error = -EROFS;
 532        if (IS_RDONLY(inode))
 533                goto out;
 534        error = -EPERM;
 535        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 536                goto out;
 537        newattrs.ia_valid =  ATTR_CTIME;
 538        if (user != (uid_t) -1) {
 539                newattrs.ia_valid |= ATTR_UID;
 540                newattrs.ia_uid = user;
 541        }
 542        if (group != (gid_t) -1) {
 543                newattrs.ia_valid |= ATTR_GID;
 544                newattrs.ia_gid = group;
 545        }
 546        if (!S_ISDIR(inode->i_mode))
 547                newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
 548        down(&inode->i_sem);
 549        error = notify_change(dentry, &newattrs);
 550        up(&inode->i_sem);
 551out:
 552        return error;
 553}
 554
 555asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group)
 556{
 557        struct nameidata nd;
 558        int error;
 559
 560        error = user_path_walk(filename, &nd);
 561        if (!error) {
 562                error = chown_common(nd.dentry, user, group);
 563                path_release(&nd);
 564        }
 565        return error;
 566}
 567
 568asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group)
 569{
 570        struct nameidata nd;
 571        int error;
 572
 573        error = user_path_walk_link(filename, &nd);
 574        if (!error) {
 575                error = chown_common(nd.dentry, user, group);
 576                path_release(&nd);
 577        }
 578        return error;
 579}
 580
 581
 582asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
 583{
 584        struct file * file;
 585        int error = -EBADF;
 586
 587        file = fget(fd);
 588        if (file) {
 589                error = chown_common(file->f_dentry, user, group);
 590                fput(file);
 591        }
 592        return error;
 593}
 594
 595/*
 596 * Note that while the flag value (low two bits) for sys_open means:
 597 *      00 - read-only
 598 *      01 - write-only
 599 *      10 - read-write
 600 *      11 - special
 601 * it is changed into
 602 *      00 - no permissions needed
 603 *      01 - read-permission
 604 *      10 - write-permission
 605 *      11 - read-write
 606 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
 607 * used by symlinks.
 608 */
 609struct file *filp_open(const char * filename, int flags, int mode)
 610{
 611        int namei_flags, error;
 612        struct nameidata nd;
 613
 614        namei_flags = flags;
 615        if ((namei_flags+1) & O_ACCMODE)
 616                namei_flags++;
 617        if (namei_flags & O_TRUNC)
 618                namei_flags |= 2;
 619
 620        error = open_namei(filename, namei_flags, mode, &nd);
 621        if (!error)
 622                return dentry_open(nd.dentry, nd.mnt, flags);
 623
 624        return ERR_PTR(error);
 625}
 626
 627struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
 628{
 629        struct file * f;
 630        struct inode *inode;
 631        static LIST_HEAD(kill_list);
 632        int error;
 633
 634        error = -ENFILE;
 635        f = get_empty_filp();
 636        if (!f)
 637                goto cleanup_dentry;
 638        f->f_flags = flags;
 639        f->f_mode = (flags+1) & O_ACCMODE;
 640        inode = dentry->d_inode;
 641        if (f->f_mode & FMODE_WRITE) {
 642                error = get_write_access(inode);
 643                if (error)
 644                        goto cleanup_file;
 645        }
 646
 647        f->f_ra.ra_pages = inode->i_mapping->backing_dev_info->ra_pages;
 648        f->f_dentry = dentry;
 649        f->f_vfsmnt = mnt;
 650        f->f_pos = 0;
 651        f->f_op = fops_get(inode->i_fop);
 652        file_move(f, &inode->i_sb->s_files);
 653
 654        if (f->f_op && f->f_op->open) {
 655                error = f->f_op->open(inode,f);
 656                if (error)
 657                        goto cleanup_all;
 658        }
 659        f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 660
 661        /* NB: we're sure to have correct a_ops only after f_op->open */
 662        if (f->f_flags & O_DIRECT) {
 663                if (!inode->i_mapping || !inode->i_mapping->a_ops ||
 664                        !inode->i_mapping->a_ops->direct_IO) {
 665                                error = -EINVAL;
 666                                goto cleanup_all;
 667                }
 668        }
 669
 670        return f;
 671
 672cleanup_all:
 673        fops_put(f->f_op);
 674        if (f->f_mode & FMODE_WRITE)
 675                put_write_access(inode);
 676        file_move(f, &kill_list); /* out of the way.. */
 677        f->f_dentry = NULL;
 678        f->f_vfsmnt = NULL;
 679cleanup_file:
 680        put_filp(f);
 681cleanup_dentry:
 682        dput(dentry);
 683        mntput(mnt);
 684        return ERR_PTR(error);
 685}
 686
 687/*
 688 * Find an empty file descriptor entry, and mark it busy.
 689 */
 690int get_unused_fd(void)
 691{
 692        struct files_struct * files = current->files;
 693        int fd, error;
 694
 695        error = -EMFILE;
 696        write_lock(&files->file_lock);
 697
 698repeat:
 699        fd = find_next_zero_bit(files->open_fds->fds_bits, 
 700                                files->max_fdset, 
 701                                files->next_fd);
 702
 703        /*
 704         * N.B. For clone tasks sharing a files structure, this test
 705         * will limit the total number of files that can be opened.
 706         */
 707        if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
 708                goto out;
 709
 710        /* Do we need to expand the fdset array? */
 711        if (fd >= files->max_fdset) {
 712                error = expand_fdset(files, fd);
 713                if (!error) {
 714                        error = -EMFILE;
 715                        goto repeat;
 716                }
 717                goto out;
 718        }
 719        
 720        /* 
 721         * Check whether we need to expand the fd array.
 722         */
 723        if (fd >= files->max_fds) {
 724                error = expand_fd_array(files, fd);
 725                if (!error) {
 726                        error = -EMFILE;
 727                        goto repeat;
 728                }
 729                goto out;
 730        }
 731
 732        FD_SET(fd, files->open_fds);
 733        FD_CLR(fd, files->close_on_exec);
 734        files->next_fd = fd + 1;
 735#if 1
 736        /* Sanity check */
 737        if (files->fd[fd] != NULL) {
 738                printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
 739                files->fd[fd] = NULL;
 740        }
 741#endif
 742        error = fd;
 743
 744out:
 745        write_unlock(&files->file_lock);
 746        return error;
 747}
 748
 749static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
 750{
 751        __FD_CLR(fd, files->open_fds);
 752        if (fd < files->next_fd)
 753                files->next_fd = fd;
 754}
 755
 756void put_unused_fd(unsigned int fd)
 757{
 758        struct files_struct *files = current->files;
 759        write_lock(&files->file_lock);
 760        __put_unused_fd(files, fd);
 761        write_unlock(&files->file_lock);
 762}
 763
 764/*
 765 * Install a file pointer in the fd array.  
 766 *
 767 * The VFS is full of places where we drop the files lock between
 768 * setting the open_fds bitmap and installing the file in the file
 769 * array.  At any such point, we are vulnerable to a dup2() race
 770 * installing a file in the array before us.  We need to detect this and
 771 * fput() the struct file we are about to overwrite in this case.
 772 *
 773 * It should never happen - if we allow dup2() do it, _really_ bad things
 774 * will follow.
 775 */
 776
 777void fd_install(unsigned int fd, struct file * file)
 778{
 779        struct files_struct *files = current->files;
 780        write_lock(&files->file_lock);
 781        if (unlikely(files->fd[fd] != NULL))
 782                BUG();
 783        files->fd[fd] = file;
 784        write_unlock(&files->file_lock);
 785}
 786
 787asmlinkage long sys_open(const char * filename, int flags, int mode)
 788{
 789        char * tmp;
 790        int fd, error;
 791
 792#if BITS_PER_LONG != 32
 793        flags |= O_LARGEFILE;
 794#endif
 795        tmp = getname(filename);
 796        fd = PTR_ERR(tmp);
 797        if (!IS_ERR(tmp)) {
 798                fd = get_unused_fd();
 799                if (fd >= 0) {
 800                        struct file *f = filp_open(tmp, flags, mode);
 801                        error = PTR_ERR(f);
 802                        if (IS_ERR(f))
 803                                goto out_error;
 804                        fd_install(fd, f);
 805                }
 806out:
 807                putname(tmp);
 808        }
 809        return fd;
 810
 811out_error:
 812        put_unused_fd(fd);
 813        fd = error;
 814        goto out;
 815}
 816
 817#ifndef __alpha__
 818
 819/*
 820 * For backward compatibility?  Maybe this should be moved
 821 * into arch/i386 instead?
 822 */
 823asmlinkage long sys_creat(const char * pathname, int mode)
 824{
 825        return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 826}
 827
 828#endif
 829
 830/*
 831 * "id" is the POSIX thread ID. We use the
 832 * files pointer for this..
 833 */
 834int filp_close(struct file *filp, fl_owner_t id)
 835{
 836        int retval;
 837
 838        if (!file_count(filp)) {
 839                printk(KERN_ERR "VFS: Close: file count is 0\n");
 840                return 0;
 841        }
 842        retval = 0;
 843        if (filp->f_op && filp->f_op->flush) {
 844                lock_kernel();
 845                retval = filp->f_op->flush(filp);
 846                unlock_kernel();
 847        }
 848        dnotify_flush(filp, id);
 849        locks_remove_posix(filp, id);
 850        fput(filp);
 851        return retval;
 852}
 853
 854/*
 855 * Careful here! We test whether the file pointer is NULL before
 856 * releasing the fd. This ensures that one clone task can't release
 857 * an fd while another clone is opening it.
 858 */
 859asmlinkage long sys_close(unsigned int fd)
 860{
 861        struct file * filp;
 862        struct files_struct *files = current->files;
 863
 864        write_lock(&files->file_lock);
 865        if (fd >= files->max_fds)
 866                goto out_unlock;
 867        filp = files->fd[fd];
 868        if (!filp)
 869                goto out_unlock;
 870        files->fd[fd] = NULL;
 871        FD_CLR(fd, files->close_on_exec);
 872        __put_unused_fd(files, fd);
 873        write_unlock(&files->file_lock);
 874        return filp_close(filp, files);
 875
 876out_unlock:
 877        write_unlock(&files->file_lock);
 878        return -EBADF;
 879}
 880
 881/*
 882 * This routine simulates a hangup on the tty, to arrange that users
 883 * are given clean terminals at login time.
 884 */
 885asmlinkage long sys_vhangup(void)
 886{
 887        if (capable(CAP_SYS_TTY_CONFIG)) {
 888                tty_vhangup(current->tty);
 889                return 0;
 890        }
 891        return -EPERM;
 892}
 893
 894/*
 895 * Called when an inode is about to be open.
 896 * We use this to disallow opening RW large files on 32bit systems if
 897 * the caller didn't specify O_LARGEFILE.  On 64bit systems we force
 898 * on this flag in sys_open.
 899 */
 900int generic_file_open(struct inode * inode, struct file * filp)
 901{
 902        if (!(filp->f_flags & O_LARGEFILE) && inode->i_size > MAX_NON_LFS)
 903                return -EFBIG;
 904        return 0;
 905}
 906
 907EXPORT_SYMBOL(generic_file_open);
 908
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.