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