2  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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. 
  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 
  20  * @APPLE_LICENSE_HEADER_END@ 
  23  * Copyright 1997,1998 Julian Elischer.  All rights reserved. 
  26  * Redistribution and use in source and binary forms, with or without 
  27  * modification, are permitted provided that the following conditions are 
  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. 
  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 
  52  *  Clark Warner (warner_c@apple.com) Tue Feb 10 2000 
  53  *  - Added err_copyfile to the vnode operations table 
  54  *  Dieter Siegmund (dieter@apple.com) 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 (dieter@apple.com) 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 (dieter@apple.com) Fri Sep 17 09:58:38 PDT 1999 
  67  *  - update the mod/access times 
  70 #include <sys/param.h> 
  71 #include <sys/systm.h> 
  72 #include <sys/namei.h> 
  73 #include <sys/kernel.h> 
  74 #include <sys/fcntl.h> 
  76 #include <sys/disklabel.h> 
  79 #include <sys/mount_internal.h> 
  81 #include <sys/kauth.h> 
  83 #include <sys/vnode_internal.h> 
  84 #include <miscfs/specfs/specdev.h> 
  85 #include <sys/dirent.h> 
  86 #include <sys/vmmeter.h> 
  88 #include <sys/uio_internal.h> 
  90 #include "devfsdefs.h" 
  92 static int devfs_update(struct vnode 
*vp
, struct timeval 
*access
, 
  93                         struct timeval 
*modify
); 
  97  * Convert a component of a pathname into a pointer to a locked node. 
  98  * This is a very central and rather complicated routine. 
  99  * If the file system is not maintained in a strict tree hierarchy, 
 100  * this can result in a deadlock situation (see comments in code below). 
 102  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 
 103  * whether the name is to be looked up, created, renamed, or deleted. 
 104  * When CREATE, RENAME, or DELETE is specified, information usable in 
 105  * creating, renaming, or deleting a directory entry may be calculated. 
 106  * If flag has LOCKPARENT or'ed into it and the target of the pathname 
 107  * exists, lookup returns both the target and its parent directory locked. 
 108  * When creating or renaming and LOCKPARENT is specified, the target may 
 109  * not be ".".  When deleting and LOCKPARENT is specified, the target may 
 110  * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK 
 111  * instead of two DNUNLOCKs. 
 113  * Overall outline of devfs_lookup: 
 115  *      check accessibility of directory 
 116  *      null terminate the component (lookup leaves the whole string alone) 
 117  *      look for name in cache, if found, then if at end of path 
 118  *        and deleting or creating, drop it, else return name 
 119  *      search for name in directory, to found or notfound 
 121  *      if creating, return locked directory, 
 124  *      if at end of path and deleting, return information to allow delete 
 125  *      if at end of path and rewriting (RENAME and LOCKPARENT), lock target 
 126  *        node and return info to allow rewrite 
 127  *      if not at end, add name to cache; if at end and neither creating 
 128  *        nor deleting, add name to cache 
 129  * On return to lookup, remove the null termination we put in at the start. 
 131  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked. 
 134 devfs_lookup(struct vnop_lookup_args 
*ap
) 
 135         /*struct vnop_lookup_args { 
 136                 struct vnode * a_dvp; directory vnode ptr 
 137                 struct vnode ** a_vpp; where to put the result 
 138                 struct componentname * a_cnp; the name we want 
 139                 vfs_context_t a_context; 
 142         struct componentname 
*cnp 
= ap
->a_cnp
; 
 143         vfs_context_t ctx 
= cnp
->cn_context
; 
 144         struct proc 
*p 
= vfs_context_proc(ctx
); 
 145         struct vnode 
*dir_vnode 
= ap
->a_dvp
; 
 146         struct vnode 
**result_vnode 
= ap
->a_vpp
; 
 147         devnode_t 
*   dir_node
;       /* the directory we are searching */ 
 148         devnode_t 
*   node 
= NULL
;       /* the node we are searching for */ 
 149         devdirent_t 
* nodename
; 
 150         int flags 
= cnp
->cn_flags
; 
 151         int op 
= cnp
->cn_nameiop
;       /* LOOKUP, CREATE, RENAME, or DELETE */ 
 152         int wantparent 
= flags 
& (LOCKPARENT
|WANTPARENT
); 
 154         char    heldchar
;       /* the char at the end of the name componet */ 
 158         *result_vnode 
= NULL
; /* safe not sorry */ /*XXX*/ 
 160         //if (dir_vnode->v_usecount == 0) 
 161             //printf("devfs_lookup: dir had no refs "); 
 162         dir_node 
= VTODN(dir_vnode
); 
 165          * Make sure that our node is a directory as well. 
 167         if (dir_node
->dn_type 
!= DEV_DIR
) { 
 173          * temporarily terminate string component 
 175         heldchar 
= cnp
->cn_nameptr
[cnp
->cn_namelen
]; 
 176         cnp
->cn_nameptr
[cnp
->cn_namelen
] = '\0'; 
 178         nodename 
= dev_findname(dir_node
, cnp
->cn_nameptr
); 
 180          * restore saved character 
 182         cnp
->cn_nameptr
[cnp
->cn_namelen
] = heldchar
; 
 186                 node 
= nodename
->de_dnp
; 
 188                 /* Do potential vnode allocation here inside the lock  
 189                  * to make sure that our device node has a non-NULL dn_vn 
 190                  * associated with it.  The device node might otherwise 
 191                  * get deleted out from under us (see devfs_dn_free()). 
 193                 error 
= devfs_dntovn(node
, result_vnode
, p
); 
 204                  * we haven't called devfs_dntovn if we get here 
 205                  * we have not taken a reference on the node.. no 
 206                  * vnode_put is necessary on these error returns 
 208                  * If it doesn't exist and we're not the last component, 
 209                  * or we're at the last component, but we're not creating 
 210                  * or renaming, return ENOENT. 
 212                 if (!(flags 
& ISLASTCN
) || !(op 
== CREATE 
|| op 
== RENAME
)) { 
 216                  * We return with the directory locked, so that 
 217                  * the parameters we set up above will still be 
 218                  * valid if we actually decide to add a new entry. 
 219                  * We return ni_vp == NULL to indicate that the entry 
 220                  * does not currently exist; we leave a pointer to 
 221                  * the (locked) directory vnode in namei_data->ni_dvp. 
 223                  * NB - if the directory is unlocked, then this 
 224                  * information cannot be used. 
 226                 return (EJUSTRETURN
); 
 229          * from this point forward, we need to vnode_put the reference 
 230          * picked up in devfs_dntovn if we decide to return an error 
 234          * If deleting, and at end of pathname, return 
 235          * parameters which can be used to remove file. 
 236          * If the wantparent flag isn't set, we return only 
 237          * the directory (in namei_data->ni_dvp), otherwise we go 
 238          * on and lock the node, being careful with ".". 
 240         if (op 
== DELETE 
&& (flags 
& ISLASTCN
)) { 
 243                  * we are trying to delete '.'.  What does this mean? XXX 
 245                 if (dir_node 
== node
) { 
 247                                 vnode_put(*result_vnode
); 
 248                                 *result_vnode 
= NULL
; 
 250                         if ( ((error 
= vnode_get(dir_vnode
)) == 0) ) { 
 251                                 *result_vnode 
= dir_vnode
; 
 259          * If rewriting (RENAME), return the vnode and the 
 260          * information required to rewrite the present directory 
 261          * Must get node of directory entry to verify it's a 
 262          * regular file, or empty directory. 
 264         if (op 
== RENAME 
&& wantparent 
&& (flags 
& ISLASTCN
)) { 
 267                  * Careful about locking second node. 
 268                  * This can only occur if the target is ".". 
 270                 if (dir_node 
== node
) { 
 278          * Step through the translation in the name.  We do not unlock the 
 279          * directory because we may need it again if a symbolic link 
 280          * is relative to the current directory.  Instead we save it 
 281          * unlocked as "saved_dir_node" XXX.  We must get the target 
 282          * node before unlocking 
 283          * the directory to insure that the node will not be removed 
 284          * before we get it.  We prevent deadlock by always fetching 
 285          * nodes from the root, moving down the directory tree. Thus 
 286          * when following backward pointers ".." we must unlock the 
 287          * parent directory before getting the requested directory. 
 288          * There is a potential race condition here if both the current 
 289          * and parent directories are removed before the lock for the 
 290          * node associated with ".." returns.  We hope that this occurs 
 291          * infrequently since we cannot avoid this race condition without 
 292          * implementing a sophisticated deadlock detection algorithm. 
 293          * Note also that this simple deadlock detection scheme will not 
 294          * work if the file system has any hard links other than ".." 
 295          * that point backwards in the directory structure. 
 297         if ((flags 
& ISDOTDOT
) == 0 && dir_node 
== node
) { 
 299                         vnode_put(*result_vnode
); 
 300                         *result_vnode 
= NULL
; 
 302                 if ( (error 
= vnode_get(dir_vnode
)) ) { 
 305                 *result_vnode 
= dir_vnode
; 
 311                 vnode_put(*result_vnode
); 
 312                 *result_vnode 
= NULL
; 
 318 devfs_getattr(struct vnop_getattr_args 
*ap
) 
 319         /*struct vnop_getattr_args { 
 321                 struct vnode_attr *a_vap; 
 326         struct vnode 
*vp 
= ap
->a_vp
; 
 327         struct vnode_attr 
*vap 
= ap
->a_vap
; 
 328         devnode_t 
*     file_node
; 
 331         file_node 
= VTODN(vp
); 
 336         dn_times(file_node
, &now
, &now
, &now
); 
 338         VATTR_RETURN(vap
, va_mode
, file_node
->dn_mode
); 
 340         switch (file_node
->dn_type
) 
 343                 VATTR_RETURN(vap
, va_rdev
,  (dev_t
)file_node
->dn_dvm
); 
 344                 vap
->va_mode 
|= (S_IFDIR
); 
 347                 VATTR_RETURN(vap
, va_rdev
, file_node
->dn_typeinfo
.dev
); 
 348                 vap
->va_mode 
|= (S_IFCHR
); 
 351                 VATTR_RETURN(vap
, va_rdev
, file_node
->dn_typeinfo
.dev
); 
 352                 vap
->va_mode 
|= (S_IFBLK
); 
 355                 VATTR_RETURN(vap
, va_rdev
, 0); 
 356                 vap
->va_mode 
|= (S_IFLNK
); 
 359                 VATTR_RETURN(vap
, va_rdev
, 0);  /* default value only */ 
 361         VATTR_RETURN(vap
, va_type
, vp
->v_type
); 
 362         VATTR_RETURN(vap
, va_nlink
, file_node
->dn_links
); 
 363         VATTR_RETURN(vap
, va_uid
, file_node
->dn_uid
); 
 364         VATTR_RETURN(vap
, va_gid
, file_node
->dn_gid
); 
 365         VATTR_RETURN(vap
, va_fsid
, (uintptr_t)file_node
->dn_dvm
); 
 366         VATTR_RETURN(vap
, va_fileid
, (uintptr_t)file_node
); 
 367         VATTR_RETURN(vap
, va_data_size
, file_node
->dn_len
); 
 369         /* return an override block size (advisory) */ 
 370         if (vp
->v_type 
== VBLK
) 
 371                 VATTR_RETURN(vap
, va_iosize
, BLKDEV_IOSIZE
); 
 372         else if (vp
->v_type 
== VCHR
) 
 373                 VATTR_RETURN(vap
, va_iosize
, MAXPHYSIO
); 
 375                 VATTR_RETURN(vap
, va_iosize
, vp
->v_mount
->mnt_vfsstat
.f_iosize
); 
 376         /* if the time is bogus, set it to the boot time */ 
 377         if (file_node
->dn_ctime
.tv_sec 
== 0) { 
 378                 file_node
->dn_ctime
.tv_sec 
= boottime_sec(); 
 379                 file_node
->dn_ctime
.tv_nsec 
= 0; 
 381         if (file_node
->dn_mtime
.tv_sec 
== 0) 
 382             file_node
->dn_mtime 
= file_node
->dn_ctime
; 
 383         if (file_node
->dn_atime
.tv_sec 
== 0) 
 384             file_node
->dn_atime 
= file_node
->dn_ctime
; 
 385         VATTR_RETURN(vap
, va_change_time
, file_node
->dn_ctime
); 
 386         VATTR_RETURN(vap
, va_modify_time
, file_node
->dn_mtime
); 
 387         VATTR_RETURN(vap
, va_access_time
, file_node
->dn_atime
); 
 388         VATTR_RETURN(vap
, va_gen
, 0); 
 389         VATTR_RETURN(vap
, va_flags
, 0); 
 390         VATTR_RETURN(vap
, va_filerev
, 0); 
 391         VATTR_RETURN(vap
, va_acl
, NULL
); 
 399 devfs_setattr(struct vnop_setattr_args 
*ap
) 
 400         /*struct vnop_setattr_args  { 
 402           struct vnode_attr *a_vap; 
 403           vfs_context_t a_context; 
 406         struct vnode 
*vp 
= ap
->a_vp
; 
 407         struct vnode_attr 
*vap 
= ap
->a_vap
; 
 408         kauth_cred_t cred 
= vfs_context_ucred(ap
->a_context
); 
 409         struct proc 
*p 
= vfs_context_proc(ap
->a_context
); 
 411         devnode_t 
*     file_node
; 
 412         struct timeval atimeval
, mtimeval
; 
 414         file_node 
= VTODN(vp
); 
 418          * Go through the fields and update if set. 
 420         if (VATTR_IS_ACTIVE(vap
, va_access_time
) || VATTR_IS_ACTIVE(vap
, va_modify_time
)) { 
 423                 if (VATTR_IS_ACTIVE(vap
, va_access_time
)) 
 424                         file_node
->dn_access 
= 1; 
 425                 if (VATTR_IS_ACTIVE(vap
, va_modify_time
)) { 
 426                         file_node
->dn_change 
= 1; 
 427                         file_node
->dn_update 
= 1; 
 429                 atimeval
.tv_sec 
= vap
->va_access_time
.tv_sec
; 
 430                 atimeval
.tv_usec 
= vap
->va_access_time
.tv_nsec 
/ 1000; 
 431                 mtimeval
.tv_sec 
= vap
->va_modify_time
.tv_sec
; 
 432                 mtimeval
.tv_usec 
= vap
->va_modify_time
.tv_nsec 
/ 1000; 
 434                 if ( (error 
= devfs_update(vp
, &atimeval
, &mtimeval
)) ) 
 437         VATTR_SET_SUPPORTED(vap
, va_access_time
); 
 438         VATTR_SET_SUPPORTED(vap
, va_change_time
); 
 441          * Change the permissions. 
 443         if (VATTR_IS_ACTIVE(vap
, va_mode
)) { 
 444                 file_node
->dn_mode 
&= ~07777; 
 445                 file_node
->dn_mode 
|= vap
->va_mode 
& 07777; 
 447         VATTR_SET_SUPPORTED(vap
, va_mode
); 
 452         if (VATTR_IS_ACTIVE(vap
, va_uid
)) 
 453                 file_node
->dn_uid 
= vap
->va_uid
; 
 454         VATTR_SET_SUPPORTED(vap
, va_uid
); 
 459         if (VATTR_IS_ACTIVE(vap
, va_gid
)) 
 460                 file_node
->dn_gid 
= vap
->va_gid
; 
 461         VATTR_SET_SUPPORTED(vap
, va_gid
); 
 469 devfs_read(struct vnop_read_args 
*ap
) 
 470         /* struct vnop_read_args { 
 474                 vfs_context_t a_context; 
 477         devnode_t 
* dn_p 
= VTODN(ap
->a_vp
); 
 479         switch (ap
->a_vp
->v_type
) { 
 483               return VNOP_READDIR(ap
->a_vp
, ap
->a_uio
, 0, NULL
, NULL
, ap
->a_context
); 
 486               printf("devfs_read(): bad file type %d", ap
->a_vp
->v_type
); 
 491         return (0); /* not reached */ 
 495 devfs_close(struct vnop_close_args 
*ap
) 
 496         /* struct vnop_close_args { 
 499                 vfs_context_t a_context; 
 502         struct vnode 
*          vp 
= ap
->a_vp
; 
 503         register devnode_t 
*    dnp 
= VTODN(vp
); 
 506         if (vnode_isinuse(vp
, 1)) { 
 509             dn_times(dnp
, &now
, &now
, &now
); 
 516 devfsspec_close(struct vnop_close_args 
*ap
) 
 517         /* struct vnop_close_args { 
 520                 vfs_context_t a_context; 
 523         struct vnode 
*          vp 
= ap
->a_vp
; 
 524         register devnode_t 
*    dnp 
= VTODN(vp
); 
 527         if (vnode_isinuse(vp
, 1)) { 
 530             dn_times(dnp
, &now
, &now
, &now
); 
 533         return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_close
), ap
)); 
 537 devfsspec_read(struct vnop_read_args 
*ap
) 
 538         /* struct vnop_read_args { 
 545         register devnode_t 
*    dnp 
= VTODN(ap
->a_vp
); 
 549         return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_read
), ap
)); 
 553 devfsspec_write(struct vnop_write_args 
*ap
) 
 554         /* struct vnop_write_args  { 
 558                 vfs_context_t a_context; 
 561         register devnode_t 
*    dnp 
= VTODN(ap
->a_vp
); 
 566         return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_write
), ap
)); 
 570  *  Write data to a file or directory. 
 573 devfs_write(struct vnop_write_args 
*ap
) 
 574         /* struct vnop_write_args  { 
 581         switch (ap
->a_vp
->v_type
) { 
 585                 printf("devfs_write(): bad file type %d", ap
->a_vp
->v_type
); 
 588         return 0; /* not reached */ 
 592 devfs_remove(struct vnop_remove_args 
*ap
) 
 593         /* struct vnop_remove_args  { 
 596                 struct componentname *a_cnp; 
 599         struct vnode 
*vp 
= ap
->a_vp
; 
 600         struct vnode 
*dvp 
= ap
->a_dvp
; 
 601         struct componentname 
*cnp 
= ap
->a_cnp
; 
 602         vfs_context_t ctx 
= cnp
->cn_context
; 
 606         int doingdirectory 
= 0; 
 608         uid_t ouruid 
= kauth_cred_getuid(vfs_context_ucred(ctx
)); 
 611          * assume that the name is null terminated as they 
 612          * are the end of the path. Get pointers to all our 
 620         tnp 
= dev_findname(tdp
, cnp
->cn_nameptr
); 
 628          * Make sure that we don't try do something stupid 
 630         if ((tp
->dn_type
) == DEV_DIR
) { 
 632                  * Avoid ".", "..", and aliases of "." for obvious reasons. 
 634                 if ( (cnp
->cn_namelen 
== 1 && cnp
->cn_nameptr
[0] == '.')  
 635                     || (cnp
->cn_flags
&ISDOTDOT
) ) { 
 642         /*********************************** 
 643          * Start actually doing things.... * 
 644          ***********************************/ 
 649          * Target must be empty if a directory and have no links 
 650          * to it. Also, ensure source and target are compatible 
 651          * (both directories, or both not directories). 
 653         if (( doingdirectory
) && (tp
->dn_links 
> 2)) { 
 667 devfs_link(struct vnop_link_args 
*ap
) 
 668         /*struct vnop_link_args  { 
 669                 struct vnode *a_tdvp; 
 671                 struct componentname *a_cnp; 
 672                 vfs_context_t a_context; 
 675         struct vnode 
*vp 
= ap
->a_vp
; 
 676         struct vnode 
*tdvp 
= ap
->a_tdvp
; 
 677         struct componentname 
*cnp 
= ap
->a_cnp
; 
 685          * First catch an arbitrary restriction for this FS 
 687         if (cnp
->cn_namelen 
> DEVMAXNAMESIZE
) { 
 688                 error 
= ENAMETOOLONG
; 
 693          * Lock our directories and get our name pointers 
 694          * assume that the names are null terminated as they 
 695          * are the end of the path. Get pointers to all our 
 701         if (tdvp
->v_mount 
!= vp
->v_mount
) { 
 707         /*********************************** 
 708          * Start actually doing things.... * 
 709          ***********************************/ 
 713         error 
= devfs_update(vp
, &now
, &now
); 
 716             error 
= dev_add_name(cnp
->cn_nameptr
, tdp
, NULL
, fp
, &tnp
); 
 725  * Rename system call. Seems overly complicated to me... 
 726  *      rename("foo", "bar"); 
 729  *      link("foo", "bar"); 
 731  * but ``atomically''. 
 733  * When the target exists, both the directory 
 734  * and target vnodes are locked. 
 735  * the source and source-parent vnodes are referenced 
 738  * Basic algorithm is: 
 740  * 1) Bump link count on source while we're linking it to the 
 741  *    target.  This also ensure the inode won't be deleted out 
 742  *    from underneath us while we work (it may be truncated by 
 743  *    a concurrent `trunc' or `open' for creation). 
 744  * 2) Link source to destination.  If destination already exists, 
 746  * 3) Unlink source reference to node if still around. If a 
 747  *    directory was moved and the parent of the destination 
 748  *    is different from the source, patch the ".." entry in the 
 752 devfs_rename(struct vnop_rename_args 
*ap
) 
 753         /*struct vnop_rename_args  { 
 754                 struct vnode *a_fdvp;  
 756                 struct componentname *a_fcnp; 
 757                 struct vnode *a_tdvp; 
 759                 struct componentname *a_tcnp; 
 760                 vfs_context_t a_context; 
 763         struct vnode 
*tvp 
= ap
->a_tvp
; 
 764         struct vnode 
*tdvp 
= ap
->a_tdvp
; 
 765         struct vnode 
*fvp 
= ap
->a_fvp
; 
 766         struct vnode 
*fdvp 
= ap
->a_fdvp
; 
 767         struct componentname 
*tcnp 
= ap
->a_tcnp
; 
 768         struct componentname 
*fcnp 
= ap
->a_fcnp
; 
 769         devnode_t 
*fp
, *fdp
, *tp
, *tdp
; 
 770         devdirent_t 
*fnp
,*tnp
; 
 771         int doingdirectory 
= 0; 
 777          * First catch an arbitrary restriction for this FS 
 779         if (tcnp
->cn_namelen 
> DEVMAXNAMESIZE
) { 
 780                 error 
= ENAMETOOLONG
; 
 785          * assume that the names are null terminated as they 
 786          * are the end of the path. Get pointers to all our 
 793         fnp 
= dev_findname(fdp
, fcnp
->cn_nameptr
); 
 803                 tnp 
= dev_findname(tdp
, tcnp
->cn_nameptr
); 
 813          * Make sure that we don't try do something stupid 
 815         if ((fp
->dn_type
) == DEV_DIR
) { 
 817                  * Avoid ".", "..", and aliases of "." for obvious reasons. 
 819                 if ((fcnp
->cn_namelen 
== 1 && fcnp
->cn_nameptr
[0] == '.')  
 820                     || (fcnp
->cn_flags
&ISDOTDOT
)  
 821                     || (tcnp
->cn_namelen 
== 1 && tcnp
->cn_nameptr
[0] == '.')  
 822                     || (tcnp
->cn_flags
&ISDOTDOT
)  
 831          * If ".." must be changed (ie the directory gets a new 
 832          * parent) then the source directory must not be in the 
 833          * directory hierarchy above the target, as this would 
 834          * orphan everything below the source directory. Also 
 835          * the user must have write permission in the source so 
 836          * as to be able to change "..".  
 838         if (doingdirectory 
&& (tdp 
!= fdp
)) { 
 839                 devnode_t 
* tmp
, *ntmp
; 
 843                                 /* XXX unlock stuff here probably */ 
 848                 } while ((tmp 
= tmp
->dn_typeinfo
.Dir
.parent
) != ntmp
); 
 851         /*********************************** 
 852          * Start actually doing things.... * 
 853          ***********************************/ 
 857         if ( (error 
= devfs_update(fvp
, &now
, &now
)) ) { 
 861          * Check if just deleting a link name. 
 864                 if (fvp
->v_type 
== VDIR
) { 
 868                 /* Release destination completely. */ 
 875          * 1) Bump link count while we're moving stuff 
 876          *    around.  If we crash somewhere before 
 877          *    completing our work,  too bad :) 
 881          * If the target exists zap it (unless it's a non-empty directory) 
 882          * We could do that as well but won't 
 885                 int ouruid 
= kauth_cred_getuid(vfs_context_ucred(tcnp
->cn_context
)); 
 887                  * Target must be empty if a directory and have no links 
 888                  * to it. Also, ensure source and target are compatible 
 889                  * (both directories, or both not directories). 
 891                 if (( doingdirectory
) && (tp
->dn_links 
> 2)) { 
 898         dev_add_name(tcnp
->cn_nameptr
,tdp
,NULL
,fp
,&tnp
); 
 900         fp
->dn_links
--; /* one less link to it.. */ 
 904         fp
->dn_links
--; /* we added one earlier*/ 
 911 devfs_symlink(struct vnop_symlink_args 
*ap
) 
 912         /*struct vnop_symlink_args { 
 914                 struct vnode **a_vpp; 
 915                 struct componentname *a_cnp; 
 916                 struct vnode_attr *a_vap; 
 918                 vfs_context_t a_context; 
 921         struct componentname 
* cnp 
= ap
->a_cnp
; 
 922         vfs_context_t ctx 
= cnp
->cn_context
; 
 923         struct proc 
*p 
= vfs_context_proc(ctx
); 
 926         devnode_type_t typeinfo
; 
 929         struct vnode_attr 
*     vap 
= ap
->a_vap
; 
 930         struct vnode 
* * vpp 
= ap
->a_vpp
; 
 932         dir_p 
= VTODN(ap
->a_dvp
); 
 933         typeinfo
.Slnk
.name 
= ap
->a_target
; 
 934         typeinfo
.Slnk
.namelen 
= strlen(ap
->a_target
); 
 937         error 
= dev_add_entry(cnp
->cn_nameptr
, dir_p
, DEV_SLNK
,  
 938                               &typeinfo
, NULL
, NULL
, &nm_p
); 
 942         dev_p 
= nm_p
->de_dnp
; 
 943         dev_p
->dn_uid 
= dir_p
->dn_uid
; 
 944         dev_p
->dn_gid 
= dir_p
->dn_gid
; 
 945         dev_p
->dn_mode 
= vap
->va_mode
; 
 946         dn_copy_times(dev_p
, dir_p
); 
 948         error 
= devfs_dntovn(dev_p
, vpp
, p
); 
 959 devfs_mknod(struct vnop_mknod_args 
*ap
) 
 960         /* struct vnop_mknod_args { 
 962                 struct vnode **a_vpp; 
 963                 struct componentname *a_cnp; 
 964                 struct vnode_attr *a_vap; 
 965                 vfs_context_t a_context; 
 968         struct componentname 
* cnp 
= ap
->a_cnp
; 
 969         vfs_context_t ctx 
= cnp
->cn_context
; 
 970         struct proc 
*p 
= vfs_context_proc(ctx
); 
 972         devdirent_t 
*   devent
; 
 973         devnode_t 
*     dir_p
;  /* devnode for parent directory */ 
 974         struct vnode 
*  dvp 
= ap
->a_dvp
; 
 976         devnode_type_t  typeinfo
; 
 977         struct vnode_attr 
*     vap 
= ap
->a_vap
; 
 978         struct vnode 
** vpp 
= ap
->a_vpp
; 
 981         if (!(vap
->va_type 
== VBLK
) && !(vap
->va_type 
== VCHR
)) { 
 982                 return (EINVAL
); /* only support mknod of special files */ 
 985         typeinfo
.dev 
= vap
->va_rdev
; 
 988         error 
= dev_add_entry(cnp
->cn_nameptr
, dir_p
,  
 989                               (vap
->va_type 
== VBLK
) ? DEV_BDEV 
: DEV_CDEV
, 
 990                               &typeinfo
, NULL
, NULL
, &devent
); 
 994         dev_p 
= devent
->de_dnp
; 
 995         error 
= devfs_dntovn(dev_p
, vpp
, p
); 
 998         dev_p
->dn_uid 
= vap
->va_uid
; 
 999         dev_p
->dn_gid 
= vap
->va_gid
; 
1000         dev_p
->dn_mode 
= vap
->va_mode
; 
1001         VATTR_SET_SUPPORTED(vap
, va_uid
); 
1002         VATTR_SET_SUPPORTED(vap
, va_gid
); 
1003         VATTR_SET_SUPPORTED(vap
, va_mode
); 
1011  * Vnode op for readdir 
1014 devfs_readdir(struct vnop_readdir_args 
*ap
) 
1015         /*struct vnop_readdir_args { 
1021                 vfs_context_t a_context; 
1024         struct vnode 
*vp 
= ap
->a_vp
; 
1025         struct uio 
*uio 
= ap
->a_uio
; 
1026         struct dirent dirent
; 
1027         devnode_t 
* dir_node
; 
1028         devdirent_t 
*   name_node
; 
1035         if (ap
->a_flags 
& (VNODE_READDIR_EXTENDED 
| VNODE_READDIR_REQSEEKOFF
)) 
1038         /*  set up refs to dir */ 
1039         dir_node 
= VTODN(vp
); 
1040         if (dir_node
->dn_type 
!= DEV_DIR
) 
1043         startpos 
= uio
->uio_offset
; 
1047         name_node 
= dir_node
->dn_typeinfo
.Dir
.dirlist
; 
1050         dir_node
->dn_access 
= 1; 
1052         while ((name_node 
|| (nodenumber 
< 2)) && (uio_resid(uio
) > 0)) 
1057                         dirent
.d_fileno 
= (int32_t)(void *)dir_node
; 
1059                         dirent
.d_namlen 
= 1; 
1060                         dirent
.d_type 
= DT_DIR
; 
1063                         if(dir_node
->dn_typeinfo
.Dir
.parent
) 
1065                                 = (int32_t)dir_node
->dn_typeinfo
.Dir
.parent
; 
1067                                 dirent
.d_fileno 
= (u_int32_t
)dir_node
; 
1069                         dirent
.d_namlen 
= 2; 
1070                         dirent
.d_type 
= DT_DIR
; 
1073                         dirent
.d_fileno 
= (int32_t)(void *)name_node
->de_dnp
; 
1074                         dirent
.d_namlen 
= strlen(name_node
->de_name
); 
1075                         name 
= name_node
->de_name
; 
1076                         switch(name_node
->de_dnp
->dn_type
) { 
1078                                 dirent
.d_type 
= DT_BLK
; 
1081                                 dirent
.d_type 
= DT_CHR
; 
1084                                 dirent
.d_type 
= DT_DIR
; 
1087                                 dirent
.d_type 
= DT_LNK
; 
1090                                 dirent
.d_type 
= DT_UNKNOWN
; 
1093 #define GENERIC_DIRSIZ(dp) \ 
1094     ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) 
1096                 reclen 
= dirent
.d_reclen 
= GENERIC_DIRSIZ(&dirent
); 
1098                 if(pos 
>= startpos
)     /* made it to the offset yet? */ 
1100                         if (uio_resid(uio
) < reclen
) /* will it fit? */ 
1102                         strcpy( dirent
.d_name
,name
); 
1103                         if ((error 
= uiomove ((caddr_t
)&dirent
, 
1104                                         dirent
.d_reclen
, uio
)) != 0) 
1108                 if((nodenumber 
>1) && name_node
) 
1109                         name_node 
= name_node
->de_next
; 
1113         uio
->uio_offset 
= pos
; 
1122 devfs_readlink(struct vnop_readlink_args 
*ap
) 
1123         /*struct vnop_readlink_args { 
1126                 vfs_context_t a_context; 
1129         struct vnode 
*vp 
= ap
->a_vp
; 
1130         struct uio 
*uio 
= ap
->a_uio
; 
1131         devnode_t 
* lnk_node
; 
1134         /*  set up refs to dir */ 
1135         lnk_node 
= VTODN(vp
); 
1137         if (lnk_node
->dn_type 
!= DEV_SLNK
) { 
1141         error 
= uiomove(lnk_node
->dn_typeinfo
.Slnk
.name
,  
1142                         lnk_node
->dn_typeinfo
.Slnk
.namelen
, uio
); 
1148 devfs_reclaim(struct vnop_reclaim_args 
*ap
) 
1149         /*struct vnop_reclaim_args { 
1153     struct vnode 
*      vp 
= ap
->a_vp
; 
1154     devnode_t 
*         dnp 
= VTODN(vp
); 
1160          * do the same as devfs_inactive in case it is not called 
1161          * before us (can that ever happen?) 
1166         if (dnp
->dn_delete
) { 
1177  * Get configurable pathname variables. 
1181         struct vnop_pathconf_args 
/* { 
1185                 vfs_context_t a_context; 
1188         switch (ap
->a_name
) { 
1190                 /* arbitrary limit matching HFS; devfs has no hard limit */ 
1191                 *ap
->a_retval 
= 32767; 
1194                 *ap
->a_retval 
= DEVMAXNAMESIZE 
- 1;     /* includes NUL */ 
1197                 *ap
->a_retval 
= DEVMAXPATHSIZE 
- 1;     /* XXX nonconformant */ 
1199         case _PC_CHOWN_RESTRICTED
: 
1205         case _PC_CASE_SENSITIVE
: 
1208         case _PC_CASE_PRESERVING
: 
1220 /**************************************************************************\ 
1222 \**************************************************************************/ 
1226  *      struct vnop_inactive_args { 
1227  *              struct vnode *a_vp; 
1228  *              vfs_context_t a_context; 
1233 devfs_inactive(__unused 
struct vnop_inactive_args 
*ap
) 
1239  * called with DEVFS_LOCK held 
1242 devfs_update(struct vnode 
*vp
, struct timeval 
*access
, struct timeval 
*modify
) 
1248         if (vp
->v_mount
->mnt_flag 
& MNT_RDONLY
) { 
1256         dn_times(ip
, access
, modify
, &now
); 
1261 #define VOPFUNC int (*)(void *) 
1263 /* The following ops are used by directories and symlinks */ 
1264 int (**devfs_vnodeop_p
)(void *); 
1265 static struct vnodeopv_entry_desc devfs_vnodeop_entries
[] = { 
1266         { &vnop_default_desc
, (VOPFUNC
)vn_default_error 
}, 
1267         { &vnop_lookup_desc
, (VOPFUNC
)devfs_lookup 
},           /* lookup */ 
1268         { &vnop_create_desc
, (VOPFUNC
)err_create 
},             /* create */ 
1269         { &vnop_whiteout_desc
, (VOPFUNC
)err_whiteout 
},         /* whiteout */ 
1270         { &vnop_mknod_desc
, (VOPFUNC
)devfs_mknod 
},             /* mknod */ 
1271         { &vnop_open_desc
, (VOPFUNC
)nop_open 
},                 /* open */ 
1272         { &vnop_close_desc
, (VOPFUNC
)devfs_close 
},             /* close */ 
1273         { &vnop_getattr_desc
, (VOPFUNC
)devfs_getattr 
},         /* getattr */ 
1274         { &vnop_setattr_desc
, (VOPFUNC
)devfs_setattr 
},         /* setattr */ 
1275         { &vnop_read_desc
, (VOPFUNC
)devfs_read 
},               /* read */ 
1276         { &vnop_write_desc
, (VOPFUNC
)devfs_write 
},             /* write */ 
1277         { &vnop_ioctl_desc
, (VOPFUNC
)err_ioctl 
},               /* ioctl */ 
1278         { &vnop_select_desc
, (VOPFUNC
)err_select 
},             /* select */ 
1279         { &vnop_revoke_desc
, (VOPFUNC
)err_revoke 
},             /* revoke */ 
1280         { &vnop_mmap_desc
, (VOPFUNC
)err_mmap 
},                 /* mmap */ 
1281         { &vnop_fsync_desc
, (VOPFUNC
)nop_fsync 
},               /* fsync */ 
1282         { &vnop_remove_desc
, (VOPFUNC
)devfs_remove 
},           /* remove */ 
1283         { &vnop_link_desc
, (VOPFUNC
)devfs_link 
},               /* link */ 
1284         { &vnop_rename_desc
, (VOPFUNC
)devfs_rename 
},           /* rename */ 
1285         { &vnop_mkdir_desc
, (VOPFUNC
)err_mkdir 
},               /* mkdir */ 
1286         { &vnop_rmdir_desc
, (VOPFUNC
)err_rmdir 
},               /* rmdir */ 
1287         { &vnop_symlink_desc
, (VOPFUNC
)devfs_symlink 
},         /* symlink */ 
1288         { &vnop_readdir_desc
, (VOPFUNC
)devfs_readdir 
},         /* readdir */ 
1289         { &vnop_readlink_desc
, (VOPFUNC
)devfs_readlink 
},       /* readlink */ 
1290         { &vnop_inactive_desc
, (VOPFUNC
)devfs_inactive 
},       /* inactive */ 
1291         { &vnop_reclaim_desc
, (VOPFUNC
)devfs_reclaim 
},         /* reclaim */ 
1292         { &vnop_strategy_desc
, (VOPFUNC
)err_strategy 
},         /* strategy */ 
1293         { &vnop_pathconf_desc
, (VOPFUNC
)devs_vnop_pathconf 
},   /* pathconf */ 
1294         { &vnop_advlock_desc
, (VOPFUNC
)err_advlock 
},           /* advlock */ 
1295         { &vnop_bwrite_desc
, (VOPFUNC
)err_bwrite 
}, 
1296         { &vnop_pagein_desc
, (VOPFUNC
)err_pagein 
},             /* Pagein */ 
1297         { &vnop_pageout_desc
, (VOPFUNC
)err_pageout 
},           /* Pageout */ 
1298         { &vnop_copyfile_desc
, (VOPFUNC
)err_copyfile 
},         /* Copyfile */ 
1299         { &vnop_blktooff_desc
, (VOPFUNC
)err_blktooff 
},         /* blktooff */ 
1300         { &vnop_offtoblk_desc
, (VOPFUNC
)err_offtoblk 
},         /* offtoblk */ 
1301         { &vnop_blockmap_desc
, (VOPFUNC
)err_blockmap 
},         /* blockmap */ 
1302         { (struct vnodeop_desc
*)NULL
, (int(*)())NULL 
} 
1304 struct vnodeopv_desc devfs_vnodeop_opv_desc 
= 
1305         { &devfs_vnodeop_p
, devfs_vnodeop_entries 
}; 
1307 /* The following ops are used by the device nodes */ 
1308 int (**devfs_spec_vnodeop_p
)(void *); 
1309 static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries
[] = { 
1310         { &vnop_default_desc
, (VOPFUNC
)vn_default_error 
}, 
1311         { &vnop_lookup_desc
, (VOPFUNC
)spec_lookup 
},            /* lookup */ 
1312         { &vnop_create_desc
, (VOPFUNC
)spec_create 
},            /* create */ 
1313         { &vnop_mknod_desc
, (VOPFUNC
)spec_mknod 
},              /* mknod */ 
1314         { &vnop_open_desc
, (VOPFUNC
)spec_open 
},                        /* open */ 
1315         { &vnop_close_desc
, (VOPFUNC
)devfsspec_close 
},         /* close */ 
1316         { &vnop_getattr_desc
, (VOPFUNC
)devfs_getattr 
},         /* getattr */ 
1317         { &vnop_setattr_desc
, (VOPFUNC
)devfs_setattr 
},         /* setattr */ 
1318         { &vnop_read_desc
, (VOPFUNC
)devfsspec_read 
},           /* read */ 
1319         { &vnop_write_desc
, (VOPFUNC
)devfsspec_write 
},         /* write */ 
1320         { &vnop_ioctl_desc
, (VOPFUNC
)spec_ioctl 
},              /* ioctl */ 
1321         { &vnop_select_desc
, (VOPFUNC
)spec_select 
},            /* select */ 
1322         { &vnop_revoke_desc
, (VOPFUNC
)spec_revoke 
},            /* revoke */ 
1323         { &vnop_mmap_desc
, (VOPFUNC
)spec_mmap 
},                        /* mmap */ 
1324         { &vnop_fsync_desc
, (VOPFUNC
)spec_fsync 
},              /* fsync */ 
1325         { &vnop_remove_desc
, (VOPFUNC
)devfs_remove 
},           /* remove */ 
1326         { &vnop_link_desc
, (VOPFUNC
)devfs_link 
},               /* link */ 
1327         { &vnop_rename_desc
, (VOPFUNC
)spec_rename 
},            /* rename */ 
1328         { &vnop_mkdir_desc
, (VOPFUNC
)spec_mkdir 
},              /* mkdir */ 
1329         { &vnop_rmdir_desc
, (VOPFUNC
)spec_rmdir 
},              /* rmdir */ 
1330         { &vnop_symlink_desc
, (VOPFUNC
)spec_symlink 
},          /* symlink */ 
1331         { &vnop_readdir_desc
, (VOPFUNC
)spec_readdir 
},          /* readdir */ 
1332         { &vnop_readlink_desc
, (VOPFUNC
)spec_readlink 
},                /* readlink */ 
1333         { &vnop_inactive_desc
, (VOPFUNC
)devfs_inactive 
},       /* inactive */ 
1334         { &vnop_reclaim_desc
, (VOPFUNC
)devfs_reclaim 
},         /* reclaim */ 
1335         { &vnop_strategy_desc
, (VOPFUNC
)spec_strategy 
},                /* strategy */ 
1336         { &vnop_pathconf_desc
, (VOPFUNC
)spec_pathconf 
},                /* pathconf */ 
1337         { &vnop_advlock_desc
, (VOPFUNC
)spec_advlock 
},          /* advlock */ 
1338         { &vnop_bwrite_desc
, (VOPFUNC
)vn_bwrite 
}, 
1339         { &vnop_devblocksize_desc
, (VOPFUNC
)spec_devblocksize 
},        /* devblocksize */ 
1340         { &vnop_pagein_desc
, (VOPFUNC
)err_pagein 
},             /* Pagein */ 
1341         { &vnop_pageout_desc
, (VOPFUNC
)err_pageout 
},           /* Pageout */ 
1342         { &vnop_copyfile_desc
, (VOPFUNC
)err_copyfile 
},         /* Copyfile */ 
1343         { &vnop_blktooff_desc
, (VOPFUNC
)spec_blktooff 
},        /* blktooff */ 
1344         { &vnop_blktooff_desc
, (VOPFUNC
)spec_offtoblk  
},       /* blkofftoblk */ 
1345         { &vnop_blockmap_desc
, (VOPFUNC
)spec_blockmap 
},        /* blockmap */ 
1346         { (struct vnodeop_desc
*)NULL
, (int(*)())NULL 
} 
1348 struct vnodeopv_desc devfs_spec_vnodeop_opv_desc 
= 
1349         { &devfs_spec_vnodeop_p
, devfs_spec_vnodeop_entries 
};