darwin-xnu/bsd/vfs/vfs_vnops.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
  23/*
  24 * Copyright (c) 1982, 1986, 1989, 1993
  25 *      The Regents of the University of California.  All rights reserved.
  26 * (c) UNIX System Laboratories, Inc.
  27 * All or some portions of this file are derived from material licensed
  28 * to the University of California by American Telephone and Telegraph
  29 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  30 * the permission of UNIX System Laboratories, Inc.
  31 *
  32 * Redistribution and use in source and binary forms, with or without
  33 * modification, are permitted provided that the following conditions
  34 * are met:
  35 * 1. Redistributions of source code must retain the above copyright
  36 *    notice, this list of conditions and the following disclaimer.
  37 * 2. Redistributions in binary form must reproduce the above copyright
  38 *    notice, this list of conditions and the following disclaimer in the
  39 *    documentation and/or other materials provided with the distribution.
  40 * 3. All advertising materials mentioning features or use of this software
  41 *    must display the following acknowledgement:
  42 *      This product includes software developed by the University of
  43 *      California, Berkeley and its contributors.
  44 * 4. Neither the name of the University nor the names of its contributors
  45 *    may be used to endorse or promote products derived from this software
  46 *    without specific prior written permission.
  47 *
  48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  58 * SUCH DAMAGE.
  59 *
  60 *      @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95
  61 *
  62 */
  63
  64#include <sys/param.h>
  65#include <sys/types.h>
  66#include <sys/systm.h>
  67#include <sys/kernel.h>
  68#include <sys/file_internal.h>
  69#include <sys/stat.h>
  70#include <sys/proc_internal.h>
  71#include <sys/kauth.h>
  72#include <sys/mount_internal.h>
  73#include <sys/namei.h>
  74#include <sys/vnode_internal.h>
  75#include <sys/ioctl.h>
  76#include <sys/tty.h>
  77#include <sys/ubc.h>
  78#include <sys/conf.h>
  79#include <sys/disk.h>
  80#include <sys/fsevents.h>
  81#include <sys/kdebug.h>
  82#include <sys/xattr.h>
  83#include <sys/ubc_internal.h>
  84#include <sys/uio_internal.h>
  85
  86#include <vm/vm_kern.h>
  87#include <vm/vm_map.h>
  88
  89#include <miscfs/specfs/specdev.h>
  90
  91
  92
  93static int vn_closefile(struct fileglob *fp, struct proc *p);
  94static int vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, struct proc *p);
  95static int vn_read(struct fileproc *fp, struct uio *uio,
  96                kauth_cred_t cred, int flags, struct proc *p);
  97static int vn_write(struct fileproc *fp, struct uio *uio,
  98                kauth_cred_t cred, int flags, struct proc *p);
  99static int vn_select( struct fileproc *fp, int which, void * wql, struct proc *p);
 100static int vn_kqfilt_add(struct fileproc *fp, struct knote *kn, struct proc *p);
 101#if 0
 102static int vn_kqfilt_remove(struct vnode *vp, uintptr_t ident, struct proc *p);
 103#endif
 104
 105struct  fileops vnops =
 106        { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile, vn_kqfilt_add, 0 };
 107
 108/*
 109 * Common code for vnode open operations.
 110 * Check permissions, and call the VNOP_OPEN or VNOP_CREATE routine.
 111 *
 112 * XXX the profusion of interfaces here is probably a bad thing.
 113 */
 114int
 115vn_open(struct nameidata *ndp, int fmode, int cmode)
 116{
 117        return(vn_open_modflags(ndp, &fmode, cmode));
 118}
 119
 120int
 121vn_open_modflags(struct nameidata *ndp, int *fmodep, int cmode)
 122{
 123        struct vnode_attr va;
 124
 125        VATTR_INIT(&va);
 126        VATTR_SET(&va, va_mode, cmode);
 127        
 128        return(vn_open_auth(ndp, fmodep, &va));
 129}
 130
 131int
 132vn_open_auth(struct nameidata *ndp, int *fmodep, struct vnode_attr *vap)
 133{
 134        struct vnode *vp;
 135        struct vnode *dvp;
 136        vfs_context_t ctx = ndp->ni_cnd.cn_context;
 137        int error;
 138        int fmode;
 139        kauth_action_t action;
 140
 141again:
 142        vp = NULL;
 143        dvp = NULL;
 144        fmode = *fmodep;
 145        if (fmode & O_CREAT) {
 146                ndp->ni_cnd.cn_nameiop = CREATE;
 147                ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | AUDITVNPATH1;
 148
 149                if ((fmode & O_EXCL) == 0)
 150                        ndp->ni_cnd.cn_flags |= FOLLOW;
 151                if ( (error = namei(ndp)) )
 152                        goto out;
 153                dvp = ndp->ni_dvp;
 154                vp = ndp->ni_vp;
 155
 156                /* not found, create */
 157                if (vp == NULL) {
 158                        /* must have attributes for a new file */
 159                        if (vap == NULL) {
 160                                error = EINVAL;
 161                                goto badcreate;
 162                        }
 163
 164                        /* authorize before creating */
 165                        if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
 166                                goto badcreate;
 167
 168                        VATTR_SET(vap, va_type, VREG);
 169                        if (fmode & O_EXCL)
 170                                vap->va_vaflags |= VA_EXCLUSIVE;
 171
 172                        if ((error = vn_create(dvp, &ndp->ni_vp, &ndp->ni_cnd, vap, 0, ctx)) != 0)
 173                                goto badcreate;
 174                        
 175                        vp = ndp->ni_vp;
 176
 177                        if (vp) {
 178                                int     update_flags = 0;
 179
 180                                // Make sure the name & parent pointers are hooked up
 181                                if (vp->v_name == NULL)
 182                                        update_flags |= VNODE_UPDATE_NAME;
 183                                if (vp->v_parent == NULLVP)
 184                                        update_flags |= VNODE_UPDATE_PARENT;
 185
 186                                if (update_flags)
 187                                        vnode_update_identity(vp, dvp, ndp->ni_cnd.cn_nameptr, ndp->ni_cnd.cn_namelen, ndp->ni_cnd.cn_hash, update_flags);
 188
 189                                if (need_fsevent(FSE_CREATE_FILE, vp)) {
 190                                        add_fsevent(FSE_CREATE_FILE, ctx,
 191                                                    FSE_ARG_VNODE, vp,
 192                                                    FSE_ARG_DONE);
 193                                }
 194                        }
 195                        /*
 196                         * nameidone has to happen before we vnode_put(dvp)
 197                         * and clear the ni_dvp field, since it may need
 198                         * to release the fs_nodelock on the dvp
 199                         */
 200badcreate:
 201                        nameidone(ndp);
 202                        ndp->ni_dvp = NULL;
 203                        vnode_put(dvp);
 204
 205                        if (error) {
 206                                /*
 207                                 * Check for a creation race.
 208                                 */
 209                                if ((error == EEXIST) && !(fmode & O_EXCL)) {
 210                                        goto again;
 211                                }
 212                                goto bad;
 213                        }
 214                        fmode &= ~O_TRUNC;
 215                } else {
 216                        nameidone(ndp);
 217                        ndp->ni_dvp = NULL;
 218                        vnode_put(dvp);
 219
 220                        if (fmode & O_EXCL) {
 221                                error = EEXIST;
 222                                goto bad;
 223                        }
 224                        fmode &= ~O_CREAT;
 225                }
 226        } else {
 227                ndp->ni_cnd.cn_nameiop = LOOKUP;
 228                ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | AUDITVNPATH1;
 229                if ( (error = namei(ndp)) )
 230                        goto out;
 231                vp = ndp->ni_vp;
 232                nameidone(ndp);
 233                ndp->ni_dvp = NULL;
 234        }
 235        if (vp->v_type == VSOCK && vp->v_tag != VT_FDESC) {
 236                error = EOPNOTSUPP;     /* Operation not supported on socket */
 237                goto bad;
 238        }
 239
 240#if DIAGNOSTIC
 241        if (UBCINFOMISSING(vp))
 242                panic("vn_open: ubc_info_init");
 243#endif /* DIAGNOSTIC */
 244
 245        /* authorize open of an existing file */
 246        if ((fmode & O_CREAT) == 0) {
 247
 248                /* disallow write operations on directories */
 249                if (vnode_isdir(vp) && (fmode & (FWRITE | O_TRUNC))) {
 250                        error = EISDIR;
 251                        goto bad;
 252                }
 253
 254                /* compute action to be authorized */
 255                action = 0;
 256                if (fmode & FREAD)
 257                        action |= KAUTH_VNODE_READ_DATA;
 258                if (fmode & (FWRITE | O_TRUNC))
 259                        action |= KAUTH_VNODE_WRITE_DATA;
 260                if ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)
 261                        goto bad;
 262                
 263        }
 264
 265        if ( (error = VNOP_OPEN(vp, fmode, ctx)) ) {
 266                goto bad;
 267        }
 268        if ( (error = vnode_ref_ext(vp, fmode)) )
 269                goto bad;
 270
 271        /* call out to allow 3rd party notification of open. 
 272         * Ignore result of kauth_authorize_fileop call.
 273         */
 274        kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN, 
 275                                                   (uintptr_t)vp, 0);
 276
 277        *fmodep = fmode;
 278        return (0);
 279bad:
 280        ndp->ni_vp = NULL;
 281        if (vp) {
 282                vnode_put(vp);
 283                /*
 284                 * Check for a race against unlink.  We had a vnode
 285                 * but according to vnode_authorize or VNOP_OPEN it
 286                 * no longer exists.
 287                 */
 288                if ((error == ENOENT) && (*fmodep & O_CREAT)) {
 289                        goto again;
 290                }
 291        }
 292out:
 293        return (error);
 294}
 295
 296/*
 297 * Authorize an action against a vnode.  This has been the canonical way to
 298 * ensure that the credential/process/etc. referenced by a vfs_context
 299 * is granted the rights called out in 'mode' against the vnode 'vp'.
 300 *
 301 * Unfortunately, the use of VREAD/VWRITE/VEXEC makes it very difficult
 302 * to add support for more rights.  As such, this interface will be deprecated
 303 * and callers will use vnode_authorize instead.
 304 */
 305#warning vn_access is deprecated
 306int
 307vn_access(vnode_t vp, int mode, vfs_context_t context)
 308{
 309        kauth_action_t  action;
 310  
 311        action = 0;
 312        if (mode & VREAD)
 313                action |= KAUTH_VNODE_READ_DATA;
 314        if (mode & VWRITE)
 315                action |= KAUTH_VNODE_WRITE_DATA;
 316        if (mode & VEXEC)
 317                action |= KAUTH_VNODE_EXECUTE;
 318  
 319        return(vnode_authorize(vp, NULL, action, context));
 320}
 321
 322/*
 323 * Vnode close call
 324 */
 325int
 326vn_close(struct vnode *vp, int flags, kauth_cred_t cred, struct proc *p)
 327{
 328        struct vfs_context context;
 329        int error;
 330
 331        context.vc_proc = p;
 332        context.vc_ucred = cred;
 333
 334        if (flags & FWASWRITTEN) {
 335                if (need_fsevent(FSE_CONTENT_MODIFIED, vp)) {
 336                        add_fsevent(FSE_CONTENT_MODIFIED, &context,
 337                                    FSE_ARG_VNODE, vp,
 338                                    FSE_ARG_DONE);
 339                }
 340        }
 341
 342        error = VNOP_CLOSE(vp, flags, &context);
 343        (void)vnode_rele_ext(vp, flags, 0);
 344
 345        return (error);
 346}
 347
 348static int
 349vn_read_swapfile(
 350        struct vnode    *vp,
 351        uio_t           uio)
 352{
 353        static char *swap_read_zero_page = NULL;
 354        int     error;
 355        off_t   swap_count, this_count;
 356        off_t   file_end, read_end;
 357        off_t   prev_resid;
 358
 359        /*
 360         * Reading from a swap file will get you all zeroes.
 361         */
 362        error = 0;
 363        swap_count = uio_resid(uio);
 364
 365        file_end = ubc_getsize(vp);
 366        read_end = uio->uio_offset + uio_resid(uio);
 367        if (uio->uio_offset >= file_end) {
 368                /* uio starts after end of file: nothing to read */
 369                swap_count = 0;
 370        } else if (read_end > file_end) {
 371                /* uio extends beyond end of file: stop before that */
 372                swap_count -= (read_end - file_end);
 373        }
 374
 375        while (swap_count > 0) {
 376                if (swap_read_zero_page == NULL) {
 377                        char *my_zero_page;
 378                        int funnel_state;
 379
 380                        /*
 381                         * Take kernel funnel so that only one thread
 382                         * sets up "swap_read_zero_page".
 383                         */
 384                        funnel_state = thread_funnel_set(kernel_flock, TRUE);
 385
 386                        if (swap_read_zero_page == NULL) {
 387                                MALLOC(my_zero_page, char *, PAGE_SIZE,
 388                                       M_TEMP, M_WAITOK);
 389                                memset(my_zero_page, '?', PAGE_SIZE);
 390                                /*
 391                                 * Adding a newline character here
 392                                 * and there prevents "less(1)", for
 393                                 * example, from getting too confused
 394                                 * about a file with one really really
 395                                 * long line.
 396                                 */
 397                                my_zero_page[PAGE_SIZE-1] = '\n';
 398                                if (swap_read_zero_page == NULL) {
 399                                        swap_read_zero_page = my_zero_page;
 400                                } else {
 401                                        FREE(my_zero_page, M_TEMP);
 402                                }
 403                        } else {
 404                                /*
 405                                 * Someone else raced us here and won;
 406                                 * just use their page.
 407                                 */
 408                        }
 409                        thread_funnel_set(kernel_flock, funnel_state);
 410                }
 411
 412                this_count = swap_count;
 413                if (this_count > PAGE_SIZE) {
 414                        this_count = PAGE_SIZE;
 415                }
 416
 417                prev_resid = uio_resid(uio);
 418                error = uiomove((caddr_t) swap_read_zero_page,
 419                                this_count,
 420                                uio);
 421                if (error) {
 422                        break;
 423                }
 424                swap_count -= (prev_resid - uio_resid(uio));
 425        }
 426
 427        return error;
 428}
 429/*
 430 * Package up an I/O request on a vnode into a uio and do it.
 431 */
 432int
 433vn_rdwr(
 434        enum uio_rw rw,
 435        struct vnode *vp,
 436        caddr_t base,
 437        int len,
 438        off_t offset,
 439        enum uio_seg segflg,
 440        int ioflg,
 441        kauth_cred_t cred,
 442        int *aresid,
 443        struct proc *p)
 444{
 445        return vn_rdwr_64(rw,
 446                        vp,
 447                        (uint64_t)(uintptr_t)base,
 448                        (int64_t)len,
 449                        offset,
 450                        segflg,
 451                        ioflg,
 452                        cred,
 453                        aresid,
 454                        p);
 455}
 456
 457
 458int
 459vn_rdwr_64(
 460        enum uio_rw rw,
 461        struct vnode *vp,
 462        uint64_t base,
 463        int64_t len,
 464        off_t offset,
 465        enum uio_seg segflg,
 466        int ioflg,
 467        kauth_cred_t cred,
 468        int *aresid,
 469        struct proc *p)
 470{
 471        uio_t auio;
 472        int spacetype;
 473        struct vfs_context context;
 474        int error=0;
 475        char uio_buf[ UIO_SIZEOF(1) ];
 476
 477        context.vc_proc = p;
 478        context.vc_ucred = cred;
 479
 480        if (UIO_SEG_IS_USER_SPACE(segflg)) {
 481                spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
 482        }
 483        else {
 484                spacetype = UIO_SYSSPACE;
 485        }
 486        auio = uio_createwithbuffer(1, offset, spacetype, rw, 
 487                                                                  &uio_buf[0], sizeof(uio_buf));
 488        uio_addiov(auio, base, len);
 489
 490        if (rw == UIO_READ) {
 491                if (vp->v_flag & VSWAP) {
 492                        error = vn_read_swapfile(vp, auio);
 493                } else {
 494                        error = VNOP_READ(vp, auio, ioflg, &context);
 495                }
 496        } else {
 497                error = VNOP_WRITE(vp, auio, ioflg, &context);
 498        }
 499
 500        if (aresid)
 501                // LP64todo - fix this
 502                *aresid = uio_resid(auio);
 503        else
 504                if (uio_resid(auio) && error == 0)
 505                        error = EIO;
 506        return (error);
 507}
 508
 509/*
 510 * File table vnode read routine.
 511 */
 512static int
 513vn_read(struct fileproc *fp, struct uio *uio, kauth_cred_t cred,
 514        int flags, struct proc *p)
 515{
 516        struct vnode *vp;
 517        int error, ioflag;
 518        off_t count;
 519        struct vfs_context context;
 520
 521        context.vc_proc = p;
 522        context.vc_ucred = cred;
 523
 524        vp = (struct vnode *)fp->f_fglob->fg_data;
 525        if ( (error = vnode_getwithref(vp)) ) {
 526                return(error);
 527        }
 528        ioflag = 0;
 529        if (fp->f_fglob->fg_flag & FNONBLOCK)
 530                ioflag |= IO_NDELAY;
 531
 532        if ((flags & FOF_OFFSET) == 0)
 533                uio->uio_offset = fp->f_fglob->fg_offset;
 534        count = uio_resid(uio);
 535
 536        if (vp->v_flag & VSWAP) {
 537                /* special case for swap files */
 538                error = vn_read_swapfile(vp, uio);
 539        } else {
 540                error = VNOP_READ(vp, uio, ioflag, &context);
 541        }
 542        if ((flags & FOF_OFFSET) == 0)
 543                fp->f_fglob->fg_offset += count - uio_resid(uio);
 544
 545        (void)vnode_put(vp);
 546        return (error);
 547}
 548
 549
 550/*
 551 * File table vnode write routine.
 552 */
 553static int
 554vn_write(struct fileproc *fp, struct uio *uio, kauth_cred_t cred,
 555        int flags, struct proc *p)
 556{
 557        struct vnode *vp;
 558        int error, ioflag;
 559        off_t count;
 560        struct vfs_context context;
 561
 562        context.vc_proc = p;
 563        context.vc_ucred = cred;
 564        count = 0;
 565        vp = (struct vnode *)fp->f_fglob->fg_data;
 566        if ( (error = vnode_getwithref(vp)) ) {
 567                return(error);
 568        }
 569        ioflag = IO_UNIT;
 570        if (vp->v_type == VREG && (fp->f_fglob->fg_flag & O_APPEND))
 571                ioflag |= IO_APPEND;
 572        if (fp->f_fglob->fg_flag & FNONBLOCK)
 573                ioflag |= IO_NDELAY;
 574        if ((fp->f_fglob->fg_flag & O_FSYNC) ||
 575                (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
 576                ioflag |= IO_SYNC;
 577
 578        if ((flags & FOF_OFFSET) == 0) {
 579                uio->uio_offset = fp->f_fglob->fg_offset;
 580                count = uio_resid(uio);
 581        }
 582        if (p && (vp->v_type == VREG) &&
 583            (((uio->uio_offset + uio_uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) ||
 584             (uio_uio_resid(uio) > (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset)))) {
 585                psignal(p, SIGXFSZ);
 586                vnode_put(vp);
 587                return (EFBIG);
 588        }
 589
 590        error = VNOP_WRITE(vp, uio, ioflag, &context);
 591
 592        if ((flags & FOF_OFFSET) == 0) {
 593                if (ioflag & IO_APPEND)
 594                        fp->f_fglob->fg_offset = uio->uio_offset;
 595                else
 596                        fp->f_fglob->fg_offset += count - uio_resid(uio);
 597        }
 598
 599        /*
 600         * Set the credentials on successful writes
 601         */
 602        if ((error == 0) && (vp->v_tag == VT_NFS) && (UBCINFOEXISTS(vp))) {
 603                /* 
 604                 * When called from aio subsystem, we only have the proc from
 605                 * which to get the credential, at this point, so use that
 606                 * instead.  This means aio functions are incompatible with
 607                 * per-thread credentials (aio operations are proxied).  We
 608                 * can't easily correct the aio vs. settid race in this case
 609                 * anyway, so we disallow it.
 610                 */
 611                if ((flags & FOF_PCRED) == 0) {
 612                        ubc_setthreadcred(vp, p, current_thread());
 613                } else {
 614                        ubc_setcred(vp, p);
 615                }
 616        }
 617        (void)vnode_put(vp);
 618        return (error);
 619}
 620
 621/*
 622 * File table vnode stat routine.
 623 */
 624int
 625vn_stat_noauth(struct vnode *vp, struct stat *sb, kauth_filesec_t *xsec, vfs_context_t ctx)
 626{
 627        struct vnode_attr va;
 628        int error;
 629        u_short mode;
 630        kauth_filesec_t fsec;
 631
 632        VATTR_INIT(&va);
 633        VATTR_WANTED(&va, va_fsid);
 634        VATTR_WANTED(&va, va_fileid);
 635        VATTR_WANTED(&va, va_mode);
 636        VATTR_WANTED(&va, va_type);
 637        VATTR_WANTED(&va, va_nlink);
 638        VATTR_WANTED(&va, va_uid);
 639        VATTR_WANTED(&va, va_gid);
 640        VATTR_WANTED(&va, va_rdev);
 641        VATTR_WANTED(&va, va_data_size);
 642        VATTR_WANTED(&va, va_access_time);
 643        VATTR_WANTED(&va, va_modify_time);
 644        VATTR_WANTED(&va, va_change_time);
 645        VATTR_WANTED(&va, va_flags);
 646        VATTR_WANTED(&va, va_gen);
 647        VATTR_WANTED(&va, va_iosize);
 648        /* lower layers will synthesise va_total_alloc from va_data_size if required */
 649        VATTR_WANTED(&va, va_total_alloc);
 650        if (xsec != NULL) {
 651                VATTR_WANTED(&va, va_uuuid);
 652                VATTR_WANTED(&va, va_guuid);
 653                VATTR_WANTED(&va, va_acl);
 654        }
 655        error = vnode_getattr(vp, &va, ctx);
 656        if (error)
 657                goto out;
 658        /*
 659         * Copy from vattr table
 660         */
 661        sb->st_dev = va.va_fsid;
 662        sb->st_ino = (ino_t)va.va_fileid;
 663        mode = va.va_mode;
 664        switch (vp->v_type) {
 665        case VREG:
 666                mode |= S_IFREG;
 667                break;
 668        case VDIR:
 669                mode |= S_IFDIR;
 670                break;
 671        case VBLK:
 672                mode |= S_IFBLK;
 673                break;
 674        case VCHR:
 675                mode |= S_IFCHR;
 676                break;
 677        case VLNK:
 678                mode |= S_IFLNK;
 679                break;
 680        case VSOCK:
 681                mode |= S_IFSOCK;
 682                break;
 683        case VFIFO:
 684                mode |= S_IFIFO;
 685                break;
 686        default:
 687                error = EBADF;
 688                goto out;
 689        };
 690        sb->st_mode = mode;
 691        sb->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
 692        sb->st_uid = va.va_uid;
 693        sb->st_gid = va.va_gid;
 694        sb->st_rdev = va.va_rdev;
 695        sb->st_size = va.va_data_size;
 696        sb->st_atimespec = va.va_access_time;
 697        sb->st_mtimespec = va.va_modify_time;
 698        sb->st_ctimespec = va.va_change_time;
 699        sb->st_blksize = va.va_iosize;
 700        sb->st_flags = va.va_flags;
 701        sb->st_blocks = roundup(va.va_total_alloc, 512) / 512;
 702
 703        /* if we're interested in exended security data and we got an ACL */
 704        if (xsec != NULL) {
 705                if (!VATTR_IS_SUPPORTED(&va, va_acl) &&
 706                    !VATTR_IS_SUPPORTED(&va, va_uuuid) &&
 707                    !VATTR_IS_SUPPORTED(&va, va_guuid)) {
 708                        *xsec = KAUTH_FILESEC_NONE;
 709                } else {
 710                
 711                        if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
 712                                fsec = kauth_filesec_alloc(va.va_acl->acl_entrycount);
 713                        } else {
 714                                fsec = kauth_filesec_alloc(0);
 715                        }
 716                        if (fsec == NULL) {
 717                                error = ENOMEM;
 718                                goto out;
 719                        }
 720                        fsec->fsec_magic = KAUTH_FILESEC_MAGIC;
 721                        if (VATTR_IS_SUPPORTED(&va, va_uuuid)) {
 722                                fsec->fsec_owner = va.va_uuuid;
 723                        } else {
 724                                fsec->fsec_owner = kauth_null_guid;
 725                        }
 726                        if (VATTR_IS_SUPPORTED(&va, va_guuid)) {
 727                                fsec->fsec_group = va.va_guuid;
 728                        } else {
 729                                fsec->fsec_group = kauth_null_guid;
 730                        }
 731                        if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
 732                                bcopy(va.va_acl, &(fsec->fsec_acl), KAUTH_ACL_COPYSIZE(va.va_acl));
 733                        } else {
 734                                fsec->fsec_acl.acl_entrycount = KAUTH_FILESEC_NOACL;
 735                        }
 736                        *xsec = fsec;
 737                }
 738        }
 739        
 740        /* Do not give the generation number out to unpriviledged users */
 741        if (va.va_gen && !vfs_context_issuser(ctx))
 742                sb->st_gen = 0; 
 743        else
 744                sb->st_gen = va.va_gen;
 745
 746        error = 0;
 747out:
 748        if (VATTR_IS_SUPPORTED(&va, va_acl) && va.va_acl != NULL)
 749                kauth_acl_free(va.va_acl);
 750        return (error);
 751}
 752
 753int
 754vn_stat(struct vnode *vp, struct stat *sb, kauth_filesec_t *xsec, vfs_context_t ctx)
 755{
 756        int error;
 757
 758        /* authorize */
 759        if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY, ctx)) != 0)
 760                return(error);
 761
 762        /* actual stat */
 763        return(vn_stat_noauth(vp, sb, xsec, ctx));
 764}
 765
 766
 767/*
 768 * File table vnode ioctl routine.
 769 */
 770static int
 771vn_ioctl(fp, com, data, p)
 772        struct fileproc *fp;
 773        u_long com;
 774        caddr_t data;
 775        struct proc *p;
 776{
 777        register struct vnode *vp = ((struct vnode *)fp->f_fglob->fg_data);
 778        struct vfs_context context;
 779        off_t file_size;
 780        int error;
 781        struct vnode *ttyvp;
 782        int funnel_state;
 783        
 784        if ( (error = vnode_getwithref(vp)) ) {
 785                return(error);
 786        }
 787        context.vc_proc = p;
 788        context.vc_ucred = p->p_ucred;  /* XXX kauth_cred_get() ??? */
 789
 790        switch (vp->v_type) {
 791
 792        case VREG:
 793        case VDIR:
 794                if (com == FIONREAD) {
 795                        if ((error = vnode_size(vp, &file_size, &context)) != 0)
 796                                goto out;
 797                        *(int *)data = file_size - fp->f_fglob->fg_offset;
 798                        goto out;
 799                }
 800                if (com == FIONBIO || com == FIOASYNC) {        /* XXX */
 801                        goto out;
 802                }
 803                /* fall into ... */
 804
 805        default:
 806                error = ENOTTY;
 807                goto out;
 808
 809        case VFIFO:
 810        case VCHR:
 811        case VBLK:
 812
 813                /* Should not be able to set block size from user space */
 814                if (com == DKIOCSETBLOCKSIZE) {
 815                        error = EPERM;
 816                        goto out;
 817                }
 818
 819                if (com == FIODTYPE) {
 820                        if (vp->v_type == VBLK) {
 821                                if (major(vp->v_rdev) >= nblkdev) {
 822                                        error = ENXIO;
 823                                        goto out;
 824                                }
 825                                *(int *)data = bdevsw[major(vp->v_rdev)].d_type;
 826
 827                        } else if (vp->v_type == VCHR) {
 828                                if (major(vp->v_rdev) >= nchrdev) {
 829                                        error = ENXIO;
 830                                        goto out;
 831                                }
 832                                *(int *)data = cdevsw[major(vp->v_rdev)].d_type;
 833                        } else {
 834                                error = ENOTTY;
 835                                goto out;
 836                        }
 837                        goto out;
 838                }
 839                error = VNOP_IOCTL(vp, com, data, fp->f_fglob->fg_flag, &context);
 840
 841                if (error == 0 && com == TIOCSCTTY) {
 842                        vnode_ref(vp);
 843
 844                        funnel_state = thread_funnel_set(kernel_flock, TRUE);
 845                        ttyvp = p->p_session->s_ttyvp;
 846                        p->p_session->s_ttyvp = vp;
 847                        thread_funnel_set(kernel_flock, funnel_state);
 848
 849                        if (ttyvp)
 850                                vnode_rele(ttyvp);
 851                }
 852        }
 853out:
 854        (void)vnode_put(vp);
 855        return(error);
 856}
 857
 858/*
 859 * File table vnode select routine.
 860 */
 861static int
 862vn_select(fp, which, wql, p)
 863        struct fileproc *fp;
 864        int which;
 865        void * wql;
 866        struct proc *p;
 867{
 868        int error;
 869        struct vnode * vp = (struct vnode *)fp->f_fglob->fg_data;
 870        struct vfs_context context;
 871
 872        if ( (error = vnode_getwithref(vp)) == 0 ) {
 873                context.vc_proc = p;
 874                context.vc_ucred = fp->f_fglob->fg_cred;
 875
 876                error = VNOP_SELECT(vp, which, fp->f_fglob->fg_flag, wql, &context);
 877
 878                (void)vnode_put(vp);
 879        }
 880        return(error);
 881        
 882}
 883
 884/*
 885 * Check that the vnode is still valid, and if so
 886 * acquire requested lock.
 887 */
 888int
 889vn_lock(__unused vnode_t vp, __unused int flags, __unused proc_t p)
 890{
 891        return (0);
 892}
 893
 894/*
 895 * File table vnode close routine.
 896 */
 897static int
 898vn_closefile(fg, p)
 899        struct fileglob *fg;
 900        struct proc *p;
 901{
 902        struct vnode *vp = (struct vnode *)fg->fg_data;
 903        int error;
 904
 905        if ( (error = vnode_getwithref(vp)) == 0 ) {
 906                error = vn_close(vp, fg->fg_flag, fg->fg_cred, p);
 907
 908                (void)vnode_put(vp);
 909        }
 910        return(error);
 911}
 912
 913int
 914vn_pathconf(vnode_t vp, int name, register_t *retval, vfs_context_t ctx)
 915{
 916        int     error = 0;
 917
 918        switch(name) {
 919        case _PC_EXTENDED_SECURITY_NP:
 920                *retval = vfs_extendedsecurity(vnode_mount(vp));
 921                break;
 922        case _PC_AUTH_OPAQUE_NP:
 923                *retval = vfs_authopaque(vnode_mount(vp));
 924                break;
 925        default:
 926                error = VNOP_PATHCONF(vp, name, retval, ctx);
 927                break;
 928        }
 929
 930        return (error);
 931}
 932
 933static int
 934vn_kqfilt_add(fp, kn, p)
 935        struct fileproc *fp;
 936        struct knote *kn;
 937        struct proc *p;
 938{
 939        struct vnode *vp = (struct vnode *)fp->f_fglob->fg_data;
 940        struct vfs_context context;
 941        int error;
 942        int funnel_state;
 943        
 944        if ( (error = vnode_getwithref(vp)) == 0 ) {
 945                context.vc_proc = p;
 946                context.vc_ucred = p->p_ucred;  /* XXX kauth_cred_get() ??? */
 947
 948                funnel_state = thread_funnel_set(kernel_flock, TRUE);
 949                error = VNOP_KQFILT_ADD(vp, kn, &context);
 950                thread_funnel_set(kernel_flock, funnel_state);
 951
 952                (void)vnode_put(vp);
 953        }
 954        return (error);
 955}
 956
 957#if 0
 958/* No one calls this yet. */
 959static int
 960vn_kqfilt_remove(vp, ident, p)
 961        struct vnode *vp;
 962        uintptr_t ident;
 963        struct proc *p;
 964{
 965        struct vfs_context context;
 966        int error;
 967        int funnel_state;
 968        
 969        if ( (error = vnode_getwithref(vp)) == 0 ) {
 970                context.vc_proc = p;
 971                context.vc_ucred = p->p_ucred;  /* XXX kauth_cred_get() ??? */
 972
 973                funnel_state = thread_funnel_set(kernel_flock, TRUE);
 974                error = VNOP_KQFILT_REMOVE(vp, ident, &context);
 975                thread_funnel_set(kernel_flock, funnel_state);
 976
 977                (void)vnode_put(vp);
 978        }
 979        return (error);
 980}
 981#endif
 982
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.