2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * Copyright 1997,1998 Julian Elischer. All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions are
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright notice,
40 * this list of conditions and the following disclaimer in the documentation
41 * and/or other materials provided with the distribution.
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
46 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
47 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
49 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
50 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * Clark Warner (warner_c@apple.com) Tue Feb 10 2000
61 * - Added err_copyfile to the vnode operations table
62 * Dieter Siegmund (dieter@apple.com) Thu Apr 8 14:08:19 PDT 1999
63 * - instead of duplicating specfs here, created a vnode-ops table
64 * that redirects most operations to specfs (as is done with ufs);
65 * - removed routines that made no sense
66 * - cleaned up reclaim: replaced devfs_vntodn() with a macro VTODN()
67 * - cleaned up symlink, link locking
68 * - added the devfs_lock to protect devfs data structures against
69 * driver's calling devfs_add_devswf()/etc.
70 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999
71 * - free the devfs devnode in devfs_inactive(), not just in devfs_reclaim()
72 * to free up kernel memory as soon as it's available
73 * - got rid of devfsspec_{read, write}
74 * Dieter Siegmund (dieter@apple.com) Fri Sep 17 09:58:38 PDT 1999
75 * - update the mod/access times
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/namei.h>
81 #include <sys/kernel.h>
82 #include <sys/fcntl.h>
84 #include <sys/disklabel.h>
87 #include <sys/mount_internal.h>
89 #include <sys/kauth.h>
91 #include <sys/vnode_internal.h>
92 #include <miscfs/specfs/specdev.h>
93 #include <sys/dirent.h>
94 #include <sys/vmmeter.h>
96 #include <sys/uio_internal.h>
98 #include "devfsdefs.h"
100 static int devfs_update(struct vnode
*vp
, struct timeval
*access
,
101 struct timeval
*modify
);
105 * Convert a component of a pathname into a pointer to a locked node.
106 * This is a very central and rather complicated routine.
107 * If the file system is not maintained in a strict tree hierarchy,
108 * this can result in a deadlock situation (see comments in code below).
110 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
111 * whether the name is to be looked up, created, renamed, or deleted.
112 * When CREATE, RENAME, or DELETE is specified, information usable in
113 * creating, renaming, or deleting a directory entry may be calculated.
114 * If flag has LOCKPARENT or'ed into it and the target of the pathname
115 * exists, lookup returns both the target and its parent directory locked.
116 * When creating or renaming and LOCKPARENT is specified, the target may
117 * not be ".". When deleting and LOCKPARENT is specified, the target may
118 * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
119 * instead of two DNUNLOCKs.
121 * Overall outline of devfs_lookup:
123 * check accessibility of directory
124 * null terminate the component (lookup leaves the whole string alone)
125 * look for name in cache, if found, then if at end of path
126 * and deleting or creating, drop it, else return name
127 * search for name in directory, to found or notfound
129 * if creating, return locked directory,
132 * if at end of path and deleting, return information to allow delete
133 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target
134 * node and return info to allow rewrite
135 * if not at end, add name to cache; if at end and neither creating
136 * nor deleting, add name to cache
137 * On return to lookup, remove the null termination we put in at the start.
139 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
142 devfs_lookup(struct vnop_lookup_args
*ap
)
143 /*struct vnop_lookup_args {
144 struct vnode * a_dvp; directory vnode ptr
145 struct vnode ** a_vpp; where to put the result
146 struct componentname * a_cnp; the name we want
147 vfs_context_t a_context;
150 struct componentname
*cnp
= ap
->a_cnp
;
151 vfs_context_t ctx
= cnp
->cn_context
;
152 struct proc
*p
= vfs_context_proc(ctx
);
153 struct vnode
*dir_vnode
= ap
->a_dvp
;
154 struct vnode
**result_vnode
= ap
->a_vpp
;
155 devnode_t
* dir_node
; /* the directory we are searching */
156 devnode_t
* node
= NULL
; /* the node we are searching for */
157 devdirent_t
* nodename
;
158 int flags
= cnp
->cn_flags
;
159 int op
= cnp
->cn_nameiop
; /* LOOKUP, CREATE, RENAME, or DELETE */
160 int wantparent
= flags
& (LOCKPARENT
|WANTPARENT
);
162 char heldchar
; /* the char at the end of the name componet */
166 *result_vnode
= NULL
; /* safe not sorry */ /*XXX*/
168 //if (dir_vnode->v_usecount == 0)
169 //printf("devfs_lookup: dir had no refs ");
170 dir_node
= VTODN(dir_vnode
);
173 * Make sure that our node is a directory as well.
175 if (dir_node
->dn_type
!= DEV_DIR
) {
181 * temporarily terminate string component
183 heldchar
= cnp
->cn_nameptr
[cnp
->cn_namelen
];
184 cnp
->cn_nameptr
[cnp
->cn_namelen
] = '\0';
186 nodename
= dev_findname(dir_node
, cnp
->cn_nameptr
);
188 * restore saved character
190 cnp
->cn_nameptr
[cnp
->cn_namelen
] = heldchar
;
194 node
= nodename
->de_dnp
;
196 /* Do potential vnode allocation here inside the lock
197 * to make sure that our device node has a non-NULL dn_vn
198 * associated with it. The device node might otherwise
199 * get deleted out from under us (see devfs_dn_free()).
201 error
= devfs_dntovn(node
, result_vnode
, p
);
212 * we haven't called devfs_dntovn if we get here
213 * we have not taken a reference on the node.. no
214 * vnode_put is necessary on these error returns
216 * If it doesn't exist and we're not the last component,
217 * or we're at the last component, but we're not creating
218 * or renaming, return ENOENT.
220 if (!(flags
& ISLASTCN
) || !(op
== CREATE
|| op
== RENAME
)) {
224 * We return with the directory locked, so that
225 * the parameters we set up above will still be
226 * valid if we actually decide to add a new entry.
227 * We return ni_vp == NULL to indicate that the entry
228 * does not currently exist; we leave a pointer to
229 * the (locked) directory vnode in namei_data->ni_dvp.
231 * NB - if the directory is unlocked, then this
232 * information cannot be used.
234 return (EJUSTRETURN
);
237 * from this point forward, we need to vnode_put the reference
238 * picked up in devfs_dntovn if we decide to return an error
242 * If deleting, and at end of pathname, return
243 * parameters which can be used to remove file.
244 * If the wantparent flag isn't set, we return only
245 * the directory (in namei_data->ni_dvp), otherwise we go
246 * on and lock the node, being careful with ".".
248 if (op
== DELETE
&& (flags
& ISLASTCN
)) {
251 * we are trying to delete '.'. What does this mean? XXX
253 if (dir_node
== node
) {
255 vnode_put(*result_vnode
);
256 *result_vnode
= NULL
;
258 if ( ((error
= vnode_get(dir_vnode
)) == 0) ) {
259 *result_vnode
= dir_vnode
;
267 * If rewriting (RENAME), return the vnode and the
268 * information required to rewrite the present directory
269 * Must get node of directory entry to verify it's a
270 * regular file, or empty directory.
272 if (op
== RENAME
&& wantparent
&& (flags
& ISLASTCN
)) {
275 * Careful about locking second node.
276 * This can only occur if the target is ".".
278 if (dir_node
== node
) {
286 * Step through the translation in the name. We do not unlock the
287 * directory because we may need it again if a symbolic link
288 * is relative to the current directory. Instead we save it
289 * unlocked as "saved_dir_node" XXX. We must get the target
290 * node before unlocking
291 * the directory to insure that the node will not be removed
292 * before we get it. We prevent deadlock by always fetching
293 * nodes from the root, moving down the directory tree. Thus
294 * when following backward pointers ".." we must unlock the
295 * parent directory before getting the requested directory.
296 * There is a potential race condition here if both the current
297 * and parent directories are removed before the lock for the
298 * node associated with ".." returns. We hope that this occurs
299 * infrequently since we cannot avoid this race condition without
300 * implementing a sophisticated deadlock detection algorithm.
301 * Note also that this simple deadlock detection scheme will not
302 * work if the file system has any hard links other than ".."
303 * that point backwards in the directory structure.
305 if ((flags
& ISDOTDOT
) == 0 && dir_node
== node
) {
307 vnode_put(*result_vnode
);
308 *result_vnode
= NULL
;
310 if ( (error
= vnode_get(dir_vnode
)) ) {
313 *result_vnode
= dir_vnode
;
319 vnode_put(*result_vnode
);
320 *result_vnode
= NULL
;
326 devfs_getattr(struct vnop_getattr_args
*ap
)
327 /*struct vnop_getattr_args {
329 struct vnode_attr *a_vap;
334 struct vnode
*vp
= ap
->a_vp
;
335 struct vnode_attr
*vap
= ap
->a_vap
;
336 devnode_t
* file_node
;
339 file_node
= VTODN(vp
);
344 dn_times(file_node
, &now
, &now
, &now
);
346 VATTR_RETURN(vap
, va_mode
, file_node
->dn_mode
);
348 switch (file_node
->dn_type
)
351 VATTR_RETURN(vap
, va_rdev
, (dev_t
)file_node
->dn_dvm
);
352 vap
->va_mode
|= (S_IFDIR
);
355 VATTR_RETURN(vap
, va_rdev
, file_node
->dn_typeinfo
.dev
);
356 vap
->va_mode
|= (S_IFCHR
);
359 VATTR_RETURN(vap
, va_rdev
, file_node
->dn_typeinfo
.dev
);
360 vap
->va_mode
|= (S_IFBLK
);
363 VATTR_RETURN(vap
, va_rdev
, 0);
364 vap
->va_mode
|= (S_IFLNK
);
367 VATTR_RETURN(vap
, va_rdev
, 0); /* default value only */
369 VATTR_RETURN(vap
, va_type
, vp
->v_type
);
370 VATTR_RETURN(vap
, va_nlink
, file_node
->dn_links
);
371 VATTR_RETURN(vap
, va_uid
, file_node
->dn_uid
);
372 VATTR_RETURN(vap
, va_gid
, file_node
->dn_gid
);
373 VATTR_RETURN(vap
, va_fsid
, (uintptr_t)file_node
->dn_dvm
);
374 VATTR_RETURN(vap
, va_fileid
, (uintptr_t)file_node
);
375 VATTR_RETURN(vap
, va_data_size
, file_node
->dn_len
);
377 /* return an override block size (advisory) */
378 if (vp
->v_type
== VBLK
)
379 VATTR_RETURN(vap
, va_iosize
, BLKDEV_IOSIZE
);
380 else if (vp
->v_type
== VCHR
)
381 VATTR_RETURN(vap
, va_iosize
, MAXPHYSIO
);
383 VATTR_RETURN(vap
, va_iosize
, vp
->v_mount
->mnt_vfsstat
.f_iosize
);
384 /* if the time is bogus, set it to the boot time */
385 if (file_node
->dn_ctime
.tv_sec
== 0) {
386 file_node
->dn_ctime
.tv_sec
= boottime_sec();
387 file_node
->dn_ctime
.tv_nsec
= 0;
389 if (file_node
->dn_mtime
.tv_sec
== 0)
390 file_node
->dn_mtime
= file_node
->dn_ctime
;
391 if (file_node
->dn_atime
.tv_sec
== 0)
392 file_node
->dn_atime
= file_node
->dn_ctime
;
393 VATTR_RETURN(vap
, va_change_time
, file_node
->dn_ctime
);
394 VATTR_RETURN(vap
, va_modify_time
, file_node
->dn_mtime
);
395 VATTR_RETURN(vap
, va_access_time
, file_node
->dn_atime
);
396 VATTR_RETURN(vap
, va_gen
, 0);
397 VATTR_RETURN(vap
, va_flags
, 0);
398 VATTR_RETURN(vap
, va_filerev
, 0);
399 VATTR_RETURN(vap
, va_acl
, NULL
);
407 devfs_setattr(struct vnop_setattr_args
*ap
)
408 /*struct vnop_setattr_args {
410 struct vnode_attr *a_vap;
411 vfs_context_t a_context;
414 struct vnode
*vp
= ap
->a_vp
;
415 struct vnode_attr
*vap
= ap
->a_vap
;
416 kauth_cred_t cred
= vfs_context_ucred(ap
->a_context
);
417 struct proc
*p
= vfs_context_proc(ap
->a_context
);
419 devnode_t
* file_node
;
420 struct timeval atimeval
, mtimeval
;
422 file_node
= VTODN(vp
);
426 * Go through the fields and update if set.
428 if (VATTR_IS_ACTIVE(vap
, va_access_time
) || VATTR_IS_ACTIVE(vap
, va_modify_time
)) {
431 if (VATTR_IS_ACTIVE(vap
, va_access_time
))
432 file_node
->dn_access
= 1;
433 if (VATTR_IS_ACTIVE(vap
, va_modify_time
)) {
434 file_node
->dn_change
= 1;
435 file_node
->dn_update
= 1;
437 atimeval
.tv_sec
= vap
->va_access_time
.tv_sec
;
438 atimeval
.tv_usec
= vap
->va_access_time
.tv_nsec
/ 1000;
439 mtimeval
.tv_sec
= vap
->va_modify_time
.tv_sec
;
440 mtimeval
.tv_usec
= vap
->va_modify_time
.tv_nsec
/ 1000;
442 if ( (error
= devfs_update(vp
, &atimeval
, &mtimeval
)) )
445 VATTR_SET_SUPPORTED(vap
, va_access_time
);
446 VATTR_SET_SUPPORTED(vap
, va_change_time
);
449 * Change the permissions.
451 if (VATTR_IS_ACTIVE(vap
, va_mode
)) {
452 file_node
->dn_mode
&= ~07777;
453 file_node
->dn_mode
|= vap
->va_mode
& 07777;
455 VATTR_SET_SUPPORTED(vap
, va_mode
);
460 if (VATTR_IS_ACTIVE(vap
, va_uid
))
461 file_node
->dn_uid
= vap
->va_uid
;
462 VATTR_SET_SUPPORTED(vap
, va_uid
);
467 if (VATTR_IS_ACTIVE(vap
, va_gid
))
468 file_node
->dn_gid
= vap
->va_gid
;
469 VATTR_SET_SUPPORTED(vap
, va_gid
);
477 devfs_read(struct vnop_read_args
*ap
)
478 /* struct vnop_read_args {
482 vfs_context_t a_context;
485 devnode_t
* dn_p
= VTODN(ap
->a_vp
);
487 switch (ap
->a_vp
->v_type
) {
491 return VNOP_READDIR(ap
->a_vp
, ap
->a_uio
, 0, NULL
, NULL
, ap
->a_context
);
494 printf("devfs_read(): bad file type %d", ap
->a_vp
->v_type
);
499 return (0); /* not reached */
503 devfs_close(struct vnop_close_args
*ap
)
504 /* struct vnop_close_args {
507 vfs_context_t a_context;
510 struct vnode
* vp
= ap
->a_vp
;
511 register devnode_t
* dnp
= VTODN(vp
);
514 if (vnode_isinuse(vp
, 1)) {
517 dn_times(dnp
, &now
, &now
, &now
);
524 devfsspec_close(struct vnop_close_args
*ap
)
525 /* struct vnop_close_args {
528 vfs_context_t a_context;
531 struct vnode
* vp
= ap
->a_vp
;
532 register devnode_t
* dnp
= VTODN(vp
);
535 if (vnode_isinuse(vp
, 1)) {
538 dn_times(dnp
, &now
, &now
, &now
);
541 return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_close
), ap
));
545 devfsspec_read(struct vnop_read_args
*ap
)
546 /* struct vnop_read_args {
553 register devnode_t
* dnp
= VTODN(ap
->a_vp
);
557 return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_read
), ap
));
561 devfsspec_write(struct vnop_write_args
*ap
)
562 /* struct vnop_write_args {
566 vfs_context_t a_context;
569 register devnode_t
* dnp
= VTODN(ap
->a_vp
);
574 return (VOCALL (spec_vnodeop_p
, VOFFSET(vnop_write
), ap
));
578 * Write data to a file or directory.
581 devfs_write(struct vnop_write_args
*ap
)
582 /* struct vnop_write_args {
589 switch (ap
->a_vp
->v_type
) {
593 printf("devfs_write(): bad file type %d", ap
->a_vp
->v_type
);
596 return 0; /* not reached */
600 devfs_remove(struct vnop_remove_args
*ap
)
601 /* struct vnop_remove_args {
604 struct componentname *a_cnp;
607 struct vnode
*vp
= ap
->a_vp
;
608 struct vnode
*dvp
= ap
->a_dvp
;
609 struct componentname
*cnp
= ap
->a_cnp
;
610 vfs_context_t ctx
= cnp
->cn_context
;
614 int doingdirectory
= 0;
616 uid_t ouruid
= kauth_cred_getuid(vfs_context_ucred(ctx
));
619 * assume that the name is null terminated as they
620 * are the end of the path. Get pointers to all our
628 tnp
= dev_findname(tdp
, cnp
->cn_nameptr
);
636 * Make sure that we don't try do something stupid
638 if ((tp
->dn_type
) == DEV_DIR
) {
640 * Avoid ".", "..", and aliases of "." for obvious reasons.
642 if ( (cnp
->cn_namelen
== 1 && cnp
->cn_nameptr
[0] == '.')
643 || (cnp
->cn_flags
&ISDOTDOT
) ) {
650 /***********************************
651 * Start actually doing things.... *
652 ***********************************/
657 * Target must be empty if a directory and have no links
658 * to it. Also, ensure source and target are compatible
659 * (both directories, or both not directories).
661 if (( doingdirectory
) && (tp
->dn_links
> 2)) {
675 devfs_link(struct vnop_link_args
*ap
)
676 /*struct vnop_link_args {
677 struct vnode *a_tdvp;
679 struct componentname *a_cnp;
680 vfs_context_t a_context;
683 struct vnode
*vp
= ap
->a_vp
;
684 struct vnode
*tdvp
= ap
->a_tdvp
;
685 struct componentname
*cnp
= ap
->a_cnp
;
693 * First catch an arbitrary restriction for this FS
695 if (cnp
->cn_namelen
> DEVMAXNAMESIZE
) {
696 error
= ENAMETOOLONG
;
701 * Lock our directories and get our name pointers
702 * assume that the names are null terminated as they
703 * are the end of the path. Get pointers to all our
709 if (tdvp
->v_mount
!= vp
->v_mount
) {
715 /***********************************
716 * Start actually doing things.... *
717 ***********************************/
721 error
= devfs_update(vp
, &now
, &now
);
724 error
= dev_add_name(cnp
->cn_nameptr
, tdp
, NULL
, fp
, &tnp
);
733 * Rename system call. Seems overly complicated to me...
734 * rename("foo", "bar");
737 * link("foo", "bar");
739 * but ``atomically''.
741 * When the target exists, both the directory
742 * and target vnodes are locked.
743 * the source and source-parent vnodes are referenced
746 * Basic algorithm is:
748 * 1) Bump link count on source while we're linking it to the
749 * target. This also ensure the inode won't be deleted out
750 * from underneath us while we work (it may be truncated by
751 * a concurrent `trunc' or `open' for creation).
752 * 2) Link source to destination. If destination already exists,
754 * 3) Unlink source reference to node if still around. If a
755 * directory was moved and the parent of the destination
756 * is different from the source, patch the ".." entry in the
760 devfs_rename(struct vnop_rename_args
*ap
)
761 /*struct vnop_rename_args {
762 struct vnode *a_fdvp;
764 struct componentname *a_fcnp;
765 struct vnode *a_tdvp;
767 struct componentname *a_tcnp;
768 vfs_context_t a_context;
771 struct vnode
*tvp
= ap
->a_tvp
;
772 struct vnode
*tdvp
= ap
->a_tdvp
;
773 struct vnode
*fvp
= ap
->a_fvp
;
774 struct vnode
*fdvp
= ap
->a_fdvp
;
775 struct componentname
*tcnp
= ap
->a_tcnp
;
776 struct componentname
*fcnp
= ap
->a_fcnp
;
777 devnode_t
*fp
, *fdp
, *tp
, *tdp
;
778 devdirent_t
*fnp
,*tnp
;
779 int doingdirectory
= 0;
785 * First catch an arbitrary restriction for this FS
787 if (tcnp
->cn_namelen
> DEVMAXNAMESIZE
) {
788 error
= ENAMETOOLONG
;
793 * assume that the names are null terminated as they
794 * are the end of the path. Get pointers to all our
801 fnp
= dev_findname(fdp
, fcnp
->cn_nameptr
);
811 tnp
= dev_findname(tdp
, tcnp
->cn_nameptr
);
821 * Make sure that we don't try do something stupid
823 if ((fp
->dn_type
) == DEV_DIR
) {
825 * Avoid ".", "..", and aliases of "." for obvious reasons.
827 if ((fcnp
->cn_namelen
== 1 && fcnp
->cn_nameptr
[0] == '.')
828 || (fcnp
->cn_flags
&ISDOTDOT
)
829 || (tcnp
->cn_namelen
== 1 && tcnp
->cn_nameptr
[0] == '.')
830 || (tcnp
->cn_flags
&ISDOTDOT
)
839 * If ".." must be changed (ie the directory gets a new
840 * parent) then the source directory must not be in the
841 * directory hierarchy above the target, as this would
842 * orphan everything below the source directory. Also
843 * the user must have write permission in the source so
844 * as to be able to change "..".
846 if (doingdirectory
&& (tdp
!= fdp
)) {
847 devnode_t
* tmp
, *ntmp
;
851 /* XXX unlock stuff here probably */
856 } while ((tmp
= tmp
->dn_typeinfo
.Dir
.parent
) != ntmp
);
859 /***********************************
860 * Start actually doing things.... *
861 ***********************************/
865 if ( (error
= devfs_update(fvp
, &now
, &now
)) ) {
869 * Check if just deleting a link name.
872 if (fvp
->v_type
== VDIR
) {
876 /* Release destination completely. */
883 * 1) Bump link count while we're moving stuff
884 * around. If we crash somewhere before
885 * completing our work, too bad :)
889 * If the target exists zap it (unless it's a non-empty directory)
890 * We could do that as well but won't
893 int ouruid
= kauth_cred_getuid(vfs_context_ucred(tcnp
->cn_context
));
895 * Target must be empty if a directory and have no links
896 * to it. Also, ensure source and target are compatible
897 * (both directories, or both not directories).
899 if (( doingdirectory
) && (tp
->dn_links
> 2)) {
906 dev_add_name(tcnp
->cn_nameptr
,tdp
,NULL
,fp
,&tnp
);
908 fp
->dn_links
--; /* one less link to it.. */
912 fp
->dn_links
--; /* we added one earlier*/
919 devfs_symlink(struct vnop_symlink_args
*ap
)
920 /*struct vnop_symlink_args {
922 struct vnode **a_vpp;
923 struct componentname *a_cnp;
924 struct vnode_attr *a_vap;
926 vfs_context_t a_context;
929 struct componentname
* cnp
= ap
->a_cnp
;
930 vfs_context_t ctx
= cnp
->cn_context
;
931 struct proc
*p
= vfs_context_proc(ctx
);
934 devnode_type_t typeinfo
;
937 struct vnode_attr
* vap
= ap
->a_vap
;
938 struct vnode
* * vpp
= ap
->a_vpp
;
940 dir_p
= VTODN(ap
->a_dvp
);
941 typeinfo
.Slnk
.name
= ap
->a_target
;
942 typeinfo
.Slnk
.namelen
= strlen(ap
->a_target
);
945 error
= dev_add_entry(cnp
->cn_nameptr
, dir_p
, DEV_SLNK
,
946 &typeinfo
, NULL
, NULL
, &nm_p
);
950 dev_p
= nm_p
->de_dnp
;
951 dev_p
->dn_uid
= dir_p
->dn_uid
;
952 dev_p
->dn_gid
= dir_p
->dn_gid
;
953 dev_p
->dn_mode
= vap
->va_mode
;
954 dn_copy_times(dev_p
, dir_p
);
956 error
= devfs_dntovn(dev_p
, vpp
, p
);
967 devfs_mknod(struct vnop_mknod_args
*ap
)
968 /* struct vnop_mknod_args {
970 struct vnode **a_vpp;
971 struct componentname *a_cnp;
972 struct vnode_attr *a_vap;
973 vfs_context_t a_context;
976 struct componentname
* cnp
= ap
->a_cnp
;
977 vfs_context_t ctx
= cnp
->cn_context
;
978 struct proc
*p
= vfs_context_proc(ctx
);
980 devdirent_t
* devent
;
981 devnode_t
* dir_p
; /* devnode for parent directory */
982 struct vnode
* dvp
= ap
->a_dvp
;
984 devnode_type_t typeinfo
;
985 struct vnode_attr
* vap
= ap
->a_vap
;
986 struct vnode
** vpp
= ap
->a_vpp
;
989 if (!(vap
->va_type
== VBLK
) && !(vap
->va_type
== VCHR
)) {
990 return (EINVAL
); /* only support mknod of special files */
993 typeinfo
.dev
= vap
->va_rdev
;
996 error
= dev_add_entry(cnp
->cn_nameptr
, dir_p
,
997 (vap
->va_type
== VBLK
) ? DEV_BDEV
: DEV_CDEV
,
998 &typeinfo
, NULL
, NULL
, &devent
);
1002 dev_p
= devent
->de_dnp
;
1003 error
= devfs_dntovn(dev_p
, vpp
, p
);
1006 dev_p
->dn_uid
= vap
->va_uid
;
1007 dev_p
->dn_gid
= vap
->va_gid
;
1008 dev_p
->dn_mode
= vap
->va_mode
;
1009 VATTR_SET_SUPPORTED(vap
, va_uid
);
1010 VATTR_SET_SUPPORTED(vap
, va_gid
);
1011 VATTR_SET_SUPPORTED(vap
, va_mode
);
1019 * Vnode op for readdir
1022 devfs_readdir(struct vnop_readdir_args
*ap
)
1023 /*struct vnop_readdir_args {
1029 vfs_context_t a_context;
1032 struct vnode
*vp
= ap
->a_vp
;
1033 struct uio
*uio
= ap
->a_uio
;
1034 struct dirent dirent
;
1035 devnode_t
* dir_node
;
1036 devdirent_t
* name_node
;
1043 if (ap
->a_flags
& (VNODE_READDIR_EXTENDED
| VNODE_READDIR_REQSEEKOFF
))
1046 /* set up refs to dir */
1047 dir_node
= VTODN(vp
);
1048 if (dir_node
->dn_type
!= DEV_DIR
)
1051 startpos
= uio
->uio_offset
;
1055 name_node
= dir_node
->dn_typeinfo
.Dir
.dirlist
;
1058 dir_node
->dn_access
= 1;
1060 while ((name_node
|| (nodenumber
< 2)) && (uio_resid(uio
) > 0))
1065 dirent
.d_fileno
= (int32_t)(void *)dir_node
;
1067 dirent
.d_namlen
= 1;
1068 dirent
.d_type
= DT_DIR
;
1071 if(dir_node
->dn_typeinfo
.Dir
.parent
)
1073 = (int32_t)dir_node
->dn_typeinfo
.Dir
.parent
;
1075 dirent
.d_fileno
= (u_int32_t
)dir_node
;
1077 dirent
.d_namlen
= 2;
1078 dirent
.d_type
= DT_DIR
;
1081 dirent
.d_fileno
= (int32_t)(void *)name_node
->de_dnp
;
1082 dirent
.d_namlen
= strlen(name_node
->de_name
);
1083 name
= name_node
->de_name
;
1084 switch(name_node
->de_dnp
->dn_type
) {
1086 dirent
.d_type
= DT_BLK
;
1089 dirent
.d_type
= DT_CHR
;
1092 dirent
.d_type
= DT_DIR
;
1095 dirent
.d_type
= DT_LNK
;
1098 dirent
.d_type
= DT_UNKNOWN
;
1101 #define GENERIC_DIRSIZ(dp) \
1102 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
1104 reclen
= dirent
.d_reclen
= GENERIC_DIRSIZ(&dirent
);
1106 if(pos
>= startpos
) /* made it to the offset yet? */
1108 if (uio_resid(uio
) < reclen
) /* will it fit? */
1110 strcpy( dirent
.d_name
,name
);
1111 if ((error
= uiomove ((caddr_t
)&dirent
,
1112 dirent
.d_reclen
, uio
)) != 0)
1116 if((nodenumber
>1) && name_node
)
1117 name_node
= name_node
->de_next
;
1121 uio
->uio_offset
= pos
;
1130 devfs_readlink(struct vnop_readlink_args
*ap
)
1131 /*struct vnop_readlink_args {
1134 vfs_context_t a_context;
1137 struct vnode
*vp
= ap
->a_vp
;
1138 struct uio
*uio
= ap
->a_uio
;
1139 devnode_t
* lnk_node
;
1142 /* set up refs to dir */
1143 lnk_node
= VTODN(vp
);
1145 if (lnk_node
->dn_type
!= DEV_SLNK
) {
1149 error
= uiomove(lnk_node
->dn_typeinfo
.Slnk
.name
,
1150 lnk_node
->dn_typeinfo
.Slnk
.namelen
, uio
);
1156 devfs_reclaim(struct vnop_reclaim_args
*ap
)
1157 /*struct vnop_reclaim_args {
1161 struct vnode
* vp
= ap
->a_vp
;
1162 devnode_t
* dnp
= VTODN(vp
);
1168 * do the same as devfs_inactive in case it is not called
1169 * before us (can that ever happen?)
1174 if (dnp
->dn_delete
) {
1185 * Get configurable pathname variables.
1189 struct vnop_pathconf_args
/* {
1193 vfs_context_t a_context;
1196 switch (ap
->a_name
) {
1198 /* arbitrary limit matching HFS; devfs has no hard limit */
1199 *ap
->a_retval
= 32767;
1202 *ap
->a_retval
= DEVMAXNAMESIZE
- 1; /* includes NUL */
1205 *ap
->a_retval
= DEVMAXPATHSIZE
- 1; /* XXX nonconformant */
1207 case _PC_CHOWN_RESTRICTED
:
1213 case _PC_CASE_SENSITIVE
:
1216 case _PC_CASE_PRESERVING
:
1228 /**************************************************************************\
1230 \**************************************************************************/
1234 * struct vnop_inactive_args {
1235 * struct vnode *a_vp;
1236 * vfs_context_t a_context;
1241 devfs_inactive(__unused
struct vnop_inactive_args
*ap
)
1247 * called with DEVFS_LOCK held
1250 devfs_update(struct vnode
*vp
, struct timeval
*access
, struct timeval
*modify
)
1256 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
) {
1264 dn_times(ip
, access
, modify
, &now
);
1269 #define VOPFUNC int (*)(void *)
1271 /* The following ops are used by directories and symlinks */
1272 int (**devfs_vnodeop_p
)(void *);
1273 static struct vnodeopv_entry_desc devfs_vnodeop_entries
[] = {
1274 { &vnop_default_desc
, (VOPFUNC
)vn_default_error
},
1275 { &vnop_lookup_desc
, (VOPFUNC
)devfs_lookup
}, /* lookup */
1276 { &vnop_create_desc
, (VOPFUNC
)err_create
}, /* create */
1277 { &vnop_whiteout_desc
, (VOPFUNC
)err_whiteout
}, /* whiteout */
1278 { &vnop_mknod_desc
, (VOPFUNC
)devfs_mknod
}, /* mknod */
1279 { &vnop_open_desc
, (VOPFUNC
)nop_open
}, /* open */
1280 { &vnop_close_desc
, (VOPFUNC
)devfs_close
}, /* close */
1281 { &vnop_getattr_desc
, (VOPFUNC
)devfs_getattr
}, /* getattr */
1282 { &vnop_setattr_desc
, (VOPFUNC
)devfs_setattr
}, /* setattr */
1283 { &vnop_read_desc
, (VOPFUNC
)devfs_read
}, /* read */
1284 { &vnop_write_desc
, (VOPFUNC
)devfs_write
}, /* write */
1285 { &vnop_ioctl_desc
, (VOPFUNC
)err_ioctl
}, /* ioctl */
1286 { &vnop_select_desc
, (VOPFUNC
)err_select
}, /* select */
1287 { &vnop_revoke_desc
, (VOPFUNC
)err_revoke
}, /* revoke */
1288 { &vnop_mmap_desc
, (VOPFUNC
)err_mmap
}, /* mmap */
1289 { &vnop_fsync_desc
, (VOPFUNC
)nop_fsync
}, /* fsync */
1290 { &vnop_remove_desc
, (VOPFUNC
)devfs_remove
}, /* remove */
1291 { &vnop_link_desc
, (VOPFUNC
)devfs_link
}, /* link */
1292 { &vnop_rename_desc
, (VOPFUNC
)devfs_rename
}, /* rename */
1293 { &vnop_mkdir_desc
, (VOPFUNC
)err_mkdir
}, /* mkdir */
1294 { &vnop_rmdir_desc
, (VOPFUNC
)err_rmdir
}, /* rmdir */
1295 { &vnop_symlink_desc
, (VOPFUNC
)devfs_symlink
}, /* symlink */
1296 { &vnop_readdir_desc
, (VOPFUNC
)devfs_readdir
}, /* readdir */
1297 { &vnop_readlink_desc
, (VOPFUNC
)devfs_readlink
}, /* readlink */
1298 { &vnop_inactive_desc
, (VOPFUNC
)devfs_inactive
}, /* inactive */
1299 { &vnop_reclaim_desc
, (VOPFUNC
)devfs_reclaim
}, /* reclaim */
1300 { &vnop_strategy_desc
, (VOPFUNC
)err_strategy
}, /* strategy */
1301 { &vnop_pathconf_desc
, (VOPFUNC
)devs_vnop_pathconf
}, /* pathconf */
1302 { &vnop_advlock_desc
, (VOPFUNC
)err_advlock
}, /* advlock */
1303 { &vnop_bwrite_desc
, (VOPFUNC
)err_bwrite
},
1304 { &vnop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* Pagein */
1305 { &vnop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* Pageout */
1306 { &vnop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
1307 { &vnop_blktooff_desc
, (VOPFUNC
)err_blktooff
}, /* blktooff */
1308 { &vnop_offtoblk_desc
, (VOPFUNC
)err_offtoblk
}, /* offtoblk */
1309 { &vnop_blockmap_desc
, (VOPFUNC
)err_blockmap
}, /* blockmap */
1310 { (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
1312 struct vnodeopv_desc devfs_vnodeop_opv_desc
=
1313 { &devfs_vnodeop_p
, devfs_vnodeop_entries
};
1315 /* The following ops are used by the device nodes */
1316 int (**devfs_spec_vnodeop_p
)(void *);
1317 static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries
[] = {
1318 { &vnop_default_desc
, (VOPFUNC
)vn_default_error
},
1319 { &vnop_lookup_desc
, (VOPFUNC
)spec_lookup
}, /* lookup */
1320 { &vnop_create_desc
, (VOPFUNC
)spec_create
}, /* create */
1321 { &vnop_mknod_desc
, (VOPFUNC
)spec_mknod
}, /* mknod */
1322 { &vnop_open_desc
, (VOPFUNC
)spec_open
}, /* open */
1323 { &vnop_close_desc
, (VOPFUNC
)devfsspec_close
}, /* close */
1324 { &vnop_getattr_desc
, (VOPFUNC
)devfs_getattr
}, /* getattr */
1325 { &vnop_setattr_desc
, (VOPFUNC
)devfs_setattr
}, /* setattr */
1326 { &vnop_read_desc
, (VOPFUNC
)devfsspec_read
}, /* read */
1327 { &vnop_write_desc
, (VOPFUNC
)devfsspec_write
}, /* write */
1328 { &vnop_ioctl_desc
, (VOPFUNC
)spec_ioctl
}, /* ioctl */
1329 { &vnop_select_desc
, (VOPFUNC
)spec_select
}, /* select */
1330 { &vnop_revoke_desc
, (VOPFUNC
)spec_revoke
}, /* revoke */
1331 { &vnop_mmap_desc
, (VOPFUNC
)spec_mmap
}, /* mmap */
1332 { &vnop_fsync_desc
, (VOPFUNC
)spec_fsync
}, /* fsync */
1333 { &vnop_remove_desc
, (VOPFUNC
)devfs_remove
}, /* remove */
1334 { &vnop_link_desc
, (VOPFUNC
)devfs_link
}, /* link */
1335 { &vnop_rename_desc
, (VOPFUNC
)spec_rename
}, /* rename */
1336 { &vnop_mkdir_desc
, (VOPFUNC
)spec_mkdir
}, /* mkdir */
1337 { &vnop_rmdir_desc
, (VOPFUNC
)spec_rmdir
}, /* rmdir */
1338 { &vnop_symlink_desc
, (VOPFUNC
)spec_symlink
}, /* symlink */
1339 { &vnop_readdir_desc
, (VOPFUNC
)spec_readdir
}, /* readdir */
1340 { &vnop_readlink_desc
, (VOPFUNC
)spec_readlink
}, /* readlink */
1341 { &vnop_inactive_desc
, (VOPFUNC
)devfs_inactive
}, /* inactive */
1342 { &vnop_reclaim_desc
, (VOPFUNC
)devfs_reclaim
}, /* reclaim */
1343 { &vnop_strategy_desc
, (VOPFUNC
)spec_strategy
}, /* strategy */
1344 { &vnop_pathconf_desc
, (VOPFUNC
)spec_pathconf
}, /* pathconf */
1345 { &vnop_advlock_desc
, (VOPFUNC
)spec_advlock
}, /* advlock */
1346 { &vnop_bwrite_desc
, (VOPFUNC
)vn_bwrite
},
1347 { &vnop_devblocksize_desc
, (VOPFUNC
)spec_devblocksize
}, /* devblocksize */
1348 { &vnop_pagein_desc
, (VOPFUNC
)err_pagein
}, /* Pagein */
1349 { &vnop_pageout_desc
, (VOPFUNC
)err_pageout
}, /* Pageout */
1350 { &vnop_copyfile_desc
, (VOPFUNC
)err_copyfile
}, /* Copyfile */
1351 { &vnop_blktooff_desc
, (VOPFUNC
)spec_blktooff
}, /* blktooff */
1352 { &vnop_blktooff_desc
, (VOPFUNC
)spec_offtoblk
}, /* blkofftoblk */
1353 { &vnop_blockmap_desc
, (VOPFUNC
)spec_blockmap
}, /* blockmap */
1354 { (struct vnodeop_desc
*)NULL
, (int(*)())NULL
}
1356 struct vnodeopv_desc devfs_spec_vnodeop_opv_desc
=
1357 { &devfs_spec_vnodeop_p
, devfs_spec_vnodeop_entries
};