Annotation of XNU/bsd/miscfs/devfs/devfs_vnops.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 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: /*
                     23:  * Copyright 1997,1998 Julian Elischer.  All rights reserved.
                     24:  * [email protected]
                     25:  * 
                     26:  * Redistribution and use in source and binary forms, with or without
                     27:  * modification, are permitted provided that the following conditions are
                     28:  * met:
                     29:  *  1. Redistributions of source code must retain the above copyright
                     30:  *     notice, this list of conditions and the following disclaimer.
                     31:  *  2. Redistributions in binary form must reproduce the above copyright notice,
                     32:  *     this list of conditions and the following disclaimer in the documentation
                     33:  *     and/or other materials provided with the distribution.
                     34:  * 
                     35:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
                     36:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     37:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     38:  * DISCLAIMED.  IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
                     39:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     40:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     41:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
                     42:  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     43:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     44:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     45:  * SUCH DAMAGE.
                     46:  * 
                     47:  * devfs_vnops.c
                     48:  */
                     49: 
                     50: /*
                     51:  * HISTORY
                     52:  *  Clark Warner ([email protected]) Tue Feb 10 2000
                     53:  *  - Added err_copyfile to the vnode operations table
                     54:  *  Dieter Siegmund ([email protected]) Thu Apr  8 14:08:19 PDT 1999
                     55:  *  - instead of duplicating specfs here, created a vnode-ops table
                     56:  *    that redirects most operations to specfs (as is done with ufs);
                     57:  *  - removed routines that made no sense
                     58:  *  - cleaned up reclaim: replaced devfs_vntodn() with a macro VTODN()
                     59:  *  - cleaned up symlink, link locking
                     60:  *  - added the devfs_lock to protect devfs data structures against
                     61:  *    driver's calling devfs_add_devswf()/etc.
                     62:  *  Dieter Siegmund ([email protected]) Wed Jul 14 13:37:59 PDT 1999
                     63:  *  - free the devfs devnode in devfs_inactive(), not just in devfs_reclaim()
                     64:  *    to free up kernel memory as soon as it's available
                     65:  *  - got rid of devfsspec_{read, write}
                     66:  *  Dieter Siegmund ([email protected]) Fri Sep 17 09:58:38 PDT 1999
                     67:  *  - update the mod/access times
                     68:  */
                     69: 
                     70: #include <sys/param.h>
                     71: #include <sys/systm.h>
                     72: #include <sys/buf.h>
                     73: #include <sys/namei.h>
                     74: #include <sys/kernel.h>
                     75: #include <sys/fcntl.h>
                     76: #include <sys/conf.h>
                     77: #include <sys/disklabel.h>
                     78: #include <sys/lock.h>
                     79: #include <sys/stat.h>
                     80: #include <sys/mount.h>
                     81: #include <sys/proc.h>
                     82: #include <sys/time.h>
                     83: #include <sys/vnode.h>
                     84: #include <miscfs/specfs/specdev.h>
                     85: #include <sys/dirent.h>
                     86: #include <sys/vmmeter.h>
                     87: #include <sys/vm.h>
                     88: 
                     89: #include "devfsdefs.h"
                     90: 
                     91: /*
                     92:  * Convert a component of a pathname into a pointer to a locked node.
                     93:  * This is a very central and rather complicated routine.
                     94:  * If the file system is not maintained in a strict tree hierarchy,
                     95:  * this can result in a deadlock situation (see comments in code below).
                     96:  *
                     97:  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
                     98:  * whether the name is to be looked up, created, renamed, or deleted.
                     99:  * When CREATE, RENAME, or DELETE is specified, information usable in
                    100:  * creating, renaming, or deleting a directory entry may be calculated.
                    101:  * If flag has LOCKPARENT or'ed into it and the target of the pathname
                    102:  * exists, lookup returns both the target and its parent directory locked.
                    103:  * When creating or renaming and LOCKPARENT is specified, the target may
                    104:  * not be ".".  When deleting and LOCKPARENT is specified, the target may
                    105:  * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
                    106:  * instead of two DNUNLOCKs.
                    107:  *
                    108:  * Overall outline of devfs_lookup:
                    109:  *
                    110:  *     check accessibility of directory
                    111:  *     null terminate the component (lookup leaves the whole string alone)
                    112:  *     look for name in cache, if found, then if at end of path
                    113:  *       and deleting or creating, drop it, else return name
                    114:  *     search for name in directory, to found or notfound
                    115:  * notfound:
                    116:  *     if creating, return locked directory,
                    117:  *     else return error
                    118:  * found:
                    119:  *     if at end of path and deleting, return information to allow delete
                    120:  *     if at end of path and rewriting (RENAME and LOCKPARENT), lock target
                    121:  *       node and return info to allow rewrite
                    122:  *     if not at end, add name to cache; if at end and neither creating
                    123:  *       nor deleting, add name to cache
                    124:  * On return to lookup, remove the null termination we put in at the start.
                    125:  *
                    126:  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
                    127:  */
                    128: static int
                    129: devfs_lookup(struct vop_lookup_args *ap)
                    130:         /*struct vop_lookup_args {
                    131:                 struct vnode * a_dvp; directory vnode ptr
                    132:                 struct vnode ** a_vpp; where to put the result
                    133:                 struct componentname * a_cnp; the name we want
                    134:         };*/
                    135: {
                    136:        struct componentname *cnp = ap->a_cnp;
                    137:        struct vnode *dir_vnode = ap->a_dvp;
                    138:        struct vnode **result_vnode = ap->a_vpp;
                    139:        devnode_t *   dir_node;       /* the directory we are searching */
                    140:        devnode_t *   node = NULL;       /* the node we are searching for */
                    141:        devdirent_t * nodename;
                    142:        int flags = cnp->cn_flags;
                    143:        int op = cnp->cn_nameiop;       /* LOOKUP, CREATE, RENAME, or DELETE */
                    144:        int lockparent = flags & LOCKPARENT;
                    145:        int wantparent = flags & (LOCKPARENT|WANTPARENT);
                    146:        int error = 0;
                    147:        struct proc *p = cnp->cn_proc;
                    148:        char    heldchar;       /* the char at the end of the name componet */
                    149: 
                    150:        *result_vnode = NULL; /* safe not sorry */ /*XXX*/
                    151: 
                    152:        if (dir_vnode->v_usecount == 0)
                    153:            printf("devfs_lookup: dir had no refs ");
                    154:        dir_node = VTODN(dir_vnode);
                    155: 
                    156:        /*
                    157:         * Check accessiblity of directory.
                    158:         */
                    159:        if (dir_node->dn_type != DEV_DIR) {
                    160:                return (ENOTDIR);
                    161:        }
                    162: 
                    163:        if ((error = VOP_ACCESS(dir_vnode, VEXEC, cnp->cn_cred, p)) != 0) {
                    164:                return (error);
                    165:        }
                    166: 
                    167:        /* temporarily terminate string component */
                    168:        heldchar = cnp->cn_nameptr[cnp->cn_namelen];
                    169:        cnp->cn_nameptr[cnp->cn_namelen] = '\0';
                    170:        DEVFS_LOCK(p);
                    171:        nodename = dev_findname(dir_node,cnp->cn_nameptr);
                    172:        if (nodename) {
                    173:            /* entry exists */
                    174:            node = nodename->de_dnp;
                    175:            node->dn_last_lookup = nodename; /* for unlink */
                    176:            /* Do potential vnode allocation here inside the lock 
                    177:             * to make sure that our device node has a non-NULL dn_vn
                    178:             * associated with it.  The device node might otherwise
                    179:             * get deleted out from under us (see devfs_dn_free()).
                    180:             */
                    181:            error = devfs_dntovn(node, result_vnode, p);
                    182:        }
                    183:        DEVFS_UNLOCK(p);
                    184:        /* restore saved character */
                    185:        cnp->cn_nameptr[cnp->cn_namelen] = heldchar;
                    186: 
                    187:        if (error)
                    188:            return (error);
                    189: 
                    190:        if (!nodename) { /* no entry */
                    191:                /* If it doesn't exist and we're not the last component,
                    192:                 * or we're at the last component, but we're not creating
                    193:                 * or renaming, return ENOENT.
                    194:                 */
                    195:                if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) {
                    196:                        return ENOENT;
                    197:                }
                    198:                /*
                    199:                 * Access for write is interpreted as allowing
                    200:                 * creation of files in the directory.
                    201:                 */
                    202:                if ((error = VOP_ACCESS(dir_vnode, VWRITE,
                    203:                                cnp->cn_cred, p)) != 0)
                    204:                {
                    205:                        return (error);
                    206:                }
                    207:                /*
                    208:                 * We return with the directory locked, so that
                    209:                 * the parameters we set up above will still be
                    210:                 * valid if we actually decide to add a new entry.
                    211:                 * We return ni_vp == NULL to indicate that the entry
                    212:                 * does not currently exist; we leave a pointer to
                    213:                 * the (locked) directory vnode in namei_data->ni_dvp.
                    214:                 * The pathname buffer is saved so that the name
                    215:                 * can be obtained later.
                    216:                 *
                    217:                 * NB - if the directory is unlocked, then this
                    218:                 * information cannot be used.
                    219:                 */
                    220:                cnp->cn_flags |= SAVENAME;
                    221:                if (!lockparent)
                    222:                        VOP_UNLOCK(dir_vnode, 0, p);
                    223:                return (EJUSTRETURN);
                    224:        }
                    225: 
                    226:        /*
                    227:         * If deleting, and at end of pathname, return
                    228:         * parameters which can be used to remove file.
                    229:         * If the wantparent flag isn't set, we return only
                    230:         * the directory (in namei_data->ni_dvp), otherwise we go
                    231:         * on and lock the node, being careful with ".".
                    232:         */
                    233:        if (op == DELETE && (flags & ISLASTCN)) {
                    234:                /*
                    235:                 * Write access to directory required to delete files.
                    236:                 */
                    237:                if ((error = VOP_ACCESS(dir_vnode, VWRITE,
                    238:                                cnp->cn_cred, p)) != 0)
                    239:                        return (error);
                    240:                /*
                    241:                 * we are trying to delete '.'.  What does this mean? XXX
                    242:                 */
                    243:                if (dir_node == node) {
                    244:                        VREF(dir_vnode);
                    245:                        *result_vnode = dir_vnode;
                    246:                        return (0);
                    247:                }
                    248: #ifdef NOTYET
                    249:                /*
                    250:                 * If directory is "sticky", then user must own
                    251:                 * the directory, or the file in it, else she
                    252:                 * may not delete it (unless she's root). This
                    253:                 * implements append-only directories.
                    254:                 */
                    255:                if ((dir_node->mode & ISVTX) &&
                    256:                    cnp->cn_cred->cr_uid != 0 &&
                    257:                    cnp->cn_cred->cr_uid != dir_node->uid &&
                    258:                    cnp->cn_cred->cr_uid != node->uid) {
                    259:                        VOP_UNLOCK(*result_vnode, 0, p);
                    260:                        return (EPERM);
                    261:                }
                    262: #endif
                    263:                if (!lockparent)
                    264:                        VOP_UNLOCK(dir_vnode, 0, p);
                    265:                return (0);
                    266:        }
                    267: 
                    268:        /*
                    269:         * If rewriting (RENAME), return the vnode and the
                    270:         * information required to rewrite the present directory
                    271:         * Must get node of directory entry to verify it's a
                    272:         * regular file, or empty directory.
                    273:         */
                    274:        if (op == RENAME && wantparent && (flags & ISLASTCN)) {
                    275:                /*
                    276:                 * Are we allowed to change the holding directory?
                    277:                 */
                    278:                if ((error = VOP_ACCESS(dir_vnode, VWRITE,
                    279:                                cnp->cn_cred, p)) != 0)
                    280:                        return (error);
                    281:                /*
                    282:                 * Careful about locking second node.
                    283:                 * This can only occur if the target is ".".
                    284:                 */
                    285:                if (dir_node == node)
                    286:                        return (EISDIR);
                    287:                /* hmm save the 'from' name (we need to delete it) */
                    288:                cnp->cn_flags |= SAVENAME;
                    289:                if (!lockparent)
                    290:                        VOP_UNLOCK(dir_vnode, 0, p);
                    291:                return (0);
                    292:        }
                    293: 
                    294:        /*
                    295:         * Step through the translation in the name.  We do not unlock the
                    296:         * directory because we may need it again if a symbolic link
                    297:         * is relative to the current directory.  Instead we save it
                    298:         * unlocked as "saved_dir_node" XXX.  We must get the target
                    299:         * node before unlocking
                    300:         * the directory to insure that the node will not be removed
                    301:         * before we get it.  We prevent deadlock by always fetching
                    302:         * nodes from the root, moving down the directory tree. Thus
                    303:         * when following backward pointers ".." we must unlock the
                    304:         * parent directory before getting the requested directory.
                    305:         * There is a potential race condition here if both the current
                    306:         * and parent directories are removed before the lock for the
                    307:         * node associated with ".." returns.  We hope that this occurs
                    308:         * infrequently since we cannot avoid this race condition without
                    309:         * implementing a sophisticated deadlock detection algorithm.
                    310:         * Note also that this simple deadlock detection scheme will not
                    311:         * work if the file system has any hard links other than ".."
                    312:         * that point backwards in the directory structure.
                    313:         */
                    314:        if (flags & ISDOTDOT) {
                    315:                VOP_UNLOCK(dir_vnode, 0, p);    /* race to get the node */
                    316:                if (lockparent && (flags & ISLASTCN))
                    317:                        vn_lock(dir_vnode, LK_EXCLUSIVE | LK_RETRY, p);
                    318:        } else if (dir_node == node) {
                    319: #if 0
                    320:            /* 
                    321:             * this next statement is wrong: we already did a vget in 
                    322:             * devfs_dntovn(); DWS 4/16/1999
                    323:             */
                    324:                 VREF(dir_vnode);        /* we want ourself, ie "." */
                    325: #endif
                    326:                *result_vnode = dir_vnode;
                    327:        } else {
                    328:                if (!lockparent || (flags & ISLASTCN))
                    329:                        VOP_UNLOCK(dir_vnode, 0, p);
                    330:        }
                    331: 
                    332:        return (0);
                    333: }
                    334: 
                    335: static int
                    336: devfs_access(struct vop_access_args *ap)
                    337:         /*struct vop_access_args  {
                    338:                 struct vnode *a_vp;
                    339:                 int  a_mode;
                    340:                 struct ucred *a_cred;
                    341:                 struct proc *a_p;
                    342:         } */ 
                    343: {
                    344:        /*
                    345:         *  mode is filled with a combination of VREAD, VWRITE,
                    346:         *  and/or VEXEC bits turned on.  In an octal number these
                    347:         *  are the Y in 0Y00.
                    348:         */
                    349:        struct vnode *vp = ap->a_vp;
                    350:        int mode = ap->a_mode;
                    351:        struct ucred *cred = ap->a_cred;
                    352:        devnode_t *     file_node;
                    353:        gid_t   *gp;
                    354:        int     i;
                    355:        struct proc *p = ap->a_p;
                    356: 
                    357:        file_node = VTODN(vp);
                    358:        /* 
                    359:         * if we are not running as a process, we are in the 
                    360:         * kernel and we DO have permission
                    361:         */
                    362:        if (p == NULL)
                    363:            return 0;
                    364: 
                    365:        /*
                    366:         * Access check is based on only one of owner, group, public.
                    367:         * If not owner, then check group. If not a member of the
                    368:         * group, then check public access.
                    369:         */
                    370:        if (cred->cr_uid != file_node->dn_uid)
                    371:        {
                    372:                /* failing that.. try groups */
                    373:                mode >>= 3;
                    374:                gp = cred->cr_groups;
                    375:                for (i = 0; i < cred->cr_ngroups; i++, gp++)
                    376:                {
                    377:                        if (file_node->dn_gid == *gp)
                    378:                        {
                    379:                                goto found;
                    380:                        }
                    381:                }
                    382:                /* failing that.. try general access */
                    383:                mode >>= 3;
                    384: found:
                    385:                ;
                    386:        }
                    387:        if ((file_node->dn_mode & mode) == mode)
                    388:                return (0);
                    389:        /*
                    390:         *  Root gets to do anything.
                    391:         * but only use suser prives as a last resort
                    392:         * (Use of super powers is recorded in ap->a_p->p_acflag)
                    393:         */
                    394:        if( suser(cred, &ap->a_p->p_acflag) == 0) /* XXX what if no proc? */
                    395:                return 0;
                    396:        return (EACCES);
                    397: }
                    398: 
                    399: static int
                    400: devfs_getattr(struct vop_getattr_args *ap)
                    401:         /*struct vop_getattr_args {
                    402:                 struct vnode *a_vp;
                    403:                 struct vattr *a_vap;
                    404:                 struct ucred *a_cred;
                    405:                 struct proc *a_p;
                    406:         } */ 
                    407: {
                    408:        struct vnode *vp = ap->a_vp;
                    409:        struct vattr *vap = ap->a_vap;
                    410:        devnode_t *     file_node;
                    411:        struct timeval  tv;
                    412: 
                    413:        file_node = VTODN(vp);
                    414:        tv = time;
                    415:        dn_times(file_node, tv, tv);
                    416:        vap->va_rdev = 0;/* default value only */
                    417:        vap->va_mode = file_node->dn_mode;
                    418:        switch (file_node->dn_type)
                    419:        {
                    420:        case    DEV_DIR:
                    421:                vap->va_rdev = (dev_t)file_node->dn_dvm;
                    422:                vap->va_mode |= (S_IFDIR);
                    423:                break;
                    424:        case    DEV_CDEV:
                    425:                vap->va_rdev = file_node->dn_typeinfo.dev;
                    426:                vap->va_mode |= (S_IFCHR);
                    427:                break;
                    428:        case    DEV_BDEV:
                    429:                vap->va_rdev = file_node->dn_typeinfo.dev;
                    430:                vap->va_mode |= (S_IFBLK);
                    431:                break;
                    432:        case    DEV_SLNK:
                    433:                vap->va_mode |= (S_IFLNK);
                    434:                break;
                    435:        }
                    436:        vap->va_type = vp->v_type;
                    437:        vap->va_nlink = file_node->dn_links;
                    438:        vap->va_uid = file_node->dn_uid;
                    439:        vap->va_gid = file_node->dn_gid;
                    440:        vap->va_fsid = (int32_t)(void *)file_node->dn_dvm;
                    441:        vap->va_fileid = (int32_t)(void *)file_node;
                    442:        vap->va_size = file_node->dn_len; /* now a u_quad_t */
                    443:        /* this doesn't belong here */
                    444:        if (vp->v_type == VBLK)
                    445:                vap->va_blocksize = BLKDEV_IOSIZE;
                    446:        else if (vp->v_type == VCHR)
                    447:                vap->va_blocksize = MAXPHYSIO;
                    448:        else
                    449:                vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
                    450:        /* if the time is bogus, set it to the boot time */
                    451:        if (file_node->dn_ctime.tv_sec == 0)
                    452:            file_node->dn_ctime.tv_sec = boottime.tv_sec;
                    453:        if (file_node->dn_mtime.tv_sec == 0)
                    454:            file_node->dn_mtime.tv_sec = boottime.tv_sec;
                    455:        if (file_node->dn_atime.tv_sec == 0)
                    456:            file_node->dn_atime.tv_sec = boottime.tv_sec;
                    457:        vap->va_ctime = file_node->dn_ctime;
                    458:        vap->va_mtime = file_node->dn_mtime;
                    459:        vap->va_atime = file_node->dn_atime;
                    460:        vap->va_gen = 0;
                    461:        vap->va_flags = 0;
                    462:        vap->va_bytes = file_node->dn_len;              /* u_quad_t */
                    463:        vap->va_filerev = 0; /* XXX */          /* u_quad_t */
                    464:        vap->va_vaflags = 0; /* XXX */
                    465:        return 0;
                    466: }
                    467: 
                    468: static int
                    469: devfs_setattr(struct vop_setattr_args *ap)
                    470:         /*struct vop_setattr_args  {
                    471:                 struct vnode *a_vp;
                    472:                 struct vattr *a_vap;
                    473:                 struct ucred *a_cred;
                    474:                 struct proc *a_p;
                    475:         } */ 
                    476: {
                    477:        struct vnode *vp = ap->a_vp;
                    478:        struct vattr *vap = ap->a_vap;
                    479:        struct ucred *cred = ap->a_cred;
                    480:        struct proc *p = ap->a_p;
                    481:        int error = 0;
                    482:        gid_t *gp;
                    483:        int i;
                    484:        devnode_t *     file_node;
                    485:        struct timeval atimeval, mtimeval;
                    486: 
                    487:        if (vap->va_flags != VNOVAL)    /* XXX needs to be implemented */
                    488:                return (EOPNOTSUPP);
                    489: 
                    490:        file_node = VTODN(vp);
                    491: 
                    492:        if ((vap->va_type != VNON)  ||
                    493:            (vap->va_nlink != VNOVAL)  ||
                    494:            (vap->va_fsid != VNOVAL)  ||
                    495:            (vap->va_fileid != VNOVAL)  ||
                    496:            (vap->va_blocksize != VNOVAL)  ||
                    497:            (vap->va_rdev != VNOVAL)  ||
                    498:            (vap->va_bytes != VNOVAL)  ||
                    499:            (vap->va_gen != VNOVAL ))
                    500:        {
                    501:                return EINVAL;
                    502:        }
                    503: 
                    504:        /*
                    505:         * Go through the fields and update iff not VNOVAL.
                    506:         */
                    507:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
                    508:            if (cred->cr_uid != file_node->dn_uid &&
                    509:                (error = suser(cred, &p->p_acflag)) &&
                    510:                ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 
                    511:                 (error = VOP_ACCESS(vp, VWRITE, cred, p))))
                    512:                return (error);
                    513:            if (vap->va_atime.tv_sec != VNOVAL)
                    514:                file_node->dn_flags |= DN_ACCESS;
                    515:            if (vap->va_mtime.tv_sec != VNOVAL)
                    516:                file_node->dn_flags |= DN_CHANGE | DN_UPDATE;
                    517:            atimeval.tv_sec = vap->va_atime.tv_sec;
                    518:            atimeval.tv_usec = vap->va_atime.tv_nsec / 1000;
                    519:            mtimeval.tv_sec = vap->va_mtime.tv_sec;
                    520:            mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000;
                    521:            if (error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))
                    522:                return (error);
                    523:        }
                    524: 
                    525:        /*
                    526:         * Change the permissions.. must be root or owner to do this.
                    527:         */
                    528:        if (vap->va_mode != (u_short)VNOVAL) {
                    529:                if ((cred->cr_uid != file_node->dn_uid)
                    530:                 && (error = suser(cred, &p->p_acflag)))
                    531:                        return (error);
                    532:                file_node->dn_mode &= ~07777;
                    533:                file_node->dn_mode |= vap->va_mode & 07777;
                    534:        }
                    535: 
                    536:        /*
                    537:         * Change the owner.. must be root to do this.
                    538:         */
                    539:        if (vap->va_uid != (uid_t)VNOVAL) {
                    540:                if (error = suser(cred, &p->p_acflag))
                    541:                        return (error);
                    542:                file_node->dn_uid = vap->va_uid;
                    543:        }
                    544: 
                    545:        /*
                    546:         * Change the group.. must be root or owner to do this.
                    547:         * If we are the owner, we must be in the target group too.
                    548:         * don't use suser() unless you have to as it reports
                    549:         * whether you needed suser powers or not.
                    550:         */
                    551:        if (vap->va_gid != (gid_t)VNOVAL) {
                    552:                if (cred->cr_uid == file_node->dn_uid){
                    553:                        gp = cred->cr_groups;
                    554:                        for (i = 0; i < cred->cr_ngroups; i++, gp++) {
                    555:                                if (vap->va_gid == *gp)
                    556:                                        goto cando; 
                    557:                        }
                    558:                }
                    559:                /*
                    560:                 * we can't do it with normal privs,
                    561:                 * do we have an ace up our sleeve?
                    562:                 */
                    563:                if (error = suser(cred, &p->p_acflag))
                    564:                        return (error);
                    565: cando:
                    566:                file_node->dn_gid = vap->va_gid;
                    567:        }
                    568: #if 0
                    569:        /*
                    570:         * Copied from somewhere else
                    571:         * but only kept as a marker and reminder of the fact that
                    572:         * flags should be handled some day
                    573:         */
                    574:        if (vap->va_flags != VNOVAL) {
                    575:                if (error = suser(cred, &p->p_acflag))
                    576:                        return error;
                    577:                if (cred->cr_uid == 0)
                    578:                ;
                    579:                else {
                    580:                }
                    581:        }
                    582: #endif
                    583:        return error;
                    584: }
                    585: 
                    586: static int
                    587: devfs_read(struct vop_read_args *ap)
                    588:         /*struct vop_read_args {
                    589:                 struct vnode *a_vp;
                    590:                 struct uio *a_uio;
                    591:                 int  a_ioflag;
                    592:                 struct ucred *a_cred;
                    593:         } */
                    594: {
                    595:        devnode_t * dn_p = VTODN(ap->a_vp);
                    596: 
                    597:        switch (ap->a_vp->v_type) {
                    598:          case VDIR: {
                    599:              dn_p->dn_flags |= DN_ACCESS;
                    600:              return VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred,
                    601:                                 NULL, NULL, NULL);
                    602:          }
                    603:          default: {
                    604:              printf("devfs_read(): bad file type %d", ap->a_vp->v_type);
                    605:              return(EINVAL);
                    606:              break;
                    607:          }
                    608:        }
                    609:        return (0); /* not reached */
                    610: }
                    611: 
                    612: static int
                    613: devfs_close(ap)
                    614:        struct vop_close_args /* {
                    615:                struct vnode *a_vp;
                    616:                int  a_fflag;
                    617:                struct ucred *a_cred;
                    618:                struct proc *a_p;
                    619:        } */ *ap;
                    620: {
                    621:        struct vnode *          vp = ap->a_vp;
                    622:        register devnode_t *    dnp = VTODN(vp);
                    623: 
                    624:        simple_lock(&vp->v_interlock);
                    625:        if (vp->v_usecount > 1)
                    626:            dn_times(dnp, time, time);
                    627:        simple_unlock(&vp->v_interlock);
                    628:        return (0);
                    629: }
                    630: 
                    631: static int
                    632: devfsspec_close(ap)
                    633:        struct vop_close_args /* {
                    634:                struct vnode *a_vp;
                    635:                int  a_fflag;
                    636:                struct ucred *a_cred;
                    637:                struct proc *a_p;
                    638:        } */ *ap;
                    639: {
                    640:        struct vnode *          vp = ap->a_vp;
                    641:        register devnode_t *    dnp = VTODN(vp);
                    642: 
                    643:        simple_lock(&vp->v_interlock);
                    644:        if (vp->v_usecount > 1)
                    645:            dn_times(dnp, time, time);
                    646:        simple_unlock(&vp->v_interlock);
                    647:        return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
                    648: }
                    649: 
                    650: static int
                    651: devfsspec_read(struct vop_read_args *ap)
                    652:         /*struct vop_read_args {
                    653:                 struct vnode *a_vp;
                    654:                 struct uio *a_uio;
                    655:                 int  a_ioflag;
                    656:                 struct ucred *a_cred;
                    657:         } */
                    658: {
                    659:     VTODN(ap->a_vp)->dn_flags |= DN_ACCESS;
                    660:     return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
                    661: }
                    662: 
                    663: static int
                    664: devfsspec_write(struct vop_write_args *ap)
                    665:         /*struct vop_write_args  {
                    666:                 struct vnode *a_vp;
                    667:                 struct uio *a_uio;
                    668:                 int  a_ioflag;
                    669:                 struct ucred *a_cred;
                    670:         } */
                    671: {
                    672:     VTODN(ap->a_vp)->dn_flags |= DN_CHANGE | DN_UPDATE;
                    673:     return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
                    674: }
                    675: 
                    676: /*
                    677:  *  Write data to a file or directory.
                    678:  */
                    679: static int
                    680: devfs_write(struct vop_write_args *ap)
                    681:         /*struct vop_write_args  {
                    682:                 struct vnode *a_vp;
                    683:                 struct uio *a_uio;
                    684:                 int  a_ioflag;
                    685:                 struct ucred *a_cred;
                    686:         } */
                    687: {
                    688:        switch (ap->a_vp->v_type) {
                    689:        case VDIR:
                    690:                return(EISDIR);
                    691:        default:
                    692:                printf("devfs_write(): bad file type %d", ap->a_vp->v_type);
                    693:                return (EINVAL);
                    694:        }
                    695:        return 0; /* not reached */
                    696: }
                    697: 
                    698: static int
                    699: devfs_remove(struct vop_remove_args *ap)
                    700:         /*struct vop_remove_args  {
                    701:                 struct vnode *a_dvp;
                    702:                 struct vnode *a_vp;
                    703:                 struct componentname *a_cnp;
                    704:         } */ 
                    705: {
                    706:        struct vnode *vp = ap->a_vp;
                    707:        struct vnode *dvp = ap->a_dvp;
                    708:        struct componentname *cnp = ap->a_cnp;
                    709:        devnode_t *  tp;
                    710:        devnode_t *  tdp;
                    711:        devdirent_t * tnp;
                    712:        int doingdirectory = 0;
                    713:        int error = 0;
                    714:        uid_t ouruid = cnp->cn_cred->cr_uid;
                    715:        struct proc *p = cnp->cn_proc;
                    716: 
                    717:        /*
                    718:         * Lock our directories and get our name pointers
                    719:         * assume that the names are null terminated as they
                    720:         * are the end of the path. Get pointers to all our
                    721:         * devfs structures.
                    722:         */
                    723:        tp = VTODN(vp);
                    724:        tdp = VTODN(dvp);
                    725:        /*
                    726:         * Assuming we are atomic, dev_lookup left this for us
                    727:         */
                    728:        tnp = tp->dn_last_lookup;
                    729: 
                    730:        /*
                    731:         * Check we are doing legal things WRT the new flags
                    732:         */
                    733:        if ((tp->dn_flags & (IMMUTABLE | APPEND))
                    734:          || (tdp->dn_flags & APPEND) /*XXX eh?*/ ) {
                    735:            error = EPERM;
                    736:            goto abort;
                    737:        }
                    738: 
                    739:        /*
                    740:         * Make sure that we don't try do something stupid
                    741:         */
                    742:        if ((tp->dn_type) == DEV_DIR) {
                    743:                /*
                    744:                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                    745:                 */
                    746:                if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') 
                    747:                    || (cnp->cn_flags&ISDOTDOT) ) {
                    748:                        error = EINVAL;
                    749:                        goto abort;
                    750:                }
                    751:                doingdirectory++;
                    752:        }
                    753: 
                    754:        /***********************************
                    755:         * Start actually doing things.... *
                    756:         ***********************************/
                    757:        tdp->dn_flags |= DN_CHANGE | DN_UPDATE;
                    758: 
                    759:        /*
                    760:         * own the parent directory, or the destination of the rename,
                    761:         * otherwise the destination may not be changed (except by
                    762:         * root). This implements append-only directories.
                    763:         * XXX shoudn't this be in generic code? 
                    764:         */
                    765:        if ((tdp->dn_mode & S_ISTXT)
                    766:          && ouruid != 0
                    767:          && ouruid != tdp->dn_uid
                    768:          && ouruid != tp->dn_uid ) {
                    769:            error = EPERM;
                    770:            goto abort;
                    771:        }
                    772:        /*
                    773:         * Target must be empty if a directory and have no links
                    774:         * to it. Also, ensure source and target are compatible
                    775:         * (both directories, or both not directories).
                    776:         */
                    777:        if (( doingdirectory) && (tp->dn_links > 2)) {
                    778:            error = ENOTEMPTY;
                    779:            goto abort;
                    780:        }
                    781:        DEVFS_LOCK(p);
                    782:        dev_free_name(tnp);
                    783:        DEVFS_UNLOCK(p);
                    784:  abort:
                    785:        if (dvp == vp)
                    786:            vrele(vp);
                    787:        else
                    788:            vput(vp);
                    789:        vput(dvp);
                    790:        return (error);
                    791: }
                    792: 
                    793: /*
                    794:  */
                    795: static int
                    796: devfs_link(struct vop_link_args *ap)
                    797:         /*struct vop_link_args  {
                    798:                 struct vnode *a_tdvp;
                    799:                 struct vnode *a_vp;
                    800:                 struct componentname *a_cnp;
                    801:         } */ 
                    802: {
                    803:        struct vnode *vp = ap->a_vp;
                    804:        struct vnode *tdvp = ap->a_tdvp;
                    805:        struct componentname *cnp = ap->a_cnp;
                    806:        struct proc *p = cnp->cn_proc;
                    807:        devnode_t * fp;
                    808:        devnode_t * tdp;
                    809:        devdirent_t * tnp;
                    810:        int error = 0;
                    811:        struct timeval tv;
                    812: 
                    813:        /*
                    814:         * First catch an arbitrary restriction for this FS
                    815:         */
                    816:        if (cnp->cn_namelen > DEVMAXNAMESIZE) {
                    817:                error = ENAMETOOLONG;
                    818:                goto out1;
                    819:        }
                    820: 
                    821:        /*
                    822:         * Lock our directories and get our name pointers
                    823:         * assume that the names are null terminated as they
                    824:         * are the end of the path. Get pointers to all our
                    825:         * devfs structures.
                    826:         */
                    827:        tdp = VTODN(tdvp);
                    828:        fp = VTODN(vp);
                    829:        
                    830:        if (tdvp->v_mount != vp->v_mount) {
                    831:                error = EXDEV;
                    832:                VOP_ABORTOP(tdvp, cnp); 
                    833:                goto out2;
                    834:        }
                    835:        if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
                    836:                VOP_ABORTOP(tdvp, cnp);
                    837:                goto out2;
                    838:        }
                    839: 
                    840:        /*
                    841:         * Check we are doing legal things WRT the new flags
                    842:         */
                    843:        if (fp->dn_flags & (IMMUTABLE | APPEND)) {
                    844:                VOP_ABORTOP(tdvp, cnp);
                    845:                error = EPERM;
                    846:                goto out1;
                    847:        }
                    848: 
                    849:        /***********************************
                    850:         * Start actually doing things.... *
                    851:         ***********************************/
                    852:        fp->dn_flags |= DN_CHANGE;
                    853:        tv = time;
                    854:        error = VOP_UPDATE(vp, &tv, &tv, 1);
                    855:        if (!error) {
                    856:            DEVFS_LOCK(p);
                    857:            error = dev_add_name(cnp->cn_nameptr, tdp, NULL, fp, &tnp);
                    858:            DEVFS_UNLOCK(p);
                    859:        }
                    860: out1:
                    861:        if (tdvp != vp)
                    862:                VOP_UNLOCK(vp, 0, p);
                    863: out2:
                    864:        vput(tdvp);
                    865:        return (error);
                    866: }
                    867: 
                    868: /*
                    869:  * Check if source directory is in the path of the target directory.
                    870:  * Target is supplied locked, source is unlocked.
                    871:  * The target is always vput before returning.
                    872:  */
                    873: int
                    874: devfs_checkpath(source, target)
                    875:        devnode_t *source, *target;
                    876: {
                    877:     int error = 0;
                    878:     devnode_t * ntmp;
                    879:     devnode_t * tmp;
                    880:     struct vnode *vp;
                    881: 
                    882:     vp = target->dn_vn;
                    883:     tmp = target;
                    884: 
                    885:     do {
                    886:        if (tmp == source) {
                    887:            error = EINVAL;
                    888:            break;
                    889:        }
                    890:        ntmp = tmp;
                    891:     } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp);
                    892: 
                    893:     if (vp != NULL)
                    894:        vput(vp);
                    895:     return (error);
                    896: }
                    897: 
                    898: /*
                    899:  * Rename system call. Seems overly complicated to me...
                    900:  *     rename("foo", "bar");
                    901:  * is essentially
                    902:  *     unlink("bar");
                    903:  *     link("foo", "bar");
                    904:  *     unlink("foo");
                    905:  * but ``atomically''.
                    906:  *
                    907:  * When the target exists, both the directory
                    908:  * and target vnodes are locked.
                    909:  * the source and source-parent vnodes are referenced
                    910:  *
                    911:  *
                    912:  * Basic algorithm is:
                    913:  *
                    914:  * 1) Bump link count on source while we're linking it to the
                    915:  *    target.  This also ensure the inode won't be deleted out
                    916:  *    from underneath us while we work (it may be truncated by
                    917:  *    a concurrent `trunc' or `open' for creation).
                    918:  * 2) Link source to destination.  If destination already exists,
                    919:  *    delete it first.
                    920:  * 3) Unlink source reference to node if still around. If a
                    921:  *    directory was moved and the parent of the destination
                    922:  *    is different from the source, patch the ".." entry in the
                    923:  *    directory.
                    924:  */
                    925: static int
                    926: devfs_rename(struct vop_rename_args *ap)
                    927:         /*struct vop_rename_args  {
                    928:                 struct vnode *a_fdvp; 
                    929:                 struct vnode *a_fvp;  
                    930:                 struct componentname *a_fcnp;
                    931:                 struct vnode *a_tdvp;
                    932:                 struct vnode *a_tvp;
                    933:                 struct componentname *a_tcnp;
                    934:         } */
                    935: {
                    936:        struct vnode *tvp = ap->a_tvp;
                    937:        struct vnode *tdvp = ap->a_tdvp;
                    938:        struct vnode *fvp = ap->a_fvp;
                    939:        struct vnode *fdvp = ap->a_fdvp;
                    940:        struct componentname *tcnp = ap->a_tcnp;
                    941:        struct componentname *fcnp = ap->a_fcnp;
                    942:        struct proc *p = fcnp->cn_proc;
                    943:        devnode_t *fp, *fdp, *tp, *tdp;
                    944:        devdirent_t *fnp,*tnp;
                    945:        int doingdirectory = 0;
                    946:        int error = 0;
                    947:        struct timeval tv;
                    948: 
                    949:        /*
                    950:         * First catch an arbitrary restriction for this FS
                    951:         */
                    952:        if(tcnp->cn_namelen > DEVMAXNAMESIZE) {
                    953:                error = ENAMETOOLONG;
                    954:                goto abortit;
                    955:        }
                    956: 
                    957:        /*
                    958:         * Lock our directories and get our name pointers
                    959:         * assume that the names are null terminated as they
                    960:         * are the end of the path. Get pointers to all our
                    961:         * devfs structures.
                    962:         */
                    963:        tdp = VTODN(tdvp);
                    964:        fdp = VTODN(fdvp);
                    965:        fp = VTODN(fvp);
                    966:        fnp = fp->dn_last_lookup;
                    967:        tp = NULL;
                    968:        tnp = NULL;
                    969:        if (tvp) {
                    970:            tp = VTODN(tvp);
                    971:            tnp = tp->dn_last_lookup;
                    972:        }
                    973:        
                    974:        /*
                    975:         * trying to move it out of devfs?
                    976:          * if we move a dir across mnt points. we need to fix all
                    977:         * the mountpoint pointers! XXX
                    978:         * so for now keep dirs within the same mount
                    979:         */
                    980:        if ((fvp->v_mount != tdvp->v_mount) ||
                    981:            (tvp && (fvp->v_mount != tvp->v_mount))) {
                    982:                error = EXDEV;
                    983: abortit:
                    984:                VOP_ABORTOP(tdvp, tcnp); 
                    985:                if (tdvp == tvp) /* eh? */
                    986:                        vrele(tdvp);
                    987:                else
                    988:                        vput(tdvp);
                    989:                if (tvp)
                    990:                        vput(tvp);
                    991:                VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
                    992:                vrele(fdvp);
                    993:                vrele(fvp);
                    994:                return (error);
                    995:        }
                    996: 
                    997:        /*
                    998:         * Check we are doing legal things WRT the new flags
                    999:         */
                   1000:        if ((tp && (tp->dn_flags & (IMMUTABLE | APPEND)))
                   1001:          || (fp->dn_flags & (IMMUTABLE | APPEND))
                   1002:          || (fdp->dn_flags & APPEND)) {
                   1003:                error = EPERM;
                   1004:                goto abortit;
                   1005:        }
                   1006: 
                   1007:        /*
                   1008:         * Make sure that we don't try do something stupid
                   1009:         */
                   1010:        if ((fp->dn_type) == DEV_DIR) {
                   1011:                /*
                   1012:                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                   1013:                 */
                   1014:                if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') 
                   1015:                    || (fcnp->cn_flags&ISDOTDOT) 
                   1016:                    || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.') 
                   1017:                    || (tcnp->cn_flags&ISDOTDOT) 
                   1018:                    || (tdp == fp )) {
                   1019:                        error = EINVAL;
                   1020:                        goto abortit;
                   1021:                }
                   1022:                doingdirectory++;
                   1023:        }
                   1024: 
                   1025:        /*
                   1026:         * If ".." must be changed (ie the directory gets a new
                   1027:         * parent) then the source directory must not be in the
                   1028:         * directory hierarchy above the target, as this would
                   1029:         * orphan everything below the source directory. Also
                   1030:         * the user must have write permission in the source so
                   1031:         * as to be able to change "..". 
                   1032:         */
                   1033:        if (doingdirectory && (tdp != fdp)) {
                   1034:                devnode_t * tmp, *ntmp;
                   1035:                error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
                   1036:                tmp = tdp;
                   1037:                do {
                   1038:                        if(tmp == fp) {
                   1039:                                /* XXX unlock stuff here probably */
                   1040:                                error = EINVAL;
                   1041:                                goto out;
                   1042:                        }
                   1043:                        ntmp = tmp;
                   1044:                } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp);
                   1045:        }
                   1046: 
                   1047:        /***********************************
                   1048:         * Start actually doing things.... *
                   1049:         ***********************************/
                   1050:        fp->dn_flags |= DN_CHANGE;
                   1051:        tv = time;
                   1052:        if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) {
                   1053:            VOP_UNLOCK(fvp, 0, p);
                   1054:            goto bad;
                   1055:        }
                   1056:        /*
                   1057:         * Check if just deleting a link name.
                   1058:         */
                   1059:        if (fvp == tvp) {
                   1060:                if (fvp->v_type == VDIR) {
                   1061:                        error = EINVAL;
                   1062:                        goto abortit;
                   1063:                }
                   1064: 
                   1065:                /* Release destination completely. */
                   1066:                VOP_ABORTOP(tdvp, tcnp);
                   1067:                vput(tdvp);
                   1068:                vput(tvp);
                   1069: 
                   1070:                /* Delete source. */
                   1071:                VOP_ABORTOP(fdvp, fcnp); /*XXX*/
                   1072:                vrele(fdvp);
                   1073:                vrele(fvp);
                   1074:                dev_free_name(fnp);
                   1075:                return 0;
                   1076:        }
                   1077: 
                   1078:        vrele(fdvp);
                   1079: 
                   1080:        /*
                   1081:         * 1) Bump link count while we're moving stuff
                   1082:         *    around.  If we crash somewhere before
                   1083:         *    completing our work,  too bad :)
                   1084:         */
                   1085:        fp->dn_links++;
                   1086:        /*
                   1087:         * If the target exists zap it (unless it's a non-empty directory)
                   1088:         * We could do that as well but won't
                   1089:         */
                   1090:        if (tp) {
                   1091:                int ouruid = tcnp->cn_cred->cr_uid;
                   1092:                /*
                   1093:                 * If the parent directory is "sticky", then the user must
                   1094:                 * own the parent directory, or the destination of the rename,
                   1095:                 * otherwise the destination may not be changed (except by
                   1096:                 * root). This implements append-only directories.
                   1097:                 * XXX shoudn't this be in generic code? 
                   1098:                 */
                   1099:                if ((tdp->dn_mode & S_ISTXT)
                   1100:                  && ouruid != 0
                   1101:                  && ouruid != tdp->dn_uid
                   1102:                  && ouruid != tp->dn_uid ) {
                   1103:                        error = EPERM;
                   1104:                        goto bad;
                   1105:                }
                   1106:                /*
                   1107:                 * Target must be empty if a directory and have no links
                   1108:                 * to it. Also, ensure source and target are compatible
                   1109:                 * (both directories, or both not directories).
                   1110:                 */
                   1111:                if (( doingdirectory) && (tp->dn_links > 2)) {
                   1112:                                error = ENOTEMPTY;
                   1113:                                goto bad;
                   1114:                }
                   1115:                dev_free_name(tnp);
                   1116:                tp = NULL;
                   1117:        }
                   1118:        dev_add_name(tcnp->cn_nameptr,tdp,NULL,fp,&tnp);
                   1119:        fnp->de_dnp = NULL;
                   1120:        fp->dn_links--; /* one less link to it.. */
                   1121:        dev_free_name(fnp);
                   1122:        fp->dn_links--; /* we added one earlier*/
                   1123:        if (tdp)
                   1124:                vput(tdvp);
                   1125:        if (tp)
                   1126:                vput(fvp);
                   1127:        vrele(fvp);
                   1128:        return (error);
                   1129: 
                   1130: bad:
                   1131:        if (tp)
                   1132:                vput(tvp);
                   1133:        vput(tdvp);
                   1134: out:
                   1135:        if (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) {
                   1136:                fp->dn_links--; /* we added one earlier*/
                   1137:                vput(fvp);
                   1138:        } else
                   1139:                vrele(fvp);
                   1140:        return (error);
                   1141: }
                   1142: 
                   1143: static int
                   1144: devfs_symlink(struct vop_symlink_args *ap)
                   1145:         /*struct vop_symlink_args {
                   1146:                 struct vnode *a_dvp;
                   1147:                 struct vnode **a_vpp;
                   1148:                 struct componentname *a_cnp;
                   1149:                 struct vattr *a_vap;
                   1150:                 char *a_target;
                   1151:         } */
                   1152: {
                   1153:        struct componentname * cnp = ap->a_cnp;
                   1154:        struct vnode *vp = NULL;
                   1155:        int error = 0;
                   1156:        devnode_t * dir_p;
                   1157:        devnode_type_t typeinfo;
                   1158:        devdirent_t * nm_p;
                   1159:        devnode_t * dev_p;
                   1160:        struct vattr *  vap = ap->a_vap;
                   1161:        struct vnode * * vpp = ap->a_vpp;
                   1162:        struct proc *p = cnp->cn_proc;
                   1163:        struct timeval tv;
                   1164: 
                   1165:        dir_p = VTODN(ap->a_dvp);
                   1166:        typeinfo.Slnk.name = ap->a_target;
                   1167:        typeinfo.Slnk.namelen = strlen(ap->a_target);
                   1168:        DEVFS_LOCK(p);
                   1169:        error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK, 
                   1170:                              &typeinfo, NULL, NULL, &nm_p);
                   1171:        DEVFS_UNLOCK(p);
                   1172:        if (error) {
                   1173:            goto failure;
                   1174:        }
                   1175:        
                   1176:        dev_p = nm_p->de_dnp;
                   1177:        dev_p->dn_uid = dir_p->dn_uid;
                   1178:        dev_p->dn_gid = dir_p->dn_gid;
                   1179:        dev_p->dn_mode = vap->va_mode;
                   1180:        dn_copy_times(dev_p, dir_p);
                   1181:        error = devfs_dntovn(dev_p, vpp, p);
                   1182:        if (error)
                   1183:            goto failure;
                   1184:        vp = *vpp;
                   1185:        vput(vp);
                   1186:  failure:
                   1187:        if ((cnp->cn_flags & SAVESTART) == 0)
                   1188:            FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
                   1189:        vput(ap->a_dvp);
                   1190:        return error;
                   1191: }
                   1192: 
                   1193: /*
                   1194:  * Mknod vnode call
                   1195:  */
                   1196: /* ARGSUSED */
                   1197: int
                   1198: devfs_mknod(ap)
                   1199:        struct vop_mknod_args /* {
                   1200:                struct vnode *a_dvp;
                   1201:                struct vnode **a_vpp;
                   1202:                struct componentname *a_cnp;
                   1203:                struct vattr *a_vap;
                   1204:        } */ *ap;
                   1205: {
                   1206:        struct componentname * cnp = ap->a_cnp;
                   1207:        devnode_t *     dev_p;
                   1208:        devdirent_t *   devent;
                   1209:        devnode_t *     dir_p;  /* devnode for parent directory */
                   1210:        struct vnode *  dvp = ap->a_dvp;
                   1211:        int             error = 0;
                   1212:        devnode_type_t  typeinfo;
                   1213:        struct vattr *  vap = ap->a_vap;
                   1214:        struct vnode ** vpp = ap->a_vpp;
                   1215:        struct proc *   p = cnp->cn_proc;
                   1216: 
                   1217:        *vpp = NULL;
                   1218:        if (!vap->va_type == VBLK && !vap->va_type == VCHR) {
                   1219:            error = EINVAL; /* only support mknod of special files */
                   1220:            goto failure;
                   1221:        }
                   1222:        dir_p = VTODN(dvp);
                   1223:        typeinfo.dev = vap->va_rdev;
                   1224:        DEVFS_LOCK(p);
                   1225:        error = dev_add_entry(cnp->cn_nameptr, dir_p, 
                   1226:                              (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV,
                   1227:                              &typeinfo, NULL, NULL, &devent);
                   1228:        DEVFS_UNLOCK(p);
                   1229:        if (error) {
                   1230:            goto failure;
                   1231:        }
                   1232:        dev_p = devent->de_dnp;
                   1233:        error = devfs_dntovn(dev_p, vpp, p);
                   1234:        if (error)
                   1235:            goto failure;
                   1236:        dev_p->dn_uid = cnp->cn_cred->cr_uid;
                   1237:        dev_p->dn_gid = dir_p->dn_gid;
                   1238:        dev_p->dn_mode = vap->va_mode;
                   1239:  failure:
                   1240:        if (*vpp) {
                   1241:            vput(*vpp);
                   1242:            *vpp = 0;
                   1243:        }
                   1244:        if ((cnp->cn_flags & SAVESTART) == 0)
                   1245:            FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
                   1246:        vput(dvp);
                   1247:        return (error);
                   1248: }
                   1249: 
                   1250: /*
                   1251:  * Vnode op for readdir
                   1252:  */
                   1253: static int
                   1254: devfs_readdir(struct vop_readdir_args *ap)
                   1255:         /*struct vop_readdir_args {
                   1256:                 struct vnode *a_vp;
                   1257:                 struct uio *a_uio;
                   1258:                 struct ucred *a_cred;
                   1259:                int *eofflag;
                   1260:                int *ncookies;
                   1261:                u_int **cookies;
                   1262:         } */
                   1263: {
                   1264:        struct vnode *vp = ap->a_vp;
                   1265:        struct uio *uio = ap->a_uio;
                   1266:        struct dirent dirent;
                   1267:        devnode_t * dir_node;
                   1268:        devdirent_t *   name_node;
                   1269:        char    *name;
                   1270:        int error = 0;
                   1271:        int reclen;
                   1272:        int nodenumber;
                   1273:        int     startpos,pos;
                   1274:        struct proc *   p = uio->uio_procp;
                   1275: 
                   1276:        /*  set up refs to dir */
                   1277:        dir_node = VTODN(vp);
                   1278:        if(dir_node->dn_type != DEV_DIR)
                   1279:                return(ENOTDIR);
                   1280: 
                   1281:        pos = 0;
                   1282:        startpos = uio->uio_offset;
                   1283:        DEVFS_LOCK(p);
                   1284:        name_node = dir_node->dn_typeinfo.Dir.dirlist;
                   1285:        nodenumber = 0;
                   1286:        dir_node->dn_flags |= DN_ACCESS;
                   1287: 
                   1288:        while ((name_node || (nodenumber < 2)) && (uio->uio_resid > 0))
                   1289:        {
                   1290:                switch(nodenumber)
                   1291:                {
                   1292:                case    0:
                   1293:                        dirent.d_fileno = (int32_t)(void *)dir_node;
                   1294:                        name = ".";
                   1295:                        dirent.d_namlen = 1;
                   1296:                        dirent.d_type = DT_DIR;
                   1297:                        break;
                   1298:                case    1:
                   1299:                        if(dir_node->dn_typeinfo.Dir.parent)
                   1300:                            dirent.d_fileno
                   1301:                                = (int32_t)dir_node->dn_typeinfo.Dir.parent;
                   1302:                        else
                   1303:                                dirent.d_fileno = (u_int32_t)dir_node;
                   1304:                        name = "..";
                   1305:                        dirent.d_namlen = 2;
                   1306:                        dirent.d_type = DT_DIR;
                   1307:                        break;
                   1308:                default:
                   1309:                        dirent.d_fileno = (int32_t)(void *)name_node->de_dnp;
                   1310:                        dirent.d_namlen = strlen(name_node->de_name);
                   1311:                        name = name_node->de_name;
                   1312:                        switch(name_node->de_dnp->dn_type) {
                   1313:                        case DEV_BDEV:
                   1314:                                dirent.d_type = DT_BLK;
                   1315:                                break;
                   1316:                        case DEV_CDEV:
                   1317:                                dirent.d_type = DT_CHR;
                   1318:                                break;
                   1319:                        case DEV_DIR:
                   1320:                                dirent.d_type = DT_DIR;
                   1321:                                break;
                   1322:                        case DEV_SLNK:
                   1323:                                dirent.d_type = DT_LNK;
                   1324:                                break;
                   1325:                        default:
                   1326:                                dirent.d_type = DT_UNKNOWN;
                   1327:                        }
                   1328:                }
                   1329: #define        GENERIC_DIRSIZ(dp) \
                   1330:     ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
                   1331: 
                   1332:                reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent);
                   1333: 
                   1334:                if(pos >= startpos)     /* made it to the offset yet? */
                   1335:                {
                   1336:                        if (uio->uio_resid < reclen) /* will it fit? */
                   1337:                                break;
                   1338:                        strcpy( dirent.d_name,name);
                   1339:                        if ((error = uiomove ((caddr_t)&dirent,
                   1340:                                        dirent.d_reclen, uio)) != 0)
                   1341:                                break;
                   1342:                }
                   1343:                pos += reclen;
                   1344:                if((nodenumber >1) && name_node)
                   1345:                        name_node = name_node->de_next;
                   1346:                nodenumber++;
                   1347:        }
                   1348:        DEVFS_UNLOCK(p);
                   1349:        uio->uio_offset = pos;
                   1350: 
                   1351:        return (error);
                   1352: }
                   1353: 
                   1354: 
                   1355: /*
                   1356:  */
                   1357: static int
                   1358: devfs_readlink(struct vop_readlink_args *ap)
                   1359:         /*struct vop_readlink_args {
                   1360:                 struct vnode *a_vp;
                   1361:                 struct uio *a_uio;
                   1362:                 struct ucred *a_cred;
                   1363:         } */
                   1364: {
                   1365:        struct vnode *vp = ap->a_vp;
                   1366:        struct uio *uio = ap->a_uio;
                   1367:        devnode_t * lnk_node;
                   1368:        int error = 0;
                   1369: 
                   1370:        /*  set up refs to dir */
                   1371:        lnk_node = VTODN(vp);
                   1372:        if(lnk_node->dn_type != DEV_SLNK)
                   1373:                return(EINVAL);
                   1374:        if ((error = VOP_ACCESS(vp, VREAD, ap->a_cred, NULL)) != 0) { /* XXX */
                   1375:                return error;
                   1376:        }
                   1377:        error = uiomove(lnk_node->dn_typeinfo.Slnk.name, 
                   1378:                        lnk_node->dn_typeinfo.Slnk.namelen, uio);
                   1379:        return error;
                   1380: }
                   1381: 
                   1382: static int
                   1383: devfs_abortop(struct vop_abortop_args *ap)
                   1384:         /*struct vop_abortop_args {
                   1385:                 struct vnode *a_dvp;
                   1386:                 struct componentname *a_cnp;
                   1387:         } */
                   1388: {
                   1389:        if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
                   1390:                FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
                   1391:        }
                   1392:        return 0;
                   1393: }
                   1394: 
                   1395: 
                   1396: static int
                   1397: devfs_reclaim(struct vop_reclaim_args *ap)
                   1398:         /*struct vop_reclaim_args {
                   1399:                struct vnode *a_vp;
                   1400:         } */
                   1401: {
                   1402:     struct vnode *     vp = ap->a_vp;
                   1403:     devnode_t *        dnp = VTODN(vp);
                   1404:     
                   1405:     if (dnp) {
                   1406:        /* 
                   1407:         * do the same as devfs_inactive in case it is not called
                   1408:         * before us (can that ever happen?)
                   1409:         */
                   1410:        dnp->dn_vn = NULL;
                   1411:        vp->v_data = NULL;
                   1412:        if (dnp->dn_delete) {
                   1413:            devnode_free(dnp);
                   1414:        }
                   1415:     }
                   1416:     return(0);
                   1417: }
                   1418: 
                   1419: /*
                   1420:  * Print out the contents of a /devfs vnode.
                   1421:  */
                   1422: static int
                   1423: devfs_print(struct vop_print_args *ap)
                   1424:        /*struct vop_print_args {
                   1425:                struct vnode *a_vp;
                   1426:        } */
                   1427: {
                   1428: 
                   1429:        return (0);
                   1430: }
                   1431: 
                   1432: /**************************************************************************\
                   1433: * pseudo ops *
                   1434: \**************************************************************************/
                   1435: 
                   1436: /*
                   1437:  *
                   1438:  *     struct vop_inactive_args {
                   1439:  *             struct vnode *a_vp;
                   1440:  *             struct proc *a_p;
                   1441:  *     } 
                   1442:  */
                   1443: 
                   1444: static int
                   1445: devfs_inactive(struct vop_inactive_args *ap)
                   1446: {
                   1447:     struct vnode *     vp = ap->a_vp;
                   1448:     devnode_t *        dnp = VTODN(vp);
                   1449:     
                   1450:     if (dnp) {
                   1451:        dnp->dn_vn = NULL;
                   1452:        vp->v_data = NULL;
                   1453:        if (dnp->dn_delete) {
                   1454:            devnode_free(dnp);
                   1455:        }
                   1456:     }
                   1457:     VOP_UNLOCK(vp, 0, ap->a_p);
                   1458:     return (0);
                   1459: }
                   1460: 
                   1461: int
                   1462: devfs_update(ap)
                   1463:        struct vop_update_args /* {
                   1464:                struct vnode *a_vp;
                   1465:                struct timeval *a_access;
                   1466:                struct timeval *a_modify;
                   1467:                int a_waitfor;
                   1468:        } */ *ap;
                   1469: {
                   1470:        register struct fs *fs;
                   1471:        int error;
                   1472:        devnode_t * ip;
                   1473: 
                   1474:        ip = VTODN(ap->a_vp);
                   1475:        if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) {
                   1476:                ip->dn_flags &=
                   1477:                    ~(DN_ACCESS | DN_CHANGE | DN_MODIFIED | DN_UPDATE);
                   1478:                return (0);
                   1479:        }
                   1480:        if ((ip->dn_flags &
                   1481:            (DN_ACCESS | DN_CHANGE | DN_MODIFIED | DN_UPDATE)) == 0)
                   1482:                return (0);
                   1483:        dn_times(ip, time, time);
                   1484:        return (0);
                   1485: }
                   1486: 
                   1487: /* The following ops are used by directories and symlinks */
                   1488: int (**devfs_vnodeop_p)();
                   1489: static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
                   1490:        { &vop_default_desc, vn_default_error },
                   1491:        { &vop_lookup_desc, devfs_lookup },             /* lookup */
                   1492:        { &vop_create_desc, err_create },               /* create */
                   1493:        { &vop_whiteout_desc, err_whiteout },           /* whiteout */
                   1494:        { &vop_mknod_desc, devfs_mknod },               /* mknod */
                   1495:        { &vop_open_desc, nop_open },                   /* open */
                   1496:        { &vop_close_desc, devfs_close },               /* close */
                   1497:        { &vop_access_desc, devfs_access },             /* access */
                   1498:        { &vop_getattr_desc, devfs_getattr },           /* getattr */
                   1499:        { &vop_setattr_desc, devfs_setattr },           /* setattr */
                   1500:        { &vop_read_desc, devfs_read },                 /* read */
                   1501:        { &vop_write_desc, devfs_write },               /* write */
                   1502:        { &vop_lease_desc, nop_lease },                 /* lease */
                   1503:        { &vop_ioctl_desc, err_ioctl },                 /* ioctl */
                   1504:        { &vop_select_desc, err_select },               /* select */
                   1505:        { &vop_revoke_desc, err_revoke },               /* revoke */
                   1506:        { &vop_mmap_desc, err_mmap },                   /* mmap */
                   1507:        { &vop_fsync_desc, nop_fsync },                 /* fsync */
                   1508:        { &vop_seek_desc, err_seek },                   /* seek */
                   1509:        { &vop_remove_desc, devfs_remove },             /* remove */
                   1510:        { &vop_link_desc, devfs_link },                 /* link */
                   1511:        { &vop_rename_desc, devfs_rename },             /* rename */
                   1512:        { &vop_mkdir_desc, err_mkdir },                 /* mkdir */
                   1513:        { &vop_rmdir_desc, err_rmdir },                 /* rmdir */
                   1514:        { &vop_symlink_desc, devfs_symlink },           /* symlink */
                   1515:        { &vop_readdir_desc, devfs_readdir },           /* readdir */
                   1516:        { &vop_readlink_desc, devfs_readlink },         /* readlink */
                   1517:        { &vop_abortop_desc, devfs_abortop },           /* abortop */
                   1518:        { &vop_inactive_desc, devfs_inactive },         /* inactive */
                   1519:        { &vop_reclaim_desc, devfs_reclaim },           /* reclaim */
                   1520:        { &vop_lock_desc, nop_lock },                   /* lock */
                   1521:        { &vop_unlock_desc, nop_unlock },               /* unlock */
                   1522:        { &vop_bmap_desc, err_bmap },                   /* bmap */
                   1523:        { &vop_strategy_desc, err_strategy },           /* strategy */
                   1524:        { &vop_print_desc, err_print },                 /* print */
                   1525:        { &vop_islocked_desc, nop_islocked },           /* islocked */
                   1526:        { &vop_pathconf_desc, err_pathconf },           /* pathconf */
                   1527:        { &vop_advlock_desc, err_advlock },             /* advlock */
                   1528:        { &vop_blkatoff_desc, err_blkatoff },           /* blkatoff */
                   1529:        { &vop_valloc_desc, err_valloc },               /* valloc */
                   1530:        { &vop_reallocblks_desc, err_reallocblks },     /* reallocblks */
                   1531:        { &vop_vfree_desc, err_vfree },                 /* vfree */
                   1532:        { &vop_truncate_desc, err_truncate },           /* truncate */
                   1533:        { &vop_update_desc, devfs_update },             /* update */
                   1534:        { &vop_bwrite_desc, err_bwrite },
                   1535:        { &vop_pagein_desc, err_pagein },               /* Pagein */
                   1536:        { &vop_pageout_desc, err_pageout },             /* Pageout */
                   1537:        { &vop_copyfile_desc, err_copyfile },           /* Copyfile */
                   1538:        { (struct vnodeop_desc*)NULL, (int(*)())NULL }
                   1539: };
                   1540: struct vnodeopv_desc devfs_vnodeop_opv_desc =
                   1541:        { &devfs_vnodeop_p, devfs_vnodeop_entries };
                   1542: 
                   1543: /* The following ops are used by the device nodes */
                   1544: int (**devfs_spec_vnodeop_p)();
                   1545: static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = {
                   1546:        { &vop_default_desc, vn_default_error },
                   1547:        { &vop_lookup_desc, spec_lookup },              /* lookup */
                   1548:        { &vop_create_desc, spec_create },              /* create */
                   1549:        { &vop_mknod_desc, spec_mknod },                /* mknod */
                   1550:        { &vop_open_desc, spec_open },                  /* open */
                   1551:        { &vop_close_desc, devfsspec_close },           /* close */
                   1552:        { &vop_access_desc, devfs_access },             /* access */
                   1553:        { &vop_getattr_desc, devfs_getattr },           /* getattr */
                   1554:        { &vop_setattr_desc, devfs_setattr },           /* setattr */
                   1555:        { &vop_read_desc, devfsspec_read },             /* read */
                   1556:        { &vop_write_desc, devfsspec_write },           /* write */
                   1557:        { &vop_lease_desc, spec_lease_check },          /* lease */
                   1558:        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
                   1559:        { &vop_select_desc, spec_select },              /* select */
                   1560:        { &vop_revoke_desc, spec_revoke },              /* revoke */
                   1561:        { &vop_mmap_desc, spec_mmap },                  /* mmap */
                   1562:        { &vop_fsync_desc, spec_fsync },                /* fsync */
                   1563:        { &vop_seek_desc, spec_seek },                  /* seek */
                   1564:        { &vop_remove_desc, devfs_remove },             /* remove */
                   1565:        { &vop_link_desc, devfs_link },                 /* link */
                   1566:        { &vop_rename_desc, spec_rename },              /* rename */
                   1567:        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
                   1568:        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
                   1569:        { &vop_symlink_desc, spec_symlink },            /* symlink */
                   1570:        { &vop_readdir_desc, spec_readdir },            /* readdir */
                   1571:        { &vop_readlink_desc, spec_readlink },          /* readlink */
                   1572:        { &vop_abortop_desc, spec_abortop },            /* abortop */
                   1573:        { &vop_inactive_desc, devfs_inactive },         /* inactive */
                   1574:        { &vop_reclaim_desc, devfs_reclaim },           /* reclaim */
                   1575:        { &vop_lock_desc, nop_lock },                   /* lock */
                   1576:        { &vop_unlock_desc, nop_unlock },               /* unlock */
                   1577:        { &vop_bmap_desc, spec_bmap },                  /* bmap */
                   1578:        { &vop_strategy_desc, spec_strategy },          /* strategy */
                   1579:        { &vop_print_desc, devfs_print },               /* print */
                   1580:        { &vop_islocked_desc, nop_islocked },           /* islocked */
                   1581:        { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
                   1582:        { &vop_advlock_desc, spec_advlock },            /* advlock */
                   1583:        { &vop_blkatoff_desc, spec_blkatoff },          /* blkatoff */
                   1584:        { &vop_valloc_desc, spec_valloc },              /* valloc */
                   1585:        { &vop_reallocblks_desc, spec_reallocblks },    /* reallocblks */
                   1586:        { &vop_vfree_desc, nop_vfree },                 /* vfree */
                   1587:        { &vop_truncate_desc, spec_truncate },          /* truncate */
                   1588:        { &vop_update_desc, devfs_update },             /* update */
                   1589:        { &vop_bwrite_desc, vn_bwrite },
                   1590: #ifdef NeXT
                   1591:        { &vop_devblocksize_desc, spec_devblocksize },  /* devblocksize */
                   1592: #endif /* NeXT */
                   1593:        { &vop_pagein_desc, spec_pagein },              /* Pagein */
                   1594:        { &vop_pageout_desc, spec_pageout },            /* Pageout */
                   1595:        { &vop_copyfile_desc, err_copyfile },           /* Copyfile */
                   1596:        { (struct vnodeop_desc*)NULL, (int(*)())NULL }
                   1597: };
                   1598: struct vnodeopv_desc devfs_spec_vnodeop_opv_desc =
                   1599:        { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries };
                   1600: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.