]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_syscalls.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_syscalls.c
1 /*
2 * Copyright (c) 1995-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 * (c) UNIX System Laboratories, Inc.
32 * All or some portions of this file are derived from material licensed
33 * to the University of California by American Telephone and Telegraph
34 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
35 * the permission of UNIX System Laboratories, Inc.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
66 */
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/namei.h>
71 #include <sys/filedesc.h>
72 #include <sys/kernel.h>
73 #include <sys/file_internal.h>
74 #include <sys/stat.h>
75 #include <sys/vnode_internal.h>
76 #include <sys/mount_internal.h>
77 #include <sys/proc_internal.h>
78 #include <sys/kauth.h>
79 #include <sys/uio_internal.h>
80 #include <sys/malloc.h>
81 #include <sys/mman.h>
82 #include <sys/dirent.h>
83 #include <sys/attr.h>
84 #include <sys/sysctl.h>
85 #include <sys/ubc.h>
86 #include <sys/quota.h>
87 #include <sys/kdebug.h>
88 #include <sys/fsevents.h>
89 #include <sys/sysproto.h>
90 #include <sys/xattr.h>
91 #include <sys/ubc_internal.h>
92 #include <machine/cons.h>
93 #include <machine/limits.h>
94 #include <miscfs/specfs/specdev.h>
95
96 #include <bsm/audit_kernel.h>
97 #include <bsm/audit_kevents.h>
98
99 #include <mach/mach_types.h>
100 #include <kern/kern_types.h>
101 #include <kern/kalloc.h>
102
103 #include <vm/vm_pageout.h>
104
105 #include <architecture/byte_order.h>
106 #include <libkern/OSAtomic.h>
107
108
109 /*
110 * The currently logged-in user, for ownership of files/directories whose on-disk
111 * permissions are ignored:
112 */
113 uid_t console_user;
114
115 static int change_dir(struct nameidata *ndp, vfs_context_t ctx);
116 static void checkdirs(struct vnode *olddp, vfs_context_t ctx);
117 void enablequotas(struct mount *mp, vfs_context_t ctx);
118 static int getfsstat_callback(mount_t mp, void * arg);
119 static int getutimes(user_addr_t usrtvp, struct timespec *tsp);
120 static int setutimes(vfs_context_t ctx, struct vnode *vp, const struct timespec *ts, int nullflag);
121 static int sync_callback(mount_t, void *);
122 static int munge_statfs(struct mount *mp, struct vfsstatfs *sfsp,
123 user_addr_t bufp, int *sizep, boolean_t is_64_bit,
124 boolean_t partial_copy);
125
126 __private_extern__ int sync_internal(void);
127
128 #ifdef __APPLE_API_OBSOLETE
129 struct fstatv_args {
130 int fd; /* file descriptor of the target file */
131 struct vstat *vsb; /* vstat structure for returned info */
132 };
133 struct lstatv_args {
134 const char *path; /* pathname of the target file */
135 struct vstat *vsb; /* vstat structure for returned info */
136 };
137 struct mkcomplex_args {
138 const char *path; /* pathname of the file to be created */
139 mode_t mode; /* access mode for the newly created file */
140 u_long type; /* format of the complex file */
141 };
142 struct statv_args {
143 const char *path; /* pathname of the target file */
144 struct vstat *vsb; /* vstat structure for returned info */
145 };
146
147 int fstatv(struct proc *p, struct fstatv_args *uap, register_t *retval);
148 int lstatv(struct proc *p, struct lstatv_args *uap, register_t *retval);
149 int mkcomplex(struct proc *p, struct mkcomplex_args *uap, register_t *retval);
150 int statv(struct proc *p, struct statv_args *uap, register_t *retval);
151
152 #endif /* __APPLE_API_OBSOLETE */
153
154 #if UNION
155 extern int (**union_vnodeop_p)(void *);
156 extern struct vnode *union_dircache(struct vnode*, struct proc*);
157 #endif /* UNION */
158
159 /* counts number of mount and unmount operations */
160 unsigned int vfs_nummntops=0;
161
162 extern struct fileops vnops;
163
164 extern void mount_list_add(mount_t mp);
165 extern void mount_list_remove(mount_t mp);
166 extern int mount_refdrain(mount_t mp);
167 extern int vcount(struct vnode *vp);
168
169
170 /*
171 * Virtual File System System Calls
172 */
173
174 /*
175 * Mount a file system.
176 */
177 /* ARGSUSED */
178 int
179 mount(struct proc *p, register struct mount_args *uap, __unused register_t *retval)
180 {
181 struct vnode *vp;
182 struct vnode *devvp = NULLVP;
183 struct vnode *device_vnode = NULLVP;
184 struct mount *mp;
185 struct vfstable *vfsp;
186 int error, flag = 0;
187 struct vnode_attr va;
188 struct vfs_context context;
189 struct nameidata nd;
190 struct nameidata nd1;
191 char fstypename[MFSNAMELEN];
192 size_t dummy=0;
193 user_addr_t devpath = USER_ADDR_NULL;
194 user_addr_t fsmountargs = uap->data;
195 int ronly = 0;
196 int mntalloc = 0;
197 mode_t accessmode;
198 boolean_t is_64bit;
199 boolean_t is_rwlock_locked = FALSE;
200
201 AUDIT_ARG(fflags, uap->flags);
202
203 context.vc_proc = p;
204 context.vc_ucred = kauth_cred_get();
205 is_64bit = proc_is64bit(p);
206
207 /*
208 * Get vnode to be covered
209 */
210 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
211 UIO_USERSPACE, uap->path, &context);
212 error = namei(&nd);
213 if (error)
214 return (error);
215 vp = nd.ni_vp;
216
217 if ((vp->v_flag & VROOT) &&
218 (vp->v_mount->mnt_flag & MNT_ROOTFS))
219 uap->flags |= MNT_UPDATE;
220
221 if (uap->flags & MNT_UPDATE) {
222 if ((vp->v_flag & VROOT) == 0) {
223 error = EINVAL;
224 goto out1;
225 }
226 mp = vp->v_mount;
227
228 /* unmount in progress return error */
229 mount_lock(mp);
230 if (mp->mnt_lflag & MNT_LUNMOUNT) {
231 mount_unlock(mp);
232 error = EBUSY;
233 goto out1;
234 }
235 mount_unlock(mp);
236 lck_rw_lock_exclusive(&mp->mnt_rwlock);
237 is_rwlock_locked = TRUE;
238 /*
239 * We only allow the filesystem to be reloaded if it
240 * is currently mounted read-only.
241 */
242 if ((uap->flags & MNT_RELOAD) &&
243 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
244 error = ENOTSUP;
245 goto out1;
246 }
247 /*
248 * Only root, or the user that did the original mount is
249 * permitted to update it.
250 */
251 if (mp->mnt_vfsstat.f_owner != kauth_cred_getuid(context.vc_ucred) &&
252 (error = suser(context.vc_ucred, &p->p_acflag))) {
253 goto out1;
254 }
255 /*
256 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
257 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
258 */
259 if (suser(context.vc_ucred, NULL)) {
260 uap->flags |= MNT_NOSUID | MNT_NODEV;
261 if (mp->mnt_flag & MNT_NOEXEC)
262 uap->flags |= MNT_NOEXEC;
263 }
264 flag = mp->mnt_flag;
265
266 mp->mnt_flag |=
267 uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
268
269 vfsp = mp->mnt_vtable;
270 goto update;
271 }
272 /*
273 * If the user is not root, ensure that they own the directory
274 * onto which we are attempting to mount.
275 */
276 VATTR_INIT(&va);
277 VATTR_WANTED(&va, va_uid);
278 if ((error = vnode_getattr(vp, &va, &context)) ||
279 (va.va_uid != kauth_cred_getuid(context.vc_ucred) &&
280 (error = suser(context.vc_ucred, &p->p_acflag)))) {
281 goto out1;
282 }
283 /*
284 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
285 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
286 */
287 if (suser(context.vc_ucred, NULL)) {
288 uap->flags |= MNT_NOSUID | MNT_NODEV;
289 if (vp->v_mount->mnt_flag & MNT_NOEXEC)
290 uap->flags |= MNT_NOEXEC;
291 }
292 if ( (error = VNOP_FSYNC(vp, MNT_WAIT, &context)) )
293 goto out1;
294
295 if ( (error = buf_invalidateblks(vp, BUF_WRITE_DATA, 0, 0)) )
296 goto out1;
297
298 if (vp->v_type != VDIR) {
299 error = ENOTDIR;
300 goto out1;
301 }
302 if ( (error = copyinstr(uap->type, fstypename, MFSNAMELEN, &dummy)) )
303 goto out1;
304
305 /* XXXAUDIT: Should we capture the type on the error path as well? */
306 AUDIT_ARG(text, fstypename);
307 mount_list_lock();
308 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
309 if (!strcmp(vfsp->vfc_name, fstypename))
310 break;
311 mount_list_unlock();
312 if (vfsp == NULL) {
313 error = ENODEV;
314 goto out1;
315 }
316 if (ISSET(vp->v_flag, VMOUNT) && (vp->v_mountedhere != NULL)) {
317 error = EBUSY;
318 goto out1;
319 }
320 SET(vp->v_flag, VMOUNT);
321
322 /*
323 * Allocate and initialize the filesystem.
324 */
325 MALLOC_ZONE(mp, struct mount *, (u_long)sizeof(struct mount),
326 M_MOUNT, M_WAITOK);
327 bzero((char *)mp, (u_long)sizeof(struct mount));
328 mntalloc = 1;
329
330 /* Initialize the default IO constraints */
331 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
332 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
333 mp->mnt_maxsegreadsize = mp->mnt_maxreadcnt;
334 mp->mnt_maxsegwritesize = mp->mnt_maxwritecnt;
335 mp->mnt_devblocksize = DEV_BSIZE;
336
337 TAILQ_INIT(&mp->mnt_vnodelist);
338 TAILQ_INIT(&mp->mnt_workerqueue);
339 TAILQ_INIT(&mp->mnt_newvnodes);
340 mount_lock_init(mp);
341 lck_rw_lock_exclusive(&mp->mnt_rwlock);
342 is_rwlock_locked = TRUE;
343 mp->mnt_op = vfsp->vfc_vfsops;
344 mp->mnt_vtable = vfsp;
345 mount_list_lock();
346 vfsp->vfc_refcount++;
347 mount_list_unlock();
348 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
349 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
350 strncpy(mp->mnt_vfsstat.f_fstypename, vfsp->vfc_name, MFSTYPENAMELEN);
351 strncpy(mp->mnt_vfsstat.f_mntonname, nd.ni_cnd.cn_pnbuf, MAXPATHLEN);
352 mp->mnt_vnodecovered = vp;
353 mp->mnt_vfsstat.f_owner = kauth_cred_getuid(context.vc_ucred);
354
355 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
356 vfs_setowner(mp, KAUTH_UID_NONE, KAUTH_GID_NONE);
357
358 update:
359 /*
360 * Set the mount level flags.
361 */
362 if (uap->flags & MNT_RDONLY)
363 mp->mnt_flag |= MNT_RDONLY;
364 else if (mp->mnt_flag & MNT_RDONLY)
365 mp->mnt_kern_flag |= MNTK_WANTRDWR;
366 mp->mnt_flag &= ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
367 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC |
368 MNT_UNKNOWNPERMISSIONS | MNT_DONTBROWSE | MNT_AUTOMOUNTED);
369 mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
370 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC |
371 MNT_UNKNOWNPERMISSIONS | MNT_DONTBROWSE | MNT_AUTOMOUNTED |
372 MNT_DEFWRITE);
373
374 if (vfsp->vfc_vfsflags & VFC_VFSLOCALARGS) {
375 if (is_64bit) {
376 if ( (error = copyin(fsmountargs, (caddr_t)&devpath, sizeof(devpath))) )
377 goto out1;
378 fsmountargs += sizeof(devpath);
379 } else {
380 char *tmp;
381 if ( (error = copyin(fsmountargs, (caddr_t)&tmp, sizeof(tmp))) )
382 goto out1;
383 /* munge into LP64 addr */
384 devpath = CAST_USER_ADDR_T(tmp);
385 fsmountargs += sizeof(tmp);
386 }
387
388 /* if it is not update and device name needs to be parsed */
389 if ((devpath)) {
390 NDINIT(&nd1, LOOKUP, FOLLOW, UIO_USERSPACE, devpath, &context);
391 if ( (error = namei(&nd1)) )
392 goto out1;
393
394 strncpy(mp->mnt_vfsstat.f_mntfromname, nd1.ni_cnd.cn_pnbuf, MAXPATHLEN);
395 devvp = nd1.ni_vp;
396
397 nameidone(&nd1);
398
399 if (devvp->v_type != VBLK) {
400 error = ENOTBLK;
401 goto out2;
402 }
403 if (major(devvp->v_rdev) >= nblkdev) {
404 error = ENXIO;
405 goto out2;
406 }
407 /*
408 * If mount by non-root, then verify that user has necessary
409 * permissions on the device.
410 */
411 if (suser(context.vc_ucred, NULL) != 0) {
412 accessmode = KAUTH_VNODE_READ_DATA;
413 if ((mp->mnt_flag & MNT_RDONLY) == 0)
414 accessmode |= KAUTH_VNODE_WRITE_DATA;
415 if ((error = vnode_authorize(devvp, NULL, accessmode, &context)) != 0)
416 goto out2;
417 }
418 }
419 if (devpath && ((uap->flags & MNT_UPDATE) == 0)) {
420 if ( (error = vnode_ref(devvp)) )
421 goto out2;
422 /*
423 * Disallow multiple mounts of the same device.
424 * Disallow mounting of a device that is currently in use
425 * (except for root, which might share swap device for miniroot).
426 * Flush out any old buffers remaining from a previous use.
427 */
428 if ( (error = vfs_mountedon(devvp)) )
429 goto out3;
430
431 if (vcount(devvp) > 1 && !(vfs_flags(mp) & MNT_ROOTFS)) {
432 error = EBUSY;
433 goto out3;
434 }
435 if ( (error = VNOP_FSYNC(devvp, MNT_WAIT, &context)) ) {
436 error = ENOTBLK;
437 goto out3;
438 }
439 if ( (error = buf_invalidateblks(devvp, BUF_WRITE_DATA, 0, 0)) )
440 goto out3;
441
442 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
443 if ( (error = VNOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, &context)) )
444 goto out3;
445
446 mp->mnt_devvp = devvp;
447 device_vnode = devvp;
448 } else {
449 if ((mp->mnt_flag & MNT_RDONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
450 /*
451 * If upgrade to read-write by non-root, then verify
452 * that user has necessary permissions on the device.
453 */
454 device_vnode = mp->mnt_devvp;
455 if (device_vnode && suser(context.vc_ucred, NULL)) {
456 if ((error = vnode_authorize(device_vnode, NULL,
457 KAUTH_VNODE_READ_DATA | KAUTH_VNODE_WRITE_DATA, &context)) != 0)
458 goto out2;
459 }
460 }
461 device_vnode = NULLVP;
462 }
463 }
464
465
466 /*
467 * Mount the filesystem.
468 */
469 error = VFS_MOUNT(mp, device_vnode, fsmountargs, &context);
470
471 if (uap->flags & MNT_UPDATE) {
472 if (mp->mnt_kern_flag & MNTK_WANTRDWR)
473 mp->mnt_flag &= ~MNT_RDONLY;
474 mp->mnt_flag &=~
475 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
476 mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
477 if (error)
478 mp->mnt_flag = flag;
479 vfs_event_signal(NULL, VQ_UPDATE, (intptr_t)NULL);
480 lck_rw_done(&mp->mnt_rwlock);
481 is_rwlock_locked = FALSE;
482 if (!error)
483 enablequotas(mp,&context);
484 goto out2;
485 }
486 /*
487 * Put the new filesystem on the mount list after root.
488 */
489 if (!error) {
490 CLR(vp->v_flag, VMOUNT);
491
492 vnode_lock(vp);
493 vp->v_mountedhere = mp;
494 vnode_unlock(vp);
495
496 vnode_ref(vp);
497
498 vfs_event_signal(NULL, VQ_MOUNT, (intptr_t)NULL);
499 checkdirs(vp, &context);
500 lck_rw_done(&mp->mnt_rwlock);
501 is_rwlock_locked = FALSE;
502 mount_list_add(mp);
503 /*
504 * there is no cleanup code here so I have made it void
505 * we need to revisit this
506 */
507 (void)VFS_START(mp, 0, &context);
508
509 /* increment the operations count */
510 OSAddAtomic(1, (SInt32 *)&vfs_nummntops);
511 enablequotas(mp,&context);
512
513 if (device_vnode) {
514 device_vnode->v_specflags |= SI_MOUNTEDON;
515
516 /*
517 * cache the IO attributes for the underlying physical media...
518 * an error return indicates the underlying driver doesn't
519 * support all the queries necessary... however, reasonable
520 * defaults will have been set, so no reason to bail or care
521 */
522 vfs_init_io_attributes(device_vnode, mp);
523 }
524 } else {
525 CLR(vp->v_flag, VMOUNT);
526 mount_list_lock();
527 mp->mnt_vtable->vfc_refcount--;
528 mount_list_unlock();
529
530 if (device_vnode ) {
531 VNOP_CLOSE(device_vnode, ronly ? FREAD : FREAD|FWRITE, &context);
532 vnode_rele(device_vnode);
533 }
534 lck_rw_done(&mp->mnt_rwlock);
535 is_rwlock_locked = FALSE;
536 mount_lock_destroy(mp);
537 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
538 }
539 nameidone(&nd);
540
541 /*
542 * drop I/O count on covered 'vp' and
543 * on the device vp if there was one
544 */
545 if (devpath && devvp)
546 vnode_put(devvp);
547 vnode_put(vp);
548
549 return(error);
550
551 out3:
552 vnode_rele(devvp);
553 out2:
554 if (devpath && devvp)
555 vnode_put(devvp);
556 out1:
557 /* Release mnt_rwlock only when it was taken */
558 if (is_rwlock_locked == TRUE) {
559 lck_rw_done(&mp->mnt_rwlock);
560 }
561 if (mntalloc)
562 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
563 vnode_put(vp);
564 nameidone(&nd);
565
566 return(error);
567
568 }
569
570 void
571 enablequotas(struct mount *mp, vfs_context_t context)
572 {
573 struct nameidata qnd;
574 int type;
575 char qfpath[MAXPATHLEN];
576 const char *qfname = QUOTAFILENAME;
577 const char *qfopsname = QUOTAOPSNAME;
578 const char *qfextension[] = INITQFNAMES;
579
580 if ((strcmp(mp->mnt_vfsstat.f_fstypename, "hfs") != 0 )
581 && (strcmp( mp->mnt_vfsstat.f_fstypename, "ufs") != 0))
582 return;
583
584 /*
585 * Enable filesystem disk quotas if necessary.
586 * We ignore errors as this should not interfere with final mount
587 */
588 for (type=0; type < MAXQUOTAS; type++) {
589 sprintf(qfpath, "%s/%s.%s", mp->mnt_vfsstat.f_mntonname, qfopsname, qfextension[type]);
590 NDINIT(&qnd, LOOKUP, FOLLOW, UIO_SYSSPACE32, CAST_USER_ADDR_T(qfpath), context);
591 if (namei(&qnd) != 0)
592 continue; /* option file to trigger quotas is not present */
593 vnode_put(qnd.ni_vp);
594 nameidone(&qnd);
595 sprintf(qfpath, "%s/%s.%s", mp->mnt_vfsstat.f_mntonname, qfname, qfextension[type]);
596
597 (void) VFS_QUOTACTL(mp, QCMD(Q_QUOTAON, type), 0, qfpath, context);
598 }
599 return;
600 }
601
602 /*
603 * Scan all active processes to see if any of them have a current
604 * or root directory onto which the new filesystem has just been
605 * mounted. If so, replace them with the new mount point.
606 */
607 static void
608 checkdirs(olddp, context)
609 struct vnode *olddp;
610 vfs_context_t context;
611 {
612 struct filedesc *fdp;
613 struct vnode *newdp;
614 struct proc *p;
615 struct vnode *tvp;
616 struct vnode *fdp_cvp;
617 struct vnode *fdp_rvp;
618 int cdir_changed = 0;
619 int rdir_changed = 0;
620 boolean_t funnel_state;
621
622 if (olddp->v_usecount == 1)
623 return;
624 if (VFS_ROOT(olddp->v_mountedhere, &newdp, context))
625 panic("mount: lost mount");
626 funnel_state = thread_funnel_set(kernel_flock, TRUE);
627
628 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
629 proc_fdlock(p);
630 fdp = p->p_fd;
631 if (fdp == (struct filedesc *)0) {
632 proc_fdunlock(p);
633 continue;
634 }
635 fdp_cvp = fdp->fd_cdir;
636 fdp_rvp = fdp->fd_rdir;
637 proc_fdunlock(p);
638
639 if (fdp_cvp == olddp) {
640 vnode_ref(newdp);
641 tvp = fdp->fd_cdir;
642 fdp_cvp = newdp;
643 cdir_changed = 1;
644 vnode_rele(tvp);
645 }
646 if (fdp_rvp == olddp) {
647 vnode_ref(newdp);
648 tvp = fdp->fd_rdir;
649 fdp_rvp = newdp;
650 rdir_changed = 1;
651 vnode_rele(tvp);
652 }
653 if (cdir_changed || rdir_changed) {
654 proc_fdlock(p);
655 fdp->fd_cdir = fdp_cvp;
656 fdp->fd_rdir = fdp_rvp;
657 proc_fdunlock(p);
658 }
659 }
660 if (rootvnode == olddp) {
661 vnode_ref(newdp);
662 tvp = rootvnode;
663 rootvnode = newdp;
664 vnode_rele(tvp);
665 }
666 thread_funnel_set(kernel_flock, funnel_state);
667
668 vnode_put(newdp);
669 }
670
671 /*
672 * Unmount a file system.
673 *
674 * Note: unmount takes a path to the vnode mounted on as argument,
675 * not special file (as before).
676 */
677 /* ARGSUSED */
678 int
679 unmount(struct proc *p, register struct unmount_args *uap, __unused register_t *retval)
680 {
681 register struct vnode *vp;
682 struct mount *mp;
683 int error;
684 struct nameidata nd;
685 struct vfs_context context;
686
687 context.vc_proc = p;
688 context.vc_ucred = kauth_cred_get();
689
690 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
691 UIO_USERSPACE, uap->path, &context);
692 error = namei(&nd);
693 if (error)
694 return (error);
695 vp = nd.ni_vp;
696 mp = vp->v_mount;
697 nameidone(&nd);
698
699 /*
700 * Must be the root of the filesystem
701 */
702 if ((vp->v_flag & VROOT) == 0) {
703 vnode_put(vp);
704 return (EINVAL);
705 }
706 vnode_put(vp);
707 return (safedounmount(mp, uap->flags, p));
708 }
709
710 /*
711 * Do the actual file system unmount, prevent some common foot shooting.
712 *
713 * XXX Should take a "vfs_context_t" instead of a "struct proc *"
714 */
715 int
716 safedounmount(mp, flags, p)
717 struct mount *mp;
718 int flags;
719 struct proc *p;
720 {
721 int error;
722
723 /*
724 * Only root, or the user that did the original mount is
725 * permitted to unmount this filesystem.
726 */
727 if ((mp->mnt_vfsstat.f_owner != kauth_cred_getuid(kauth_cred_get())) &&
728 (error = suser(kauth_cred_get(), &p->p_acflag)))
729 return (error);
730
731 /*
732 * Don't allow unmounting the root file system.
733 */
734 if (mp->mnt_flag & MNT_ROOTFS)
735 return (EBUSY); /* the root is always busy */
736
737 return (dounmount(mp, flags, p));
738 }
739
740 /*
741 * Do the actual file system unmount.
742 */
743 int
744 dounmount(mp, flags, p)
745 register struct mount *mp;
746 int flags;
747 struct proc *p;
748 {
749 struct vnode *coveredvp = (vnode_t)0;
750 int error;
751 int needwakeup = 0;
752 struct vfs_context context;
753 int forcedunmount = 0;
754 int lflags = 0;
755
756 context.vc_proc = p;
757 context.vc_ucred = kauth_cred_get();
758
759 if (flags & MNT_FORCE)
760 forcedunmount = 1;
761 mount_lock(mp);
762 /* XXX post jaguar fix LK_DRAIN - then clean this up */
763 if ((flags & MNT_FORCE)) {
764 mp->mnt_kern_flag |= MNTK_FRCUNMOUNT;
765 mp->mnt_lflag |= MNT_LFORCE;
766 }
767 if (mp->mnt_lflag & MNT_LUNMOUNT) {
768 mp->mnt_lflag |= MNT_LWAIT;
769 msleep((caddr_t)mp, &mp->mnt_mlock, (PVFS | PDROP), "dounmount", 0 );
770 /*
771 * The prior unmount attempt has probably succeeded.
772 * Do not dereference mp here - returning EBUSY is safest.
773 */
774 return (EBUSY);
775 }
776 mp->mnt_kern_flag |= MNTK_UNMOUNT;
777 mp->mnt_lflag |= MNT_LUNMOUNT;
778 mp->mnt_flag &=~ MNT_ASYNC;
779 mount_unlock(mp);
780 lck_rw_lock_exclusive(&mp->mnt_rwlock);
781 fsevent_unmount(mp); /* has to come first! */
782 error = 0;
783 if (forcedunmount == 0) {
784 ubc_umount(mp); /* release cached vnodes */
785 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
786 error = VFS_SYNC(mp, MNT_WAIT, &context);
787 if (error) {
788 mount_lock(mp);
789 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
790 mp->mnt_lflag &= ~MNT_LUNMOUNT;
791 mp->mnt_lflag &= ~MNT_LFORCE;
792 goto out;
793 }
794 }
795 }
796
797 if (forcedunmount)
798 lflags |= FORCECLOSE;
799 error = vflush(mp, NULLVP, SKIPSWAP | SKIPSYSTEM | SKIPROOT | lflags);
800 if ((forcedunmount == 0) && error) {
801 mount_lock(mp);
802 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
803 mp->mnt_lflag &= ~MNT_LUNMOUNT;
804 mp->mnt_lflag &= ~MNT_LFORCE;
805 goto out;
806 }
807
808 /* make sure there are no one in the mount iterations or lookup */
809 mount_iterdrain(mp);
810
811 error = VFS_UNMOUNT(mp, flags, &context);
812 if (error) {
813 mount_iterreset(mp);
814 mount_lock(mp);
815 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
816 mp->mnt_lflag &= ~MNT_LUNMOUNT;
817 mp->mnt_lflag &= ~MNT_LFORCE;
818 goto out;
819 }
820
821 /* increment the operations count */
822 if (!error)
823 OSAddAtomic(1, (SInt32 *)&vfs_nummntops);
824
825 if ( mp->mnt_devvp && mp->mnt_vtable->vfc_vfsflags & VFC_VFSLOCALARGS) {
826 mp->mnt_devvp->v_specflags &= ~SI_MOUNTEDON;
827 VNOP_CLOSE(mp->mnt_devvp, mp->mnt_flag & MNT_RDONLY ? FREAD : FREAD|FWRITE,
828 &context);
829 vnode_rele(mp->mnt_devvp);
830 }
831 lck_rw_done(&mp->mnt_rwlock);
832 mount_list_remove(mp);
833 lck_rw_lock_exclusive(&mp->mnt_rwlock);
834
835 /* mark the mount point hook in the vp but not drop the ref yet */
836 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
837 vnode_getwithref(coveredvp);
838 vnode_lock(coveredvp);
839 coveredvp->v_mountedhere = (struct mount *)0;
840 vnode_unlock(coveredvp);
841 vnode_put(coveredvp);
842 }
843
844 mount_list_lock();
845 mp->mnt_vtable->vfc_refcount--;
846 mount_list_unlock();
847
848 cache_purgevfs(mp); /* remove cache entries for this file sys */
849 vfs_event_signal(NULL, VQ_UNMOUNT, (intptr_t)NULL);
850 mount_lock(mp);
851 mp->mnt_lflag |= MNT_LDEAD;
852
853 if (mp->mnt_lflag & MNT_LWAIT) {
854 /*
855 * do the wakeup here
856 * in case we block in mount_refdrain
857 * which will drop the mount lock
858 * and allow anyone blocked in vfs_busy
859 * to wakeup and see the LDEAD state
860 */
861 mp->mnt_lflag &= ~MNT_LWAIT;
862 wakeup((caddr_t)mp);
863 }
864 mount_refdrain(mp);
865 out:
866 if (mp->mnt_lflag & MNT_LWAIT) {
867 mp->mnt_lflag &= ~MNT_LWAIT;
868 needwakeup = 1;
869 }
870 mount_unlock(mp);
871 lck_rw_done(&mp->mnt_rwlock);
872
873 if (needwakeup)
874 wakeup((caddr_t)mp);
875 if (!error) {
876 if ((coveredvp != NULLVP)) {
877 vnode_getwithref(coveredvp);
878 vnode_rele(coveredvp);
879 vnode_lock(coveredvp);
880 if(mp->mnt_crossref == 0) {
881 vnode_unlock(coveredvp);
882 mount_lock_destroy(mp);
883 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
884 } else {
885 coveredvp->v_lflag |= VL_MOUNTDEAD;
886 vnode_unlock(coveredvp);
887 }
888 vnode_put(coveredvp);
889 } else if (mp->mnt_flag & MNT_ROOTFS) {
890 mount_lock_destroy(mp);
891 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
892 } else
893 panic("dounmount: no coveredvp");
894 }
895 return (error);
896 }
897
898 void
899 mount_dropcrossref(mount_t mp, vnode_t dp, int need_put)
900 {
901 vnode_lock(dp);
902 mp->mnt_crossref--;
903 if (mp->mnt_crossref < 0)
904 panic("mount cross refs -ve");
905 if (((dp->v_lflag & VL_MOUNTDEAD) == VL_MOUNTDEAD) && (mp->mnt_crossref == 0)) {
906 dp->v_lflag &= ~VL_MOUNTDEAD;
907 if (need_put)
908 vnode_put_locked(dp);
909 vnode_unlock(dp);
910 mount_lock_destroy(mp);
911 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
912 return;
913 }
914 if (need_put)
915 vnode_put_locked(dp);
916 vnode_unlock(dp);
917 }
918
919
920 /*
921 * Sync each mounted filesystem.
922 */
923 #if DIAGNOSTIC
924 int syncprt = 0;
925 struct ctldebug debug0 = { "syncprt", &syncprt };
926 #endif
927
928 int print_vmpage_stat=0;
929
930 static int
931 sync_callback(mount_t mp, __unused void * arg)
932 {
933 struct proc * p = current_proc();
934 int asyncflag;
935 struct vfs_context context;
936
937 context.vc_proc = p;
938 context.vc_ucred = kauth_cred_get();
939
940 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
941 asyncflag = mp->mnt_flag & MNT_ASYNC;
942 mp->mnt_flag &= ~MNT_ASYNC;
943 VFS_SYNC(mp, MNT_NOWAIT, &context);
944 if (asyncflag)
945 mp->mnt_flag |= MNT_ASYNC;
946 }
947 return(VFS_RETURNED);
948 }
949
950
951 extern unsigned int vp_pagein, vp_pgodirty, vp_pgoclean;
952 extern unsigned int dp_pgins, dp_pgouts;
953
954 /* ARGSUSED */
955 int
956 sync(__unused struct proc *p, __unused struct sync_args *uap, __unused register_t *retval)
957 {
958
959 vfs_iterate(LK_NOWAIT, sync_callback, (void *)0);
960 {
961 if(print_vmpage_stat) {
962 vm_countdirtypages();
963 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty, vp_pgoclean, vp_pagein,
964 dp_pgins, dp_pgouts);
965 }
966 }
967 #if DIAGNOSTIC
968 if (syncprt)
969 vfs_bufstats();
970 #endif /* DIAGNOSTIC */
971 return (0);
972 }
973
974 /*
975 * Change filesystem quotas.
976 */
977 /* ARGSUSED */
978 int
979 quotactl(struct proc *p, register struct quotactl_args *uap, __unused register_t *retval)
980 {
981 register struct mount *mp;
982 int error, quota_cmd, quota_status;
983 caddr_t datap;
984 size_t fnamelen;
985 struct nameidata nd;
986 struct vfs_context context;
987 struct dqblk my_dqblk;
988
989 context.vc_proc = p;
990 context.vc_ucred = kauth_cred_get();
991
992 AUDIT_ARG(uid, uap->uid, 0, 0, 0);
993 AUDIT_ARG(cmd, uap->cmd);
994 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
995 UIO_USERSPACE, uap->path, &context);
996 error = namei(&nd);
997 if (error)
998 return (error);
999 mp = nd.ni_vp->v_mount;
1000 vnode_put(nd.ni_vp);
1001 nameidone(&nd);
1002
1003 /* copyin any data we will need for downstream code */
1004 quota_cmd = uap->cmd >> SUBCMDSHIFT;
1005
1006 switch (quota_cmd) {
1007 case Q_QUOTAON:
1008 /* uap->arg specifies a file from which to take the quotas */
1009 fnamelen = MAXPATHLEN;
1010 datap = kalloc(MAXPATHLEN);
1011 error = copyinstr(uap->arg, datap, MAXPATHLEN, &fnamelen);
1012 break;
1013 case Q_GETQUOTA:
1014 /* uap->arg is a pointer to a dqblk structure. */
1015 datap = (caddr_t) &my_dqblk;
1016 break;
1017 case Q_SETQUOTA:
1018 case Q_SETUSE:
1019 /* uap->arg is a pointer to a dqblk structure. */
1020 datap = (caddr_t) &my_dqblk;
1021 if (proc_is64bit(p)) {
1022 struct user_dqblk my_dqblk64;
1023 error = copyin(uap->arg, (caddr_t)&my_dqblk64, sizeof (my_dqblk64));
1024 if (error == 0) {
1025 munge_dqblk(&my_dqblk, &my_dqblk64, FALSE);
1026 }
1027 }
1028 else {
1029 error = copyin(uap->arg, (caddr_t)&my_dqblk, sizeof (my_dqblk));
1030 }
1031 break;
1032 case Q_QUOTASTAT:
1033 /* uap->arg is a pointer to an integer */
1034 datap = (caddr_t) &quota_status;
1035 break;
1036 default:
1037 datap = NULL;
1038 break;
1039 } /* switch */
1040
1041 if (error == 0) {
1042 error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, datap, &context);
1043 }
1044
1045 switch (quota_cmd) {
1046 case Q_QUOTAON:
1047 if (datap != NULL)
1048 kfree(datap, MAXPATHLEN);
1049 break;
1050 case Q_GETQUOTA:
1051 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1052 if (error == 0) {
1053 if (proc_is64bit(p)) {
1054 struct user_dqblk my_dqblk64;
1055 munge_dqblk(&my_dqblk, &my_dqblk64, TRUE);
1056 error = copyout((caddr_t)&my_dqblk64, uap->arg, sizeof (my_dqblk64));
1057 }
1058 else {
1059 error = copyout(datap, uap->arg, sizeof (struct dqblk));
1060 }
1061 }
1062 break;
1063 case Q_QUOTASTAT:
1064 /* uap->arg is a pointer to an integer */
1065 if (error == 0) {
1066 error = copyout(datap, uap->arg, sizeof(quota_status));
1067 }
1068 break;
1069 default:
1070 break;
1071 } /* switch */
1072
1073 return (error);
1074 }
1075
1076 /*
1077 * Get filesystem statistics.
1078 */
1079 /* ARGSUSED */
1080 int
1081 statfs(struct proc *p, register struct statfs_args *uap, __unused register_t *retval)
1082 {
1083 struct mount *mp;
1084 struct vfsstatfs *sp;
1085 int error;
1086 struct nameidata nd;
1087 struct vfs_context context;
1088 vnode_t vp;
1089
1090 context.vc_proc = p;
1091 context.vc_ucred = kauth_cred_get();
1092
1093 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1094 UIO_USERSPACE, uap->path, &context);
1095 error = namei(&nd);
1096 if (error)
1097 return (error);
1098 vp = nd.ni_vp;
1099 mp = vp->v_mount;
1100 sp = &mp->mnt_vfsstat;
1101 nameidone(&nd);
1102
1103 error = vfs_update_vfsstat(mp, &context);
1104 vnode_put(vp);
1105 if (error != 0)
1106 return (error);
1107
1108 error = munge_statfs(mp, sp, uap->buf, NULL, IS_64BIT_PROCESS(p), TRUE);
1109 return (error);
1110 }
1111
1112 /*
1113 * Get filesystem statistics.
1114 */
1115 /* ARGSUSED */
1116 int
1117 fstatfs(struct proc *p, register struct fstatfs_args *uap, __unused register_t *retval)
1118 {
1119 struct vnode *vp;
1120 struct mount *mp;
1121 struct vfsstatfs *sp;
1122 int error;
1123 struct vfs_context context;
1124
1125 context.vc_proc = p;
1126 context.vc_ucred = kauth_cred_get();
1127
1128 AUDIT_ARG(fd, uap->fd);
1129
1130 if ( (error = file_vnode(uap->fd, &vp)) )
1131 return (error);
1132
1133 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
1134
1135 mp = vp->v_mount;
1136 if (!mp) {
1137 file_drop(uap->fd);
1138 return (EBADF);
1139 }
1140 sp = &mp->mnt_vfsstat;
1141 if ((error = vfs_update_vfsstat(mp, &context)) != 0) {
1142 file_drop(uap->fd);
1143 return (error);
1144 }
1145 file_drop(uap->fd);
1146
1147 error = munge_statfs(mp, sp, uap->buf, NULL, IS_64BIT_PROCESS(p), TRUE);
1148
1149 return (error);
1150 }
1151
1152
1153 struct getfsstat_struct {
1154 user_addr_t sfsp;
1155 int count;
1156 int maxcount;
1157 int flags;
1158 int error;
1159 };
1160
1161
1162 static int
1163 getfsstat_callback(mount_t mp, void * arg)
1164 {
1165
1166 struct getfsstat_struct *fstp = (struct getfsstat_struct *)arg;
1167 struct vfsstatfs *sp;
1168 struct proc * p = current_proc();
1169 int error, my_size;
1170 struct vfs_context context;
1171
1172 context.vc_proc = p;
1173 context.vc_ucred = kauth_cred_get();
1174
1175 if (fstp->sfsp && fstp->count < fstp->maxcount) {
1176 sp = &mp->mnt_vfsstat;
1177 /*
1178 * If MNT_NOWAIT is specified, do not refresh the
1179 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1180 */
1181 if (((fstp->flags & MNT_NOWAIT) == 0 || (fstp->flags & MNT_WAIT)) &&
1182 (error = vfs_update_vfsstat(mp, &context))) {
1183 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error);
1184 return(VFS_RETURNED);
1185 }
1186
1187 /*
1188 * Need to handle LP64 version of struct statfs
1189 */
1190 error = munge_statfs(mp, sp, fstp->sfsp, &my_size, IS_64BIT_PROCESS(p), FALSE);
1191 if (error) {
1192 fstp->error = error;
1193 return(VFS_RETURNED_DONE);
1194 }
1195 fstp->sfsp += my_size;
1196 }
1197 fstp->count++;
1198 return(VFS_RETURNED);
1199 }
1200
1201 /*
1202 * Get statistics on all filesystems.
1203 */
1204 int
1205 getfsstat(__unused proc_t p, struct getfsstat_args *uap, int *retval)
1206 {
1207 user_addr_t sfsp;
1208 int count, maxcount;
1209 struct getfsstat_struct fst;
1210
1211 if (IS_64BIT_PROCESS(p)) {
1212 maxcount = uap->bufsize / sizeof(struct user_statfs);
1213 }
1214 else {
1215 maxcount = uap->bufsize / sizeof(struct statfs);
1216 }
1217 sfsp = uap->buf;
1218 count = 0;
1219
1220 fst.sfsp = sfsp;
1221 fst.flags = uap->flags;
1222 fst.count = 0;
1223 fst.error = 0;
1224 fst.maxcount = maxcount;
1225
1226
1227 vfs_iterate(0, getfsstat_callback, &fst);
1228
1229 if (fst.error ) {
1230 KAUTH_DEBUG("ERROR - %s gets %d", p->p_comm, fst.error);
1231 return(fst.error);
1232 }
1233
1234 if (fst.sfsp && fst.count > fst.maxcount)
1235 *retval = fst.maxcount;
1236 else
1237 *retval = fst.count;
1238 return (0);
1239 }
1240
1241 #if COMPAT_GETFSSTAT
1242 ogetfsstat(p, uap, retval)
1243 struct proc *p;
1244 register struct getfsstat_args *uap;
1245 register_t *retval;
1246 {
1247 return (ENOTSUP);
1248 }
1249 #endif
1250
1251 /*
1252 * Change current working directory to a given file descriptor.
1253 */
1254 /* ARGSUSED */
1255 int
1256 fchdir(struct proc *p, struct fchdir_args *uap, __unused register_t *retval)
1257 {
1258 register struct filedesc *fdp = p->p_fd;
1259 struct vnode *vp, *tdp, *tvp;
1260 struct mount *mp;
1261 int error;
1262 struct vfs_context context;
1263
1264 context.vc_proc = p;
1265 context.vc_ucred = kauth_cred_get();
1266
1267 if ( (error = file_vnode(uap->fd, &vp)) )
1268 return(error);
1269 if ( (error = vnode_getwithref(vp)) ) {
1270 file_drop(uap->fd);
1271 return(error);
1272 }
1273
1274 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
1275
1276 if (vp->v_type != VDIR)
1277 error = ENOTDIR;
1278 else
1279 error = vnode_authorize(vp, NULL, KAUTH_VNODE_SEARCH, &context);
1280 while (!error && (mp = vp->v_mountedhere) != NULL) {
1281 if (vfs_busy(mp, LK_NOWAIT)) {
1282 error = EACCES;
1283 goto out;
1284 }
1285 error = VFS_ROOT(mp, &tdp, &context);
1286 vfs_unbusy(mp);
1287 if (error)
1288 break;
1289 vnode_put(vp);
1290 vp = tdp;
1291 }
1292 if (error)
1293 goto out;
1294 if ( (error = vnode_ref(vp)) )
1295 goto out;
1296 vnode_put(vp);
1297
1298 proc_fdlock(p);
1299 tvp = fdp->fd_cdir;
1300 fdp->fd_cdir = vp;
1301 proc_fdunlock(p);
1302
1303 if (tvp)
1304 vnode_rele(tvp);
1305 file_drop(uap->fd);
1306
1307 return (0);
1308 out:
1309 vnode_put(vp);
1310 file_drop(uap->fd);
1311
1312 return(error);
1313 }
1314
1315 /*
1316 * Change current working directory (``.'').
1317 */
1318 /* ARGSUSED */
1319 int
1320 chdir(struct proc *p, struct chdir_args *uap, __unused register_t *retval)
1321 {
1322 register struct filedesc *fdp = p->p_fd;
1323 int error;
1324 struct nameidata nd;
1325 struct vnode *tvp;
1326 struct vfs_context context;
1327
1328 context.vc_proc = p;
1329 context.vc_ucred = kauth_cred_get();
1330
1331 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1332 UIO_USERSPACE, uap->path, &context);
1333 error = change_dir(&nd, &context);
1334 if (error)
1335 return (error);
1336 if ( (error = vnode_ref(nd.ni_vp)) ) {
1337 vnode_put(nd.ni_vp);
1338 return (error);
1339 }
1340 /*
1341 * drop the iocount we picked up in change_dir
1342 */
1343 vnode_put(nd.ni_vp);
1344
1345 proc_fdlock(p);
1346 tvp = fdp->fd_cdir;
1347 fdp->fd_cdir = nd.ni_vp;
1348 proc_fdunlock(p);
1349
1350 if (tvp)
1351 vnode_rele(tvp);
1352
1353 return (0);
1354 }
1355
1356 /*
1357 * Change notion of root (``/'') directory.
1358 */
1359 /* ARGSUSED */
1360 int
1361 chroot(struct proc *p, struct chroot_args *uap, __unused register_t *retval)
1362 {
1363 register struct filedesc *fdp = p->p_fd;
1364 int error;
1365 struct nameidata nd;
1366 boolean_t shared_regions_active;
1367 struct vnode *tvp;
1368 struct vfs_context context;
1369
1370 context.vc_proc = p;
1371 context.vc_ucred = kauth_cred_get();
1372
1373 if ((error = suser(kauth_cred_get(), &p->p_acflag)))
1374 return (error);
1375
1376 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1377 UIO_USERSPACE, uap->path, &context);
1378 error = change_dir(&nd, &context);
1379 if (error)
1380 return (error);
1381
1382 if(p->p_flag & P_NOSHLIB) {
1383 shared_regions_active = FALSE;
1384 } else {
1385 shared_regions_active = TRUE;
1386 }
1387 if ((error = clone_system_shared_regions(shared_regions_active,
1388 TRUE, /* chain_regions */
1389 (int)nd.ni_vp))) {
1390 vnode_put(nd.ni_vp);
1391 return (error);
1392 }
1393 if ( (error = vnode_ref(nd.ni_vp)) ) {
1394 vnode_put(nd.ni_vp);
1395 return (error);
1396 }
1397 vnode_put(nd.ni_vp);
1398
1399 proc_fdlock(p);
1400 tvp = fdp->fd_rdir;
1401 fdp->fd_rdir = nd.ni_vp;
1402 fdp->fd_flags |= FD_CHROOT;
1403 proc_fdunlock(p);
1404
1405 if (tvp != NULL)
1406 vnode_rele(tvp);
1407
1408 return (0);
1409 }
1410
1411 /*
1412 * Common routine for chroot and chdir.
1413 */
1414 static int
1415 change_dir(struct nameidata *ndp, vfs_context_t ctx)
1416 {
1417 struct vnode *vp;
1418 int error;
1419
1420 if ((error = namei(ndp)))
1421 return (error);
1422 nameidone(ndp);
1423 vp = ndp->ni_vp;
1424 if (vp->v_type != VDIR)
1425 error = ENOTDIR;
1426 else
1427 error = vnode_authorize(vp, NULL, KAUTH_VNODE_SEARCH, ctx);
1428 if (error)
1429 vnode_put(vp);
1430
1431 return (error);
1432 }
1433
1434 /*
1435 * Check permissions, allocate an open file structure,
1436 * and call the device open routine if any.
1437 */
1438
1439 #warning XXX implement uid, gid
1440 static int
1441 open1(vfs_context_t ctx, user_addr_t upath, int uflags, struct vnode_attr *vap, register_t *retval)
1442 {
1443 struct proc *p = vfs_context_proc(ctx);
1444 register struct filedesc *fdp = p->p_fd;
1445 register struct fileproc *fp;
1446 register struct vnode *vp;
1447 int flags, oflags;
1448 struct fileproc *nfp;
1449 int type, indx, error;
1450 struct flock lf;
1451 struct nameidata nd;
1452
1453 oflags = uflags;
1454
1455 if ((oflags & O_ACCMODE) == O_ACCMODE)
1456 return(EINVAL);
1457 flags = FFLAGS(uflags);
1458
1459 AUDIT_ARG(fflags, oflags);
1460 AUDIT_ARG(mode, vap->va_mode);
1461
1462 if ( (error = falloc(p, &nfp, &indx)) ) {
1463 return (error);
1464 }
1465 fp = nfp;
1466 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1467 UIO_USERSPACE, upath, ctx);
1468 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
1469
1470 if ((error = vn_open_auth(&nd, &flags, vap))) {
1471 if ((error == ENODEV || error == ENXIO) && (p->p_dupfd >= 0)) { /* XXX from fdopen */
1472 if ((error = dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
1473 fp_drop(p, indx, 0, 0);
1474 *retval = indx;
1475 return (0);
1476 }
1477 }
1478 if (error == ERESTART)
1479 error = EINTR;
1480 fp_free(p, indx, fp);
1481
1482 return (error);
1483 }
1484 p->p_dupfd = 0;
1485 vp = nd.ni_vp;
1486
1487 fp->f_fglob->fg_flag = flags & (FMASK | O_EVTONLY);
1488 fp->f_fglob->fg_type = DTYPE_VNODE;
1489 fp->f_fglob->fg_ops = &vnops;
1490 fp->f_fglob->fg_data = (caddr_t)vp;
1491
1492 if (flags & (O_EXLOCK | O_SHLOCK)) {
1493 lf.l_whence = SEEK_SET;
1494 lf.l_start = 0;
1495 lf.l_len = 0;
1496 if (flags & O_EXLOCK)
1497 lf.l_type = F_WRLCK;
1498 else
1499 lf.l_type = F_RDLCK;
1500 type = F_FLOCK;
1501 if ((flags & FNONBLOCK) == 0)
1502 type |= F_WAIT;
1503 if ((error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, type, ctx)))
1504 goto bad;
1505 fp->f_fglob->fg_flag |= FHASLOCK;
1506 }
1507
1508 /* try to truncate by setting the size attribute */
1509 if ((flags & O_TRUNC) && ((error = vnode_setsize(vp, (off_t)0, 0, ctx)) != 0))
1510 goto bad;
1511
1512 vnode_put(vp);
1513
1514 proc_fdlock(p);
1515 *fdflags(p, indx) &= ~UF_RESERVED;
1516 fp_drop(p, indx, fp, 1);
1517 proc_fdunlock(p);
1518
1519 *retval = indx;
1520
1521 return (0);
1522 bad:
1523 vn_close(vp, fp->f_fglob->fg_flag, fp->f_fglob->fg_cred, p);
1524 vnode_put(vp);
1525 fp_free(p, indx, fp);
1526
1527 return (error);
1528
1529 }
1530
1531 int
1532 open_extended(struct proc *p, struct open_extended_args *uap, register_t *retval)
1533 {
1534 struct vfs_context context;
1535 register struct filedesc *fdp = p->p_fd;
1536 int ciferror;
1537 kauth_filesec_t xsecdst;
1538 struct vnode_attr va;
1539 int cmode;
1540
1541 xsecdst = NULL;
1542 if ((uap->xsecurity != USER_ADDR_NULL) &&
1543 ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0))
1544 return ciferror;
1545
1546 context.vc_proc = p;
1547 context.vc_ucred = kauth_cred_get();
1548
1549 VATTR_INIT(&va);
1550 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
1551 VATTR_SET(&va, va_mode, cmode);
1552 if (uap->uid != KAUTH_UID_NONE)
1553 VATTR_SET(&va, va_uid, uap->uid);
1554 if (uap->gid != KAUTH_GID_NONE)
1555 VATTR_SET(&va, va_gid, uap->gid);
1556 if (xsecdst != NULL)
1557 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
1558
1559 ciferror = open1(&context, uap->path, uap->flags, &va, retval);
1560 if (xsecdst != NULL)
1561 kauth_filesec_free(xsecdst);
1562
1563 return ciferror;
1564 }
1565
1566 int
1567 open(struct proc *p, struct open_args *uap, register_t *retval)
1568 {
1569 struct vfs_context context;
1570 register struct filedesc *fdp = p->p_fd;
1571 struct vnode_attr va;
1572 int cmode;
1573
1574 context.vc_proc = p;
1575 context.vc_ucred = kauth_cred_get();
1576
1577 VATTR_INIT(&va);
1578 /* Mask off all but regular access permissions */
1579 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
1580 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
1581
1582 return(open1(&context, uap->path, uap->flags, &va, retval));
1583 }
1584
1585
1586 /*
1587 * Create a special file.
1588 */
1589 static int mkfifo1(vfs_context_t ctx, user_addr_t upath, struct vnode_attr *vap);
1590
1591 int
1592 mknod(struct proc *p, register struct mknod_args *uap, __unused register_t *retval)
1593 {
1594 struct vnode_attr va;
1595 struct vfs_context context;
1596 int error;
1597 int whiteout = 0;
1598 struct nameidata nd;
1599 vnode_t vp, dvp;
1600
1601 context.vc_proc = p;
1602 context.vc_ucred = kauth_cred_get();
1603
1604 VATTR_INIT(&va);
1605 VATTR_SET(&va, va_mode, (uap->mode & ALLPERMS) & ~p->p_fd->fd_cmask);
1606 VATTR_SET(&va, va_rdev, uap->dev);
1607
1608 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
1609 if ((uap->mode & S_IFMT) == S_IFIFO)
1610 return(mkfifo1(&context, uap->path, &va));
1611
1612 AUDIT_ARG(mode, uap->mode);
1613 AUDIT_ARG(dev, uap->dev);
1614
1615 if ((error = suser(context.vc_ucred, &p->p_acflag)))
1616 return (error);
1617 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
1618 UIO_USERSPACE, uap->path, &context);
1619 error = namei(&nd);
1620 if (error)
1621 return (error);
1622 dvp = nd.ni_dvp;
1623 vp = nd.ni_vp;
1624
1625 if (vp != NULL) {
1626 error = EEXIST;
1627 goto out;
1628 }
1629
1630 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context)) != 0)
1631 goto out;
1632
1633 switch (uap->mode & S_IFMT) {
1634 case S_IFMT: /* used by badsect to flag bad sectors */
1635 VATTR_SET(&va, va_type, VBAD);
1636 break;
1637 case S_IFCHR:
1638 VATTR_SET(&va, va_type, VCHR);
1639 break;
1640 case S_IFBLK:
1641 VATTR_SET(&va, va_type, VBLK);
1642 break;
1643 case S_IFWHT:
1644 whiteout = 1;
1645 break;
1646 default:
1647 error = EINVAL;
1648 goto out;
1649 }
1650 if (whiteout) {
1651 error = VNOP_WHITEOUT(dvp, &nd.ni_cnd, CREATE, &context);
1652 } else {
1653 error = vn_create(dvp, &vp, &nd.ni_cnd, &va, 0, &context);
1654 }
1655 if (error)
1656 goto out;
1657
1658 if (vp) {
1659 int update_flags = 0;
1660
1661 // Make sure the name & parent pointers are hooked up
1662 if (vp->v_name == NULL)
1663 update_flags |= VNODE_UPDATE_NAME;
1664 if (vp->v_parent == NULLVP)
1665 update_flags |= VNODE_UPDATE_PARENT;
1666
1667 if (update_flags)
1668 vnode_update_identity(vp, dvp, nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, update_flags);
1669
1670 add_fsevent(FSE_CREATE_FILE, &context,
1671 FSE_ARG_VNODE, vp,
1672 FSE_ARG_DONE);
1673 }
1674
1675 out:
1676 /*
1677 * nameidone has to happen before we vnode_put(dvp)
1678 * since it may need to release the fs_nodelock on the dvp
1679 */
1680 nameidone(&nd);
1681
1682 if (vp)
1683 vnode_put(vp);
1684 vnode_put(dvp);
1685
1686 return (error);
1687 }
1688
1689 /*
1690 * Create a named pipe.
1691 */
1692 static int
1693 mkfifo1(vfs_context_t ctx, user_addr_t upath, struct vnode_attr *vap)
1694 {
1695 vnode_t vp, dvp;
1696 int error;
1697 struct nameidata nd;
1698
1699 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
1700 UIO_USERSPACE, upath, ctx);
1701 error = namei(&nd);
1702 if (error)
1703 return (error);
1704 dvp = nd.ni_dvp;
1705 vp = nd.ni_vp;
1706
1707 /* check that this is a new file and authorize addition */
1708 if (vp != NULL) {
1709 error = EEXIST;
1710 goto out;
1711 }
1712 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
1713 goto out;
1714
1715 VATTR_SET(vap, va_type, VFIFO);
1716
1717 error = vn_create(dvp, &vp, &nd.ni_cnd, vap, 0, ctx);
1718 out:
1719 /*
1720 * nameidone has to happen before we vnode_put(dvp)
1721 * since it may need to release the fs_nodelock on the dvp
1722 */
1723 nameidone(&nd);
1724
1725 if (vp)
1726 vnode_put(vp);
1727 vnode_put(dvp);
1728
1729 return error;
1730 }
1731
1732 int
1733 mkfifo_extended(struct proc *p, struct mkfifo_extended_args *uap, __unused register_t *retval)
1734 {
1735 int ciferror;
1736 kauth_filesec_t xsecdst;
1737 struct vfs_context context;
1738 struct vnode_attr va;
1739
1740 xsecdst = KAUTH_FILESEC_NONE;
1741 if (uap->xsecurity != USER_ADDR_NULL) {
1742 if ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
1743 return ciferror;
1744 }
1745
1746 context.vc_proc = p;
1747 context.vc_ucred = kauth_cred_get();
1748
1749 VATTR_INIT(&va);
1750 VATTR_SET(&va, va_mode, (uap->mode & ALLPERMS) & ~p->p_fd->fd_cmask);
1751 if (uap->uid != KAUTH_UID_NONE)
1752 VATTR_SET(&va, va_uid, uap->uid);
1753 if (uap->gid != KAUTH_GID_NONE)
1754 VATTR_SET(&va, va_gid, uap->gid);
1755 if (xsecdst != KAUTH_FILESEC_NONE)
1756 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
1757
1758 ciferror = mkfifo1(&context, uap->path, &va);
1759
1760 if (xsecdst != KAUTH_FILESEC_NONE)
1761 kauth_filesec_free(xsecdst);
1762 return ciferror;
1763 }
1764
1765 /* ARGSUSED */
1766 int
1767 mkfifo(struct proc *p, register struct mkfifo_args *uap, __unused register_t *retval)
1768 {
1769 struct vfs_context context;
1770 struct vnode_attr va;
1771
1772 context.vc_proc = p;
1773 context.vc_ucred = kauth_cred_get();
1774
1775 VATTR_INIT(&va);
1776 VATTR_SET(&va, va_mode, (uap->mode & ALLPERMS) & ~p->p_fd->fd_cmask);
1777
1778 return(mkfifo1(&context, uap->path, &va));
1779 }
1780
1781 /*
1782 * Make a hard file link.
1783 */
1784 /* ARGSUSED */
1785 int
1786 link(struct proc *p, register struct link_args *uap, __unused register_t *retval)
1787 {
1788 vnode_t vp, dvp, lvp;
1789 struct nameidata nd;
1790 struct vfs_context context;
1791 int error;
1792 fse_info finfo;
1793 int need_event, has_listeners;
1794
1795 context.vc_proc = p;
1796 context.vc_ucred = kauth_cred_get();
1797 vp = dvp = lvp = NULLVP;
1798
1799 /* look up the object we are linking to */
1800 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1801 UIO_USERSPACE, uap->path, &context);
1802 error = namei(&nd);
1803 if (error)
1804 return (error);
1805 vp = nd.ni_vp;
1806
1807 nameidone(&nd);
1808
1809 /* we're not allowed to link to directories */
1810 if (vp->v_type == VDIR) {
1811 error = EPERM; /* POSIX */
1812 goto out;
1813 }
1814
1815 /* or to anything that kauth doesn't want us to (eg. immutable items) */
1816 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_LINKTARGET, &context)) != 0)
1817 goto out;
1818
1819 /* lookup the target node */
1820 nd.ni_cnd.cn_nameiop = CREATE;
1821 nd.ni_cnd.cn_flags = LOCKPARENT | AUDITVNPATH2;
1822 nd.ni_dirp = uap->link;
1823 error = namei(&nd);
1824 if (error != 0)
1825 goto out;
1826 dvp = nd.ni_dvp;
1827 lvp = nd.ni_vp;
1828 /* target node must not exist */
1829 if (lvp != NULLVP) {
1830 error = EEXIST;
1831 goto out2;
1832 }
1833 /* cannot link across mountpoints */
1834 if (vnode_mount(vp) != vnode_mount(dvp)) {
1835 error = EXDEV;
1836 goto out2;
1837 }
1838
1839 /* authorize creation of the target note */
1840 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context)) != 0)
1841 goto out2;
1842
1843 /* and finally make the link */
1844 error = VNOP_LINK(vp, dvp, &nd.ni_cnd, &context);
1845 if (error)
1846 goto out2;
1847
1848 need_event = need_fsevent(FSE_CREATE_FILE, dvp);
1849 has_listeners = kauth_authorize_fileop_has_listeners();
1850
1851 if (need_event || has_listeners) {
1852 char *target_path = NULL;
1853 char *link_to_path = NULL;
1854 int len, link_name_len;
1855
1856 /* build the path to the new link file */
1857 target_path = get_pathbuff();
1858 len = MAXPATHLEN;
1859 vn_getpath(dvp, target_path, &len);
1860 target_path[len-1] = '/';
1861 strcpy(&target_path[len], nd.ni_cnd.cn_nameptr);
1862 len += nd.ni_cnd.cn_namelen;
1863
1864 if (has_listeners) {
1865 /* build the path to file we are linking to */
1866 link_to_path = get_pathbuff();
1867 link_name_len = MAXPATHLEN;
1868 vn_getpath(vp, link_to_path, &link_name_len);
1869
1870 /* call out to allow 3rd party notification of rename.
1871 * Ignore result of kauth_authorize_fileop call.
1872 */
1873 kauth_authorize_fileop(vfs_context_ucred(&context), KAUTH_FILEOP_LINK,
1874 (uintptr_t)link_to_path, (uintptr_t)target_path);
1875 if (link_to_path != NULL)
1876 release_pathbuff(link_to_path);
1877 }
1878 if (need_event) {
1879 /* construct fsevent */
1880 if (get_fse_info(vp, &finfo, &context) == 0) {
1881 // build the path to the destination of the link
1882 add_fsevent(FSE_CREATE_FILE, &context,
1883 FSE_ARG_STRING, len, target_path,
1884 FSE_ARG_FINFO, &finfo,
1885 FSE_ARG_DONE);
1886 }
1887 }
1888 release_pathbuff(target_path);
1889 }
1890 out2:
1891 /*
1892 * nameidone has to happen before we vnode_put(dvp)
1893 * since it may need to release the fs_nodelock on the dvp
1894 */
1895 nameidone(&nd);
1896 out:
1897 if (lvp)
1898 vnode_put(lvp);
1899 if (dvp)
1900 vnode_put(dvp);
1901 vnode_put(vp);
1902 return (error);
1903 }
1904
1905 /*
1906 * Make a symbolic link.
1907 *
1908 * We could add support for ACLs here too...
1909 */
1910 /* ARGSUSED */
1911 int
1912 symlink(struct proc *p, register struct symlink_args *uap, __unused register_t *retval)
1913 {
1914 struct vnode_attr va;
1915 char *path;
1916 int error;
1917 struct nameidata nd;
1918 struct vfs_context context;
1919 vnode_t vp, dvp;
1920 size_t dummy=0;
1921
1922 context.vc_proc = p;
1923 context.vc_ucred = kauth_cred_get();
1924
1925 MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1926 error = copyinstr(uap->path, path, MAXPATHLEN, &dummy);
1927 if (error)
1928 goto out;
1929 AUDIT_ARG(text, path); /* This is the link string */
1930
1931 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
1932 UIO_USERSPACE, uap->link, &context);
1933 error = namei(&nd);
1934 if (error)
1935 goto out;
1936 dvp = nd.ni_dvp;
1937 vp = nd.ni_vp;
1938
1939 if (vp == NULL) {
1940 VATTR_INIT(&va);
1941 VATTR_SET(&va, va_type, VLNK);
1942 VATTR_SET(&va, va_mode, ACCESSPERMS & ~p->p_fd->fd_cmask);
1943
1944 /* authorize */
1945 error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, &context);
1946 /* get default ownership, etc. */
1947 if (error == 0)
1948 error = vnode_authattr_new(dvp, &va, 0, &context);
1949 if (error == 0)
1950 error = VNOP_SYMLINK(dvp, &vp, &nd.ni_cnd, &va, path, &context);
1951
1952 /* do fallback attribute handling */
1953 if (error == 0)
1954 error = vnode_setattr_fallback(vp, &va, &context);
1955
1956 if (error == 0) {
1957 int update_flags = 0;
1958
1959 if (vp == NULL) {
1960 nd.ni_cnd.cn_nameiop = LOOKUP;
1961 nd.ni_cnd.cn_flags = 0;
1962 error = namei(&nd);
1963 vp = nd.ni_vp;
1964
1965 if (vp == NULL)
1966 goto skipit;
1967 }
1968
1969 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
1970 /* call out to allow 3rd party notification of rename.
1971 * Ignore result of kauth_authorize_fileop call.
1972 */
1973 if (kauth_authorize_fileop_has_listeners() &&
1974 namei(&nd) == 0) {
1975 char *new_link_path = NULL;
1976 int len;
1977
1978 /* build the path to the new link file */
1979 new_link_path = get_pathbuff();
1980 len = MAXPATHLEN;
1981 vn_getpath(dvp, new_link_path, &len);
1982 new_link_path[len - 1] = '/';
1983 strcpy(&new_link_path[len], nd.ni_cnd.cn_nameptr);
1984
1985 kauth_authorize_fileop(vfs_context_ucred(&context), KAUTH_FILEOP_SYMLINK,
1986 (uintptr_t)path, (uintptr_t)new_link_path);
1987 if (new_link_path != NULL)
1988 release_pathbuff(new_link_path);
1989 }
1990 #endif
1991 // Make sure the name & parent pointers are hooked up
1992 if (vp->v_name == NULL)
1993 update_flags |= VNODE_UPDATE_NAME;
1994 if (vp->v_parent == NULLVP)
1995 update_flags |= VNODE_UPDATE_PARENT;
1996
1997 if (update_flags)
1998 vnode_update_identity(vp, dvp, nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, update_flags);
1999
2000 add_fsevent(FSE_CREATE_FILE, &context,
2001 FSE_ARG_VNODE, vp,
2002 FSE_ARG_DONE);
2003 }
2004 } else
2005 error = EEXIST;
2006
2007 skipit:
2008 /*
2009 * nameidone has to happen before we vnode_put(dvp)
2010 * since it may need to release the fs_nodelock on the dvp
2011 */
2012 nameidone(&nd);
2013
2014 if (vp)
2015 vnode_put(vp);
2016 vnode_put(dvp);
2017 out:
2018 FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
2019
2020 return (error);
2021 }
2022
2023 /*
2024 * Delete a whiteout from the filesystem.
2025 */
2026 /* ARGSUSED */
2027 #warning XXX authorization not implmented for whiteouts
2028 int
2029 undelete(struct proc *p, register struct undelete_args *uap, __unused register_t *retval)
2030 {
2031 int error;
2032 struct nameidata nd;
2033 struct vfs_context context;
2034 vnode_t vp, dvp;
2035
2036 context.vc_proc = p;
2037 context.vc_ucred = kauth_cred_get();
2038
2039 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT|AUDITVNPATH1,
2040 UIO_USERSPACE, uap->path, &context);
2041 error = namei(&nd);
2042 if (error)
2043 return (error);
2044 dvp = nd.ni_dvp;
2045 vp = nd.ni_vp;
2046
2047 if (vp == NULLVP && (nd.ni_cnd.cn_flags & ISWHITEOUT)) {
2048 error = VNOP_WHITEOUT(dvp, &nd.ni_cnd, DELETE, &context);
2049 } else
2050 error = EEXIST;
2051
2052 /*
2053 * nameidone has to happen before we vnode_put(dvp)
2054 * since it may need to release the fs_nodelock on the dvp
2055 */
2056 nameidone(&nd);
2057
2058 if (vp)
2059 vnode_put(vp);
2060 vnode_put(dvp);
2061
2062 return (error);
2063 }
2064
2065 /*
2066 * Delete a name from the filesystem.
2067 */
2068 /* ARGSUSED */
2069 static int
2070 _unlink(struct proc *p, struct unlink_args *uap, __unused register_t *retval, int nodelbusy)
2071 {
2072 vnode_t vp, dvp;
2073 int error;
2074 struct nameidata nd;
2075 struct vfs_context context;
2076 struct componentname *cnp;
2077 int flags = 0;
2078
2079 context.vc_proc = p;
2080 context.vc_ucred = kauth_cred_get();
2081
2082 NDINIT(&nd, DELETE, LOCKPARENT | AUDITVNPATH1,
2083 UIO_USERSPACE, uap->path, &context);
2084 cnp = &nd.ni_cnd;
2085
2086 /* With Carbon delete semantics, busy files cannot be deleted */
2087 if (nodelbusy)
2088 flags |= VNODE_REMOVE_NODELETEBUSY;
2089
2090 error = namei(&nd);
2091 if (error)
2092 return (error);
2093 dvp = nd.ni_dvp;
2094 vp = nd.ni_vp;
2095
2096 if (vp->v_type == VDIR) {
2097 error = EPERM; /* POSIX */
2098 } else {
2099 /*
2100 * The root of a mounted filesystem cannot be deleted.
2101 */
2102 if (vp->v_flag & VROOT) {
2103 error = EBUSY;
2104 }
2105 }
2106 /* authorize the delete operation */
2107 if (!error)
2108 error = vnode_authorize(vp, nd.ni_dvp, KAUTH_VNODE_DELETE, &context);
2109
2110 if (!error) {
2111 char *path = NULL;
2112 int len;
2113 fse_info finfo;
2114
2115 if (need_fsevent(FSE_DELETE, dvp)) {
2116 path = get_pathbuff();
2117 len = MAXPATHLEN;
2118 vn_getpath(vp, path, &len);
2119 get_fse_info(vp, &finfo, &context);
2120 }
2121 error = VNOP_REMOVE(dvp, vp, &nd.ni_cnd, flags, &context);
2122
2123 if ( !error && path != NULL) {
2124 add_fsevent(FSE_DELETE, &context,
2125 FSE_ARG_STRING, len, path,
2126 FSE_ARG_FINFO, &finfo,
2127 FSE_ARG_DONE);
2128 }
2129 if (path != NULL)
2130 release_pathbuff(path);
2131 }
2132 /*
2133 * nameidone has to happen before we vnode_put(dvp)
2134 * since it may need to release the fs_nodelock on the dvp
2135 */
2136 nameidone(&nd);
2137 vnode_put(dvp);
2138 vnode_put(vp);
2139 return (error);
2140 }
2141
2142 /*
2143 * Delete a name from the filesystem using POSIX semantics.
2144 */
2145 int
2146 unlink(p, uap, retval)
2147 struct proc *p;
2148 struct unlink_args *uap;
2149 register_t *retval;
2150 {
2151 return _unlink(p, uap, retval, 0);
2152 }
2153
2154 /*
2155 * Delete a name from the filesystem using Carbon semantics.
2156 */
2157 int
2158 delete(p, uap, retval)
2159 struct proc *p;
2160 struct delete_args *uap;
2161 register_t *retval;
2162 {
2163 return _unlink(p, (struct unlink_args *)uap, retval, 1);
2164 }
2165
2166 /*
2167 * Reposition read/write file offset.
2168 */
2169 int
2170 lseek(p, uap, retval)
2171 struct proc *p;
2172 register struct lseek_args *uap;
2173 off_t *retval;
2174 {
2175 struct fileproc *fp;
2176 struct vnode *vp;
2177 struct vfs_context context;
2178 off_t offset = uap->offset, file_size;
2179 int error;
2180
2181 if ( (error = fp_getfvp(p,uap->fd, &fp, &vp)) ) {
2182 if (error == ENOTSUP)
2183 return (ESPIPE);
2184 return (error);
2185 }
2186 if (vnode_isfifo(vp)) {
2187 file_drop(uap->fd);
2188 return(ESPIPE);
2189 }
2190 if ( (error = vnode_getwithref(vp)) ) {
2191 file_drop(uap->fd);
2192 return(error);
2193 }
2194
2195 switch (uap->whence) {
2196 case L_INCR:
2197 offset += fp->f_fglob->fg_offset;
2198 break;
2199 case L_XTND:
2200 context.vc_proc = p;
2201 context.vc_ucred = kauth_cred_get();
2202 if ((error = vnode_size(vp, &file_size, &context)) != 0)
2203 break;
2204 offset += file_size;
2205 break;
2206 case L_SET:
2207 break;
2208 default:
2209 error = EINVAL;
2210 }
2211 if (error == 0) {
2212 if (uap->offset > 0 && offset < 0) {
2213 /* Incremented/relative move past max size */
2214 error = EOVERFLOW;
2215 } else {
2216 /*
2217 * Allow negative offsets on character devices, per
2218 * POSIX 1003.1-2001. Most likely for writing disk
2219 * labels.
2220 */
2221 if (offset < 0 && vp->v_type != VCHR) {
2222 /* Decremented/relative move before start */
2223 error = EINVAL;
2224 } else {
2225 /* Success */
2226 fp->f_fglob->fg_offset = offset;
2227 *retval = fp->f_fglob->fg_offset;
2228 }
2229 }
2230 }
2231 (void)vnode_put(vp);
2232 file_drop(uap->fd);
2233 return (error);
2234 }
2235
2236
2237 /*
2238 * Check access permissions.
2239 */
2240 static int
2241 access1(vnode_t vp, vnode_t dvp, int uflags, vfs_context_t ctx)
2242 {
2243 kauth_action_t action;
2244 int error;
2245
2246 /*
2247 * If just the regular access bits, convert them to something
2248 * that vnode_authorize will understand.
2249 */
2250 if (!(uflags & _ACCESS_EXTENDED_MASK)) {
2251 action = 0;
2252 if (uflags & R_OK)
2253 action |= KAUTH_VNODE_READ_DATA; /* aka KAUTH_VNODE_LIST_DIRECTORY */
2254 if (uflags & W_OK) {
2255 if (vnode_isdir(vp)) {
2256 action |= KAUTH_VNODE_ADD_FILE |
2257 KAUTH_VNODE_ADD_SUBDIRECTORY;
2258 /* might want delete rights here too */
2259 } else {
2260 action |= KAUTH_VNODE_WRITE_DATA;
2261 }
2262 }
2263 if (uflags & X_OK) {
2264 if (vnode_isdir(vp)) {
2265 action |= KAUTH_VNODE_SEARCH;
2266 } else {
2267 action |= KAUTH_VNODE_EXECUTE;
2268 }
2269 }
2270 } else {
2271 /* take advantage of definition of uflags */
2272 action = uflags >> 8;
2273 }
2274
2275 /* action == 0 means only check for existence */
2276 if (action != 0) {
2277 error = vnode_authorize(vp, dvp, action | KAUTH_VNODE_ACCESS, ctx);
2278 } else {
2279 error = 0;
2280 }
2281
2282 return(error);
2283 }
2284
2285
2286
2287 /* XXX need to support the check-as uid argument */
2288 int
2289 access_extended(__unused struct proc *p, struct access_extended_args *uap, __unused register_t *retval)
2290 {
2291 struct accessx_descriptor *input;
2292 errno_t *result;
2293 int error, limit, nent, i, j, wantdelete;
2294 struct vfs_context context;
2295 struct nameidata nd;
2296 int niopts;
2297 vnode_t vp, dvp;
2298
2299 input = NULL;
2300 result = NULL;
2301 error = 0;
2302 vp = NULL;
2303 dvp = NULL;
2304 context.vc_ucred = NULL;
2305
2306 /* check input size and fetch descriptor array into allocated storage */
2307 if (uap->size > ACCESSX_MAX_TABLESIZE)
2308 return(ENOMEM);
2309 if (uap->size < sizeof(struct accessx_descriptor))
2310 return(EINVAL);
2311 MALLOC(input, struct accessx_descriptor *, uap->size, M_TEMP, M_WAITOK);
2312 if (input == NULL) {
2313 error = ENOMEM;
2314 goto out;
2315 }
2316 error = copyin(uap->entries, input, uap->size);
2317 if (error)
2318 goto out;
2319
2320 /*
2321 * Access is defined as checking against the process'
2322 * real identity, even if operations are checking the
2323 * effective identity. So we need to tweak the credential
2324 * in the context.
2325 */
2326 context.vc_ucred = kauth_cred_copy_real(kauth_cred_get());
2327 context.vc_proc = current_proc();
2328
2329 /*
2330 * Find out how many entries we have, so we can allocate the result array.
2331 */
2332 limit = uap->size / sizeof(struct accessx_descriptor);
2333 nent = limit;
2334 wantdelete = 0;
2335 for (i = 0; i < nent; i++) {
2336 /*
2337 * Take the offset to the name string for this entry and convert to an
2338 * input array index, which would be one off the end of the array if this
2339 * was the lowest-addressed name string.
2340 */
2341 j = input[i].ad_name_offset / sizeof(struct accessx_descriptor);
2342 /* bad input */
2343 if (j > limit) {
2344 error = EINVAL;
2345 goto out;
2346 }
2347 /* implicit reference to previous name, not a real offset */
2348 if (j == 0) {
2349 /* first entry must have a name string */
2350 if (i == 0) {
2351 error = EINVAL;
2352 goto out;
2353 }
2354 continue;
2355 }
2356 if (j < nent)
2357 nent = j;
2358 }
2359 if (nent > ACCESSX_MAX_DESCRIPTORS) {
2360 error = ENOMEM;
2361 goto out;
2362 }
2363 MALLOC(result, errno_t *, nent * sizeof(errno_t), M_TEMP, M_WAITOK);
2364 if (result == NULL) {
2365 error = ENOMEM;
2366 goto out;
2367 }
2368
2369 /*
2370 * Do the work.
2371 */
2372 error = 0;
2373 for (i = 0; i < nent; i++) {
2374 /*
2375 * Looking up a new name?
2376 */
2377 if (input[i].ad_name_offset != 0) {
2378 /* discard old vnodes */
2379 if (vp) {
2380 vnode_put(vp);
2381 vp = NULL;
2382 }
2383 if (dvp) {
2384 vnode_put(dvp);
2385 dvp = NULL;
2386 }
2387
2388 /* scan forwards to see if we need the parent this time */
2389 wantdelete = input[i].ad_flags & _DELETE_OK;
2390 for (j = i + 1; (j < nent) && (input[j].ad_name_offset == 0); j++)
2391 if (input[j].ad_flags & _DELETE_OK)
2392 wantdelete = 1;
2393
2394 niopts = FOLLOW | AUDITVNPATH1;
2395 /* need parent for vnode_authorize for deletion test */
2396 if (wantdelete)
2397 niopts |= WANTPARENT;
2398
2399 /* do the lookup */
2400 NDINIT(&nd, LOOKUP, niopts, UIO_SYSSPACE, CAST_USER_ADDR_T((const char *)input + input[i].ad_name_offset), &context);
2401 error = namei(&nd);
2402 if (!error) {
2403 vp = nd.ni_vp;
2404 if (wantdelete)
2405 dvp = nd.ni_dvp;
2406 }
2407 nameidone(&nd);
2408 }
2409
2410 /*
2411 * Handle lookup errors.
2412 */
2413 switch(error) {
2414 case ENOENT:
2415 case EACCES:
2416 case EPERM:
2417 case ENOTDIR:
2418 result[i] = error;
2419 break;
2420 case 0:
2421 /* run this access check */
2422 result[i] = access1(vp, dvp, input[i].ad_flags, &context);
2423 break;
2424 default:
2425 /* fatal lookup error */
2426
2427 goto out;
2428 }
2429 }
2430
2431 /* copy out results */
2432 error = copyout(result, uap->results, nent * sizeof(errno_t));
2433
2434 out:
2435 if (input)
2436 FREE(input, M_TEMP);
2437 if (result)
2438 FREE(result, M_TEMP);
2439 if (vp)
2440 vnode_put(vp);
2441 if (dvp)
2442 vnode_put(dvp);
2443 if (context.vc_ucred)
2444 kauth_cred_rele(context.vc_ucred);
2445 return(error);
2446 }
2447
2448 int
2449 access(__unused struct proc *p, register struct access_args *uap, __unused register_t *retval)
2450 {
2451 int error;
2452 struct nameidata nd;
2453 int niopts;
2454 struct vfs_context context;
2455
2456 /*
2457 * Access is defined as checking against the process'
2458 * real identity, even if operations are checking the
2459 * effective identity. So we need to tweak the credential
2460 * in the context.
2461 */
2462 context.vc_ucred = kauth_cred_copy_real(kauth_cred_get());
2463 context.vc_proc = current_proc();
2464
2465 niopts = FOLLOW | AUDITVNPATH1;
2466 /* need parent for vnode_authorize for deletion test */
2467 if (uap->flags & _DELETE_OK)
2468 niopts |= WANTPARENT;
2469 NDINIT(&nd, LOOKUP, niopts, UIO_USERSPACE, uap->path, &context);
2470 error = namei(&nd);
2471 if (error)
2472 goto out;
2473
2474 error = access1(nd.ni_vp, nd.ni_dvp, uap->flags, &context);
2475
2476 vnode_put(nd.ni_vp);
2477 if (uap->flags & _DELETE_OK)
2478 vnode_put(nd.ni_dvp);
2479 nameidone(&nd);
2480
2481 out:
2482 kauth_cred_rele(context.vc_ucred);
2483 return(error);
2484 }
2485
2486
2487 static int
2488 stat2(vfs_context_t ctx, struct nameidata *ndp, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size)
2489 {
2490 struct stat sb;
2491 struct user_stat user_sb;
2492 caddr_t sbp;
2493 int error, my_size;
2494 kauth_filesec_t fsec;
2495 size_t xsecurity_bufsize;
2496
2497 error = namei(ndp);
2498 if (error)
2499 return (error);
2500 fsec = KAUTH_FILESEC_NONE;
2501 error = vn_stat(ndp->ni_vp, &sb, (xsecurity != USER_ADDR_NULL ? &fsec : NULL), ctx);
2502 vnode_put(ndp->ni_vp);
2503 nameidone(ndp);
2504
2505 if (error)
2506 return (error);
2507 /* Zap spare fields */
2508 sb.st_lspare = 0;
2509 sb.st_qspare[0] = 0LL;
2510 sb.st_qspare[1] = 0LL;
2511 if (IS_64BIT_PROCESS(vfs_context_proc(ctx))) {
2512 munge_stat(&sb, &user_sb);
2513 my_size = sizeof(user_sb);
2514 sbp = (caddr_t)&user_sb;
2515 }
2516 else {
2517 my_size = sizeof(sb);
2518 sbp = (caddr_t)&sb;
2519 }
2520 if ((error = copyout(sbp, ub, my_size)) != 0)
2521 goto out;
2522
2523 /* caller wants extended security information? */
2524 if (xsecurity != USER_ADDR_NULL) {
2525
2526 /* did we get any? */
2527 if (fsec == KAUTH_FILESEC_NONE) {
2528 if (susize(xsecurity_size, 0) != 0) {
2529 error = EFAULT;
2530 goto out;
2531 }
2532 } else {
2533 /* find the user buffer size */
2534 xsecurity_bufsize = fusize(xsecurity_size);
2535
2536 /* copy out the actual data size */
2537 if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) {
2538 error = EFAULT;
2539 goto out;
2540 }
2541
2542 /* if the caller supplied enough room, copy out to it */
2543 if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec))
2544 error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec));
2545 }
2546 }
2547 out:
2548 if (fsec != KAUTH_FILESEC_NONE)
2549 kauth_filesec_free(fsec);
2550 return (error);
2551 }
2552
2553 /*
2554 * Get file status; this version follows links.
2555 */
2556 static int
2557 stat1(struct proc *p, user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size)
2558 {
2559 struct nameidata nd;
2560 struct vfs_context context;
2561
2562 context.vc_proc = p;
2563 context.vc_ucred = kauth_cred_get();
2564
2565 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
2566 UIO_USERSPACE, path, &context);
2567 return(stat2(&context, &nd, ub, xsecurity, xsecurity_size));
2568 }
2569
2570 int
2571 stat_extended(struct proc *p, struct stat_extended_args *uap, __unused register_t *retval)
2572 {
2573 return (stat1(p, uap->path, uap->ub, uap->xsecurity, uap->xsecurity_size));
2574 }
2575
2576 int
2577 stat(struct proc *p, struct stat_args *uap, __unused register_t *retval)
2578 {
2579 return(stat1(p, uap->path, uap->ub, 0, 0));
2580 }
2581
2582 /*
2583 * Get file status; this version does not follow links.
2584 */
2585 static int
2586 lstat1(struct proc *p, user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size)
2587 {
2588 struct nameidata nd;
2589 struct vfs_context context;
2590
2591 context.vc_proc = p;
2592 context.vc_ucred = kauth_cred_get();
2593
2594 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNPATH1,
2595 UIO_USERSPACE, path, &context);
2596
2597 return(stat2(&context, &nd, ub, xsecurity, xsecurity_size));
2598 }
2599
2600 int
2601 lstat_extended(struct proc *p, struct lstat_extended_args *uap, __unused register_t *retval)
2602 {
2603 return (lstat1(p, uap->path, uap->ub, uap->xsecurity, uap->xsecurity_size));
2604 }
2605
2606 int
2607 lstat(struct proc *p, struct lstat_args *uap, __unused register_t *retval)
2608 {
2609 return(lstat1(p, uap->path, uap->ub, 0, 0));
2610 }
2611
2612 /*
2613 * Get configurable pathname variables.
2614 */
2615 /* ARGSUSED */
2616 int
2617 pathconf(p, uap, retval)
2618 struct proc *p;
2619 register struct pathconf_args *uap;
2620 register_t *retval;
2621 {
2622 int error;
2623 struct nameidata nd;
2624 struct vfs_context context;
2625
2626 context.vc_proc = p;
2627 context.vc_ucred = kauth_cred_get();
2628
2629 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
2630 UIO_USERSPACE, uap->path, &context);
2631 error = namei(&nd);
2632 if (error)
2633 return (error);
2634
2635 error = vn_pathconf(nd.ni_vp, uap->name, retval, &context);
2636
2637 vnode_put(nd.ni_vp);
2638 nameidone(&nd);
2639 return (error);
2640 }
2641
2642 /*
2643 * Return target name of a symbolic link.
2644 */
2645 /* ARGSUSED */
2646 int
2647 readlink(p, uap, retval)
2648 struct proc *p;
2649 register struct readlink_args *uap;
2650 register_t *retval;
2651 {
2652 register struct vnode *vp;
2653 uio_t auio;
2654 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
2655 int error;
2656 struct nameidata nd;
2657 struct vfs_context context;
2658 char uio_buf[ UIO_SIZEOF(1) ];
2659
2660 context.vc_proc = p;
2661 context.vc_ucred = kauth_cred_get();
2662
2663 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNPATH1,
2664 UIO_USERSPACE, uap->path, &context);
2665 error = namei(&nd);
2666 if (error)
2667 return (error);
2668 vp = nd.ni_vp;
2669
2670 nameidone(&nd);
2671
2672 auio = uio_createwithbuffer(1, 0, spacetype, UIO_READ,
2673 &uio_buf[0], sizeof(uio_buf));
2674 uio_addiov(auio, uap->buf, uap->count);
2675 if (vp->v_type != VLNK)
2676 error = EINVAL;
2677 else {
2678 error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_DATA, &context);
2679 if (error == 0)
2680 error = VNOP_READLINK(vp, auio, &context);
2681 }
2682 vnode_put(vp);
2683 // LP64todo - fix this
2684 *retval = uap->count - (int)uio_resid(auio);
2685 return (error);
2686 }
2687
2688 /*
2689 * Change file flags.
2690 */
2691 static int
2692 chflags1(vnode_t vp, int flags, vfs_context_t ctx)
2693 {
2694 struct vnode_attr va;
2695 kauth_action_t action;
2696 int error;
2697
2698 VATTR_INIT(&va);
2699 VATTR_SET(&va, va_flags, flags);
2700
2701 /* request authorisation, disregard immutability */
2702 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)
2703 goto out;
2704 /*
2705 * Request that the auth layer disregard those file flags it's allowed to when
2706 * authorizing this operation; we need to do this in order to be able to
2707 * clear immutable flags.
2708 */
2709 if (action && ((error = vnode_authorize(vp, NULL, action | KAUTH_VNODE_NOIMMUTABLE, ctx)) != 0))
2710 goto out;
2711 error = vnode_setattr(vp, &va, ctx);
2712
2713 out:
2714 vnode_put(vp);
2715 return(error);
2716 }
2717
2718 /*
2719 * Change flags of a file given a path name.
2720 */
2721 /* ARGSUSED */
2722 int
2723 chflags(struct proc *p, register struct chflags_args *uap, __unused register_t *retval)
2724 {
2725 register struct vnode *vp;
2726 struct vfs_context context;
2727 int error;
2728 struct nameidata nd;
2729
2730 context.vc_proc = p;
2731 context.vc_ucred = kauth_cred_get();
2732
2733 AUDIT_ARG(fflags, uap->flags);
2734 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
2735 UIO_USERSPACE, uap->path, &context);
2736 error = namei(&nd);
2737 if (error)
2738 return (error);
2739 vp = nd.ni_vp;
2740 nameidone(&nd);
2741
2742 error = chflags1(vp, uap->flags, &context);
2743
2744 return(error);
2745 }
2746
2747 /*
2748 * Change flags of a file given a file descriptor.
2749 */
2750 /* ARGSUSED */
2751 int
2752 fchflags(struct proc *p, register struct fchflags_args *uap, __unused register_t *retval)
2753 {
2754 struct vfs_context context;
2755 struct vnode *vp;
2756 int error;
2757
2758 AUDIT_ARG(fd, uap->fd);
2759 AUDIT_ARG(fflags, uap->flags);
2760 if ( (error = file_vnode(uap->fd, &vp)) )
2761 return (error);
2762
2763 if ((error = vnode_getwithref(vp))) {
2764 file_drop(uap->fd);
2765 return(error);
2766 }
2767
2768 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
2769
2770 context.vc_proc = p;
2771 context.vc_ucred = kauth_cred_get();
2772
2773 error = chflags1(vp, uap->flags, &context);
2774
2775 file_drop(uap->fd);
2776 return (error);
2777 }
2778
2779 /*
2780 * Change security information on a filesystem object.
2781 */
2782 static int
2783 chmod2(vfs_context_t ctx, struct vnode *vp, struct vnode_attr *vap)
2784 {
2785 kauth_action_t action;
2786 int error;
2787
2788 AUDIT_ARG(mode, (mode_t)vap->va_mode);
2789 #warning XXX audit new args
2790
2791 /* make sure that the caller is allowed to set this security information */
2792 if (((error = vnode_authattr(vp, vap, &action, ctx)) != 0) ||
2793 ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)) {
2794 if (error == EACCES)
2795 error = EPERM;
2796 return(error);
2797 }
2798
2799 error = vnode_setattr(vp, vap, ctx);
2800
2801 return (error);
2802 }
2803
2804
2805 /*
2806 * Change mode of a file given path name.
2807 */
2808 static int
2809 chmod1(vfs_context_t ctx, user_addr_t path, struct vnode_attr *vap)
2810 {
2811 struct nameidata nd;
2812 int error;
2813
2814 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
2815 UIO_USERSPACE, path, ctx);
2816 if ((error = namei(&nd)))
2817 return (error);
2818 error = chmod2(ctx, nd.ni_vp, vap);
2819 vnode_put(nd.ni_vp);
2820 nameidone(&nd);
2821 return(error);
2822 }
2823
2824 int
2825 chmod_extended(struct proc *p, struct chmod_extended_args *uap, __unused register_t *retval)
2826 {
2827 struct vfs_context context;
2828 int error;
2829 struct vnode_attr va;
2830 kauth_filesec_t xsecdst;
2831
2832 VATTR_INIT(&va);
2833 if (uap->mode != -1)
2834 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
2835 if (uap->uid != KAUTH_UID_NONE)
2836 VATTR_SET(&va, va_uid, uap->uid);
2837 if (uap->gid != KAUTH_GID_NONE)
2838 VATTR_SET(&va, va_gid, uap->gid);
2839
2840 xsecdst = NULL;
2841 switch(uap->xsecurity) {
2842 /* explicit remove request */
2843 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
2844 VATTR_SET(&va, va_acl, NULL);
2845 break;
2846 /* not being set */
2847 case USER_ADDR_NULL:
2848 break;
2849 default:
2850 if ((error = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
2851 return(error);
2852 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
2853 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va.va_acl->acl_entrycount);
2854 }
2855 context.vc_proc = p;
2856 context.vc_ucred = kauth_cred_get();
2857
2858 error = chmod1(&context, uap->path, &va);
2859
2860 if (xsecdst != NULL)
2861 kauth_filesec_free(xsecdst);
2862 return(error);
2863 }
2864
2865 int
2866 chmod(struct proc *p, register struct chmod_args *uap, __unused register_t *retval)
2867 {
2868 struct vfs_context context;
2869 struct vnode_attr va;
2870
2871 VATTR_INIT(&va);
2872 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
2873
2874 context.vc_proc = p;
2875 context.vc_ucred = kauth_cred_get();
2876
2877 return(chmod1(&context, uap->path, &va));
2878 }
2879
2880 /*
2881 * Change mode of a file given a file descriptor.
2882 */
2883 static int
2884 fchmod1(struct proc *p, int fd, struct vnode_attr *vap)
2885 {
2886 struct vnode *vp;
2887 int error;
2888 struct vfs_context context;
2889
2890 context.vc_proc = p;
2891 context.vc_ucred = kauth_cred_get();
2892
2893 AUDIT_ARG(fd, fd);
2894
2895 if ((error = file_vnode(fd, &vp)) != 0)
2896 return (error);
2897 if ((error = vnode_getwithref(vp)) != 0) {
2898 file_drop(fd);
2899 return(error);
2900 }
2901 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
2902
2903 error = chmod2(&context, vp, vap);
2904 (void)vnode_put(vp);
2905 file_drop(fd);
2906
2907 return (error);
2908 }
2909
2910 int
2911 fchmod_extended(struct proc *p, struct fchmod_extended_args *uap, __unused register_t *retval)
2912 {
2913 int error;
2914 struct vnode_attr va;
2915 kauth_filesec_t xsecdst;
2916
2917 VATTR_INIT(&va);
2918 if (uap->mode != -1)
2919 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
2920 if (uap->uid != KAUTH_UID_NONE)
2921 VATTR_SET(&va, va_uid, uap->uid);
2922 if (uap->gid != KAUTH_GID_NONE)
2923 VATTR_SET(&va, va_gid, uap->gid);
2924
2925 xsecdst = NULL;
2926 switch(uap->xsecurity) {
2927 case USER_ADDR_NULL:
2928 VATTR_SET(&va, va_acl, NULL);
2929 break;
2930 case CAST_USER_ADDR_T(-1):
2931 break;
2932 default:
2933 if ((error = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
2934 return(error);
2935 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
2936 }
2937
2938 error = fchmod1(p, uap->fd, &va);
2939
2940
2941 switch(uap->xsecurity) {
2942 case USER_ADDR_NULL:
2943 case CAST_USER_ADDR_T(-1):
2944 break;
2945 default:
2946 if (xsecdst != NULL)
2947 kauth_filesec_free(xsecdst);
2948 }
2949 return(error);
2950 }
2951
2952 int
2953 fchmod(struct proc *p, register struct fchmod_args *uap, __unused register_t *retval)
2954 {
2955 struct vnode_attr va;
2956
2957 VATTR_INIT(&va);
2958 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
2959
2960 return(fchmod1(p, uap->fd, &va));
2961 }
2962
2963
2964 /*
2965 * Set ownership given a path name.
2966 */
2967 /* ARGSUSED */
2968 static int
2969 chown1(vfs_context_t ctx, register struct chown_args *uap, __unused register_t *retval, int follow)
2970 {
2971 register struct vnode *vp;
2972 struct vnode_attr va;
2973 int error;
2974 struct nameidata nd;
2975 kauth_action_t action;
2976
2977 AUDIT_ARG(owner, uap->uid, uap->gid);
2978
2979 NDINIT(&nd, LOOKUP, (follow ? FOLLOW : 0) | AUDITVNPATH1,
2980 UIO_USERSPACE, uap->path, ctx);
2981 error = namei(&nd);
2982 if (error)
2983 return (error);
2984 vp = nd.ni_vp;
2985
2986 nameidone(&nd);
2987
2988 /*
2989 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2990 * by looking for chown() calls on /dev/console from a console process.
2991 */
2992 if ((vp) && (vp->v_type == VBLK || vp->v_type == VCHR) && (vp->v_specinfo) &&
2993 (major(vp->v_specinfo->si_rdev) == CONSMAJOR) &&
2994 (minor(vp->v_specinfo->si_rdev) == 0)) {
2995 console_user = uap->uid;
2996 };
2997 VATTR_INIT(&va);
2998 if (uap->uid != VNOVAL)
2999 VATTR_SET(&va, va_uid, uap->uid);
3000 if (uap->gid != VNOVAL)
3001 VATTR_SET(&va, va_gid, uap->gid);
3002
3003 /* preflight and authorize attribute changes */
3004 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)
3005 goto out;
3006 if (action && ((error = vnode_authorize(vp, NULL, action, ctx)) != 0))
3007 goto out;
3008 error = vnode_setattr(vp, &va, ctx);
3009
3010 out:
3011 /*
3012 * EACCES is only allowed from namei(); permissions failure should
3013 * return EPERM, so we need to translate the error code.
3014 */
3015 if (error == EACCES)
3016 error = EPERM;
3017
3018 vnode_put(vp);
3019 return (error);
3020 }
3021
3022 int
3023 chown(struct proc *p, register struct chown_args *uap, register_t *retval)
3024 {
3025 struct vfs_context context;
3026
3027 context.vc_proc = p;
3028 context.vc_ucred = kauth_cred_get();
3029
3030 return chown1(&context, uap, retval, 1);
3031 }
3032
3033 int
3034 lchown(struct proc *p, register struct lchown_args *uap, register_t *retval)
3035 {
3036 struct vfs_context context;
3037
3038 context.vc_proc = p;
3039 context.vc_ucred = kauth_cred_get();
3040
3041 /* Argument list identical, but machine generated; cast for chown1() */
3042 return chown1(&context, (struct chown_args *)uap, retval, 0);
3043 }
3044
3045 /*
3046 * Set ownership given a file descriptor.
3047 */
3048 /* ARGSUSED */
3049 int
3050 fchown(struct proc *p, register struct fchown_args *uap, __unused register_t *retval)
3051 {
3052 struct vnode_attr va;
3053 struct vfs_context context;
3054 struct vnode *vp;
3055 int error;
3056 kauth_action_t action;
3057
3058 AUDIT_ARG(owner, uap->uid, uap->gid);
3059 AUDIT_ARG(fd, uap->fd);
3060
3061 if ( (error = file_vnode(uap->fd, &vp)) )
3062 return (error);
3063
3064 if ( (error = vnode_getwithref(vp)) ) {
3065 file_drop(uap->fd);
3066 return(error);
3067 }
3068 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
3069
3070 VATTR_INIT(&va);
3071 if (uap->uid != VNOVAL)
3072 VATTR_SET(&va, va_uid, uap->uid);
3073 if (uap->gid != VNOVAL)
3074 VATTR_SET(&va, va_gid, uap->gid);
3075
3076 context.vc_proc = p;
3077 context.vc_ucred = kauth_cred_get();
3078
3079 /* preflight and authorize attribute changes */
3080 if ((error = vnode_authattr(vp, &va, &action, &context)) != 0)
3081 goto out;
3082 if (action && ((error = vnode_authorize(vp, NULL, action, &context)) != 0)) {
3083 if (error == EACCES)
3084 error = EPERM;
3085 goto out;
3086 }
3087 error = vnode_setattr(vp, &va, &context);
3088
3089 out:
3090 (void)vnode_put(vp);
3091 file_drop(uap->fd);
3092 return (error);
3093 }
3094
3095 static int
3096 getutimes(usrtvp, tsp)
3097 user_addr_t usrtvp;
3098 struct timespec *tsp;
3099 {
3100 struct user_timeval tv[2];
3101 int error;
3102
3103 if (usrtvp == USER_ADDR_NULL) {
3104 struct timeval old_tv;
3105 /* XXX Y2038 bug because of microtime argument */
3106 microtime(&old_tv);
3107 TIMEVAL_TO_TIMESPEC(&old_tv, &tsp[0]);
3108 tsp[1] = tsp[0];
3109 } else {
3110 if (IS_64BIT_PROCESS(current_proc())) {
3111 error = copyin(usrtvp, (void *)tv, sizeof(tv));
3112 } else {
3113 struct timeval old_tv[2];
3114 error = copyin(usrtvp, (void *)old_tv, sizeof(old_tv));
3115 tv[0].tv_sec = old_tv[0].tv_sec;
3116 tv[0].tv_usec = old_tv[0].tv_usec;
3117 tv[1].tv_sec = old_tv[1].tv_sec;
3118 tv[1].tv_usec = old_tv[1].tv_usec;
3119 }
3120 if (error)
3121 return (error);
3122 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
3123 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
3124 }
3125 return 0;
3126 }
3127
3128 static int
3129 setutimes(vfs_context_t ctx, struct vnode *vp, const struct timespec *ts,
3130 int nullflag)
3131 {
3132 int error;
3133 struct vnode_attr va;
3134 kauth_action_t action;
3135
3136 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
3137
3138 VATTR_INIT(&va);
3139 VATTR_SET(&va, va_access_time, ts[0]);
3140 VATTR_SET(&va, va_modify_time, ts[1]);
3141 if (nullflag)
3142 va.va_vaflags |= VA_UTIMES_NULL;
3143
3144 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)
3145 goto out;
3146 /* since we may not need to auth anything, check here */
3147 if ((action != 0) && ((error = vnode_authorize(vp, NULL, action, ctx)) != 0))
3148 goto out;
3149 error = vnode_setattr(vp, &va, ctx);
3150
3151 out:
3152 return error;
3153 }
3154
3155 /*
3156 * Set the access and modification times of a file.
3157 */
3158 /* ARGSUSED */
3159 int
3160 utimes(struct proc *p, register struct utimes_args *uap, __unused register_t *retval)
3161 {
3162 struct timespec ts[2];
3163 user_addr_t usrtvp;
3164 int error;
3165 struct nameidata nd;
3166 struct vfs_context context;
3167
3168 context.vc_proc = p;
3169 context.vc_ucred = kauth_cred_get();
3170
3171 /* AUDIT: Needed to change the order of operations to do the
3172 * name lookup first because auditing wants the path.
3173 */
3174 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
3175 UIO_USERSPACE, uap->path, &context);
3176 error = namei(&nd);
3177 if (error)
3178 return (error);
3179 nameidone(&nd);
3180
3181 /*
3182 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
3183 * the current time instead.
3184 */
3185 usrtvp = uap->tptr;
3186 if ((error = getutimes(usrtvp, ts)) != 0)
3187 goto out;
3188
3189 error = setutimes(&context, nd.ni_vp, ts, usrtvp == USER_ADDR_NULL);
3190
3191 out:
3192 vnode_put(nd.ni_vp);
3193 return (error);
3194 }
3195
3196 /*
3197 * Set the access and modification times of a file.
3198 */
3199 /* ARGSUSED */
3200 int
3201 futimes(struct proc *p, register struct futimes_args *uap, __unused register_t *retval)
3202 {
3203 struct timespec ts[2];
3204 struct vnode *vp;
3205 user_addr_t usrtvp;
3206 int error;
3207 struct vfs_context context;
3208
3209 context.vc_proc = p;
3210 context.vc_ucred = kauth_cred_get();
3211
3212 AUDIT_ARG(fd, uap->fd);
3213 usrtvp = uap->tptr;
3214 if ((error = getutimes(usrtvp, ts)) != 0)
3215 return (error);
3216 if ((error = file_vnode(uap->fd, &vp)) != 0)
3217 return (error);
3218 if((error = vnode_getwithref(vp))) {
3219 file_drop(uap->fd);
3220 return(error);
3221 }
3222
3223 error = setutimes(&context, vp, ts, usrtvp == 0);
3224 vnode_put(vp);
3225 file_drop(uap->fd);
3226 return(error);
3227 }
3228
3229 /*
3230 * Truncate a file given its path name.
3231 */
3232 /* ARGSUSED */
3233 int
3234 truncate(struct proc *p, register struct truncate_args *uap, __unused register_t *retval)
3235 {
3236 register struct vnode *vp;
3237 struct vnode_attr va;
3238 struct vfs_context context;
3239 int error;
3240 struct nameidata nd;
3241 kauth_action_t action;
3242
3243 context.vc_proc = p;
3244 context.vc_ucred = kauth_cred_get();
3245
3246 if (uap->length < 0)
3247 return(EINVAL);
3248 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
3249 UIO_USERSPACE, uap->path, &context);
3250 if ((error = namei(&nd)))
3251 return (error);
3252 vp = nd.ni_vp;
3253
3254 nameidone(&nd);
3255
3256 VATTR_INIT(&va);
3257 VATTR_SET(&va, va_data_size, uap->length);
3258 if ((error = vnode_authattr(vp, &va, &action, &context)) != 0)
3259 goto out;
3260 if ((action != 0) && ((error = vnode_authorize(vp, NULL, action, &context)) != 0))
3261 goto out;
3262 error = vnode_setattr(vp, &va, &context);
3263 out:
3264 vnode_put(vp);
3265 return (error);
3266 }
3267
3268 /*
3269 * Truncate a file given a file descriptor.
3270 */
3271 /* ARGSUSED */
3272 int
3273 ftruncate(p, uap, retval)
3274 struct proc *p;
3275 register struct ftruncate_args *uap;
3276 register_t *retval;
3277 {
3278 struct vfs_context context;
3279 struct vnode_attr va;
3280 struct vnode *vp;
3281 struct fileproc *fp;
3282 int error ;
3283 int fd = uap->fd;
3284
3285 context.vc_proc = current_proc();
3286 context.vc_ucred = kauth_cred_get();
3287
3288 AUDIT_ARG(fd, uap->fd);
3289 if (uap->length < 0)
3290 return(EINVAL);
3291
3292 if ( (error = fp_lookup(p,fd,&fp,0)) ) {
3293 return(error);
3294 }
3295
3296 if (fp->f_fglob->fg_type == DTYPE_PSXSHM) {
3297 error = pshm_truncate(p, fp, uap->fd, uap->length, retval);
3298 goto out;
3299 }
3300 if (fp->f_fglob->fg_type != DTYPE_VNODE) {
3301 error = EINVAL;
3302 goto out;
3303 }
3304
3305 vp = (struct vnode *)fp->f_fglob->fg_data;
3306
3307 if ((fp->f_fglob->fg_flag & FWRITE) == 0) {
3308 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
3309 error = EINVAL;
3310 goto out;
3311 }
3312
3313 if ((error = vnode_getwithref(vp)) != 0) {
3314 goto out;
3315 }
3316
3317 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
3318
3319 VATTR_INIT(&va);
3320 VATTR_SET(&va, va_data_size, uap->length);
3321 error = vnode_setattr(vp, &va, &context);
3322 (void)vnode_put(vp);
3323 out:
3324 file_drop(fd);
3325 return (error);
3326 }
3327
3328
3329 /*
3330 * Sync an open file.
3331 */
3332 /* ARGSUSED */
3333 int
3334 fsync(struct proc *p, struct fsync_args *uap, __unused register_t *retval)
3335 {
3336 struct vnode *vp;
3337 struct fileproc *fp;
3338 struct vfs_context context;
3339 int error;
3340
3341 if ( (error = fp_getfvp(p, uap->fd, &fp, &vp)) )
3342 return (error);
3343 if ( (error = vnode_getwithref(vp)) ) {
3344 file_drop(uap->fd);
3345 return(error);
3346 }
3347 context.vc_proc = p;
3348 context.vc_ucred = fp->f_fglob->fg_cred;
3349
3350 error = VNOP_FSYNC(vp, MNT_WAIT, &context);
3351
3352 (void)vnode_put(vp);
3353 file_drop(uap->fd);
3354 return (error);
3355 }
3356
3357 /*
3358 * Duplicate files. Source must be a file, target must be a file or
3359 * must not exist.
3360 *
3361 * XXX Copyfile authorisation checking is woefully inadequate, and will not
3362 * perform inheritance correctly.
3363 */
3364 /* ARGSUSED */
3365 int
3366 copyfile(struct proc *p, register struct copyfile_args *uap, __unused register_t *retval)
3367 {
3368 vnode_t tvp, fvp, tdvp, sdvp;
3369 struct nameidata fromnd, tond;
3370 int error;
3371 struct vfs_context context;
3372
3373 context.vc_proc = p;
3374 context.vc_ucred = kauth_cred_get();
3375
3376 /* Check that the flags are valid. */
3377
3378 if (uap->flags & ~CPF_MASK) {
3379 return(EINVAL);
3380 }
3381
3382 NDINIT(&fromnd, LOOKUP, SAVESTART | AUDITVNPATH1,
3383 UIO_USERSPACE, uap->from, &context);
3384 if ((error = namei(&fromnd)))
3385 return (error);
3386 fvp = fromnd.ni_vp;
3387
3388 NDINIT(&tond, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | AUDITVNPATH2,
3389 UIO_USERSPACE, uap->to, &context);
3390 if ((error = namei(&tond))) {
3391 goto out1;
3392 }
3393 tdvp = tond.ni_dvp;
3394 tvp = tond.ni_vp;
3395
3396 if (tvp != NULL) {
3397 if (!(uap->flags & CPF_OVERWRITE)) {
3398 error = EEXIST;
3399 goto out;
3400 }
3401 }
3402 if (fvp->v_type == VDIR || (tvp && tvp->v_type == VDIR)) {
3403 error = EISDIR;
3404 goto out;
3405 }
3406
3407 if ((error = vnode_authorize(tdvp, NULL, KAUTH_VNODE_ADD_FILE, &context)) != 0)
3408 goto out;
3409
3410 if (fvp == tdvp)
3411 error = EINVAL;
3412 /*
3413 * If source is the same as the destination (that is the
3414 * same inode number) then there is nothing to do.
3415 * (fixed to have POSIX semantics - CSM 3/2/98)
3416 */
3417 if (fvp == tvp)
3418 error = -1;
3419 if (!error)
3420 error = VNOP_COPYFILE(fvp,tdvp,tvp,&tond.ni_cnd,uap->mode,uap->flags,&context);
3421 out:
3422 sdvp = tond.ni_startdir;
3423 /*
3424 * nameidone has to happen before we vnode_put(tdvp)
3425 * since it may need to release the fs_nodelock on the tdvp
3426 */
3427 nameidone(&tond);
3428
3429 if (tvp)
3430 vnode_put(tvp);
3431 vnode_put(tdvp);
3432 vnode_put(sdvp);
3433 out1:
3434 vnode_put(fvp);
3435
3436 if (fromnd.ni_startdir)
3437 vnode_put(fromnd.ni_startdir);
3438 nameidone(&fromnd);
3439
3440 if (error == -1)
3441 return (0);
3442 return (error);
3443 }
3444
3445
3446 /*
3447 * Rename files. Source and destination must either both be directories,
3448 * or both not be directories. If target is a directory, it must be empty.
3449 */
3450 /* ARGSUSED */
3451 int
3452 rename(proc_t p, register struct rename_args *uap, __unused register_t *retval)
3453 {
3454 vnode_t tvp, tdvp;
3455 vnode_t fvp, fdvp;
3456 struct nameidata fromnd, tond;
3457 struct vfs_context context;
3458 int error;
3459 int mntrename;
3460 char *oname, *from_name, *to_name;
3461 int from_len, to_len;
3462 int holding_mntlock;
3463 mount_t locked_mp = NULL;
3464 vnode_t oparent;
3465 fse_info from_finfo, to_finfo;
3466
3467 context.vc_proc = p;
3468 context.vc_ucred = kauth_cred_get();
3469 holding_mntlock = 0;
3470 retry:
3471 fvp = tvp = NULL;
3472 fdvp = tdvp = NULL;
3473 mntrename = FALSE;
3474
3475 NDINIT(&fromnd, DELETE, WANTPARENT | AUDITVNPATH1, UIO_USERSPACE, uap->from, &context);
3476
3477 if ( (error = namei(&fromnd)) )
3478 goto out1;
3479 fdvp = fromnd.ni_dvp;
3480 fvp = fromnd.ni_vp;
3481
3482 NDINIT(&tond, RENAME, WANTPARENT | AUDITVNPATH2, UIO_USERSPACE, uap->to, &context);
3483 if (fvp->v_type == VDIR)
3484 tond.ni_cnd.cn_flags |= WILLBEDIR;
3485
3486 if ( (error = namei(&tond)) ) {
3487 /*
3488 * Translate error code for rename("dir1", "dir2/.").
3489 */
3490 if (error == EISDIR && fvp->v_type == VDIR)
3491 error = EINVAL;
3492 goto out1;
3493 }
3494 tdvp = tond.ni_dvp;
3495 tvp = tond.ni_vp;
3496
3497 if (tvp != NULL) {
3498 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
3499 error = ENOTDIR;
3500 goto out1;
3501 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
3502 error = EISDIR;
3503 goto out1;
3504 }
3505 }
3506 if (fvp == tdvp) {
3507 error = EINVAL;
3508 goto out1;
3509 }
3510
3511 /*
3512 * Authorization.
3513 *
3514 * If tvp is a directory and not the same as fdvp, or tdvp is not the same as fdvp,
3515 * the node is moving between directories and we need rights to remove from the
3516 * old and add to the new.
3517 *
3518 * If tvp already exists and is not a directory, we need to be allowed to delete it.
3519 *
3520 * Note that we do not inherit when renaming. XXX this needs to be revisited to
3521 * implement the deferred-inherit bit.
3522 */
3523 {
3524 int moving = 0;
3525
3526 error = 0;
3527 if ((tvp != NULL) && vnode_isdir(tvp)) {
3528 if (tvp != fdvp)
3529 moving = 1;
3530 } else if (tdvp != fdvp) {
3531 moving = 1;
3532 }
3533 /*
3534 * must have delete rights to remove the old name even in the simple case of
3535 * fdvp == tdvp
3536 */
3537 if ((error = vnode_authorize(fvp, fdvp, KAUTH_VNODE_DELETE, &context)) != 0)
3538 goto auth_exit;
3539 if (moving) {
3540 /* moving into tdvp or tvp, must have rights to add */
3541 if ((error = vnode_authorize(((tvp != NULL) && vnode_isdir(tvp)) ? tvp : tdvp,
3542 NULL,
3543 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
3544 &context)) != 0)
3545 goto auth_exit;
3546 } else {
3547 /* node staying in same directory, must be allowed to add new name */
3548 if ((error = vnode_authorize(fdvp, NULL,
3549 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE, &context)) != 0)
3550 goto auth_exit;
3551 }
3552 /* overwriting tvp */
3553 if ((tvp != NULL) && !vnode_isdir(tvp) &&
3554 ((error = vnode_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, &context)) != 0))
3555 goto auth_exit;
3556
3557 /* XXX more checks? */
3558
3559 auth_exit:
3560 /* authorization denied */
3561 if (error != 0)
3562 goto out1;
3563 }
3564 /*
3565 * Allow the renaming of mount points.
3566 * - target must not exist
3567 * - target must reside in the same directory as source
3568 * - union mounts cannot be renamed
3569 * - "/" cannot be renamed
3570 */
3571 if ((fvp->v_flag & VROOT) &&
3572 (fvp->v_type == VDIR) &&
3573 (tvp == NULL) &&
3574 (fvp->v_mountedhere == NULL) &&
3575 (fdvp == tdvp) &&
3576 ((fvp->v_mount->mnt_flag & (MNT_UNION | MNT_ROOTFS)) == 0) &&
3577 (fvp->v_mount->mnt_vnodecovered != NULLVP)) {
3578 struct vnode *coveredvp;
3579
3580 /* switch fvp to the covered vnode */
3581 coveredvp = fvp->v_mount->mnt_vnodecovered;
3582 if ( (vnode_getwithref(coveredvp)) ) {
3583 error = ENOENT;
3584 goto out1;
3585 }
3586 vnode_put(fvp);
3587
3588 fvp = coveredvp;
3589 mntrename = TRUE;
3590 }
3591 /*
3592 * Check for cross-device rename.
3593 */
3594 if ((fvp->v_mount != tdvp->v_mount) ||
3595 (tvp && (fvp->v_mount != tvp->v_mount))) {
3596 error = EXDEV;
3597 goto out1;
3598 }
3599 /*
3600 * Avoid renaming "." and "..".
3601 */
3602 if (fvp->v_type == VDIR &&
3603 ((fdvp == fvp) ||
3604 (fromnd.ni_cnd.cn_namelen == 1 && fromnd.ni_cnd.cn_nameptr[0] == '.') ||
3605 ((fromnd.ni_cnd.cn_flags | tond.ni_cnd.cn_flags) & ISDOTDOT)) ) {
3606 error = EINVAL;
3607 goto out1;
3608 }
3609 /*
3610 * The following edge case is caught here:
3611 * (to cannot be a descendent of from)
3612 *
3613 * o fdvp
3614 * /
3615 * /
3616 * o fvp
3617 * \
3618 * \
3619 * o tdvp
3620 * /
3621 * /
3622 * o tvp
3623 */
3624 if (tdvp->v_parent == fvp) {
3625 error = EINVAL;
3626 goto out1;
3627 }
3628
3629 /*
3630 * If source is the same as the destination (that is the
3631 * same inode number) then there is nothing to do...
3632 * EXCEPT if the underlying file system supports case
3633 * insensitivity and is case preserving. In this case
3634 * the file system needs to handle the special case of
3635 * getting the same vnode as target (fvp) and source (tvp).
3636 *
3637 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
3638 * and _PC_CASE_PRESERVING can have this exception, and they need to
3639 * handle the special case of getting the same vnode as target and
3640 * source. NOTE: Then the target is unlocked going into vnop_rename,
3641 * so not to cause locking problems. There is a single reference on tvp.
3642 *
3643 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
3644 * that correct behaviour then is just to remove the source (link)
3645 */
3646 if (fvp == tvp && fdvp == tdvp) {
3647 if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
3648 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
3649 fromnd.ni_cnd.cn_namelen)) {
3650 goto out1;
3651 }
3652 }
3653
3654 if (holding_mntlock && fvp->v_mount != locked_mp) {
3655 /*
3656 * we're holding a reference and lock
3657 * on locked_mp, but it no longer matches
3658 * what we want to do... so drop our hold
3659 */
3660 mount_unlock_renames(locked_mp);
3661 mount_drop(locked_mp, 0);
3662 holding_mntlock = 0;
3663 }
3664 if (tdvp != fdvp && fvp->v_type == VDIR) {
3665 /*
3666 * serialize renames that re-shape
3667 * the tree... if holding_mntlock is
3668 * set, then we're ready to go...
3669 * otherwise we
3670 * first need to drop the iocounts
3671 * we picked up, second take the
3672 * lock to serialize the access,
3673 * then finally start the lookup
3674 * process over with the lock held
3675 */
3676 if (!holding_mntlock) {
3677 /*
3678 * need to grab a reference on
3679 * the mount point before we
3680 * drop all the iocounts... once
3681 * the iocounts are gone, the mount
3682 * could follow
3683 */
3684 locked_mp = fvp->v_mount;
3685 mount_ref(locked_mp, 0);
3686
3687 /*
3688 * nameidone has to happen before we vnode_put(tvp)
3689 * since it may need to release the fs_nodelock on the tvp
3690 */
3691 nameidone(&tond);
3692
3693 if (tvp)
3694 vnode_put(tvp);
3695 vnode_put(tdvp);
3696
3697 /*
3698 * nameidone has to happen before we vnode_put(fdvp)
3699 * since it may need to release the fs_nodelock on the fvp
3700 */
3701 nameidone(&fromnd);
3702
3703 vnode_put(fvp);
3704 vnode_put(fdvp);
3705
3706 mount_lock_renames(locked_mp);
3707 holding_mntlock = 1;
3708
3709 goto retry;
3710 }
3711 } else {
3712 /*
3713 * when we dropped the iocounts to take
3714 * the lock, we allowed the identity of
3715 * the various vnodes to change... if they did,
3716 * we may no longer be dealing with a rename
3717 * that reshapes the tree... once we're holding
3718 * the iocounts, the vnodes can't change type
3719 * so we're free to drop the lock at this point
3720 * and continue on
3721 */
3722 if (holding_mntlock) {
3723 mount_unlock_renames(locked_mp);
3724 mount_drop(locked_mp, 0);
3725 holding_mntlock = 0;
3726 }
3727 }
3728 // save these off so we can later verify that fvp is the same
3729 oname = fvp->v_name;
3730 oparent = fvp->v_parent;
3731
3732 if (need_fsevent(FSE_RENAME, fvp)) {
3733 get_fse_info(fvp, &from_finfo, &context);
3734
3735 if (tvp) {
3736 get_fse_info(tvp, &to_finfo, &context);
3737 }
3738 from_name = get_pathbuff();
3739 from_len = MAXPATHLEN;
3740 vn_getpath(fvp, from_name, &from_len);
3741
3742 to_name = get_pathbuff();
3743 to_len = MAXPATHLEN;
3744
3745 if (tvp && tvp->v_type != VDIR) {
3746 vn_getpath(tvp, to_name, &to_len);
3747 } else {
3748 vn_getpath(tdvp, to_name, &to_len);
3749 // if the path is not just "/", then append a "/"
3750 if (to_len > 2) {
3751 to_name[to_len-1] = '/';
3752 } else {
3753 to_len--;
3754 }
3755 strcpy(&to_name[to_len], tond.ni_cnd.cn_nameptr);
3756 to_len += tond.ni_cnd.cn_namelen + 1;
3757 to_name[to_len] = '\0';
3758 }
3759 } else {
3760 from_name = NULL;
3761 to_name = NULL;
3762 }
3763 error = VNOP_RENAME(fdvp, fvp, &fromnd.ni_cnd,
3764 tdvp, tvp, &tond.ni_cnd,
3765 &context);
3766
3767 if (holding_mntlock) {
3768 /*
3769 * we can drop our serialization
3770 * lock now
3771 */
3772 mount_unlock_renames(locked_mp);
3773 mount_drop(locked_mp, 0);
3774 holding_mntlock = 0;
3775 }
3776 if (error) {
3777 if (to_name != NULL)
3778 release_pathbuff(to_name);
3779 if (from_name != NULL)
3780 release_pathbuff(from_name);
3781 from_name = to_name = NULL;
3782
3783 goto out1;
3784 }
3785
3786 /* call out to allow 3rd party notification of rename.
3787 * Ignore result of kauth_authorize_fileop call.
3788 */
3789 kauth_authorize_fileop(vfs_context_ucred(&context), KAUTH_FILEOP_RENAME,
3790 (uintptr_t)from_name, (uintptr_t)to_name);
3791
3792 if (from_name != NULL && to_name != NULL) {
3793 if (tvp) {
3794 add_fsevent(FSE_RENAME, &context,
3795 FSE_ARG_STRING, from_len, from_name,
3796 FSE_ARG_FINFO, &from_finfo,
3797 FSE_ARG_STRING, to_len, to_name,
3798 FSE_ARG_FINFO, &to_finfo,
3799 FSE_ARG_DONE);
3800 } else {
3801 add_fsevent(FSE_RENAME, &context,
3802 FSE_ARG_STRING, from_len, from_name,
3803 FSE_ARG_FINFO, &from_finfo,
3804 FSE_ARG_STRING, to_len, to_name,
3805 FSE_ARG_DONE);
3806 }
3807 }
3808 if (to_name != NULL)
3809 release_pathbuff(to_name);
3810 if (from_name != NULL)
3811 release_pathbuff(from_name);
3812 from_name = to_name = NULL;
3813
3814 /*
3815 * update filesystem's mount point data
3816 */
3817 if (mntrename) {
3818 char *cp, *pathend, *mpname;
3819 char * tobuf;
3820 struct mount *mp;
3821 int maxlen;
3822 size_t len = 0;
3823
3824 mp = fvp->v_mountedhere;
3825
3826 if (vfs_busy(mp, LK_NOWAIT)) {
3827 error = EBUSY;
3828 goto out1;
3829 }
3830 MALLOC_ZONE(tobuf, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
3831
3832 error = copyinstr(uap->to, tobuf, MAXPATHLEN, &len);
3833 if (!error) {
3834 /* find current mount point prefix */
3835 pathend = &mp->mnt_vfsstat.f_mntonname[0];
3836 for (cp = pathend; *cp != '\0'; ++cp) {
3837 if (*cp == '/')
3838 pathend = cp + 1;
3839 }
3840 /* find last component of target name */
3841 for (mpname = cp = tobuf; *cp != '\0'; ++cp) {
3842 if (*cp == '/')
3843 mpname = cp + 1;
3844 }
3845 /* append name to prefix */
3846 maxlen = MAXPATHLEN - (pathend - mp->mnt_vfsstat.f_mntonname);
3847 bzero(pathend, maxlen);
3848 strncpy(pathend, mpname, maxlen - 1);
3849 }
3850 FREE_ZONE(tobuf, MAXPATHLEN, M_NAMEI);
3851
3852 vfs_unbusy(mp);
3853 }
3854 /*
3855 * fix up name & parent pointers. note that we first
3856 * check that fvp has the same name/parent pointers it
3857 * had before the rename call... this is a 'weak' check
3858 * at best...
3859 */
3860 if (oname == fvp->v_name && oparent == fvp->v_parent) {
3861 int update_flags;
3862
3863 update_flags = VNODE_UPDATE_NAME;
3864
3865 if (fdvp != tdvp)
3866 update_flags |= VNODE_UPDATE_PARENT;
3867
3868 vnode_update_identity(fvp, tdvp, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen, tond.ni_cnd.cn_hash, update_flags);
3869 }
3870 out1:
3871 if (holding_mntlock) {
3872 mount_unlock_renames(locked_mp);
3873 mount_drop(locked_mp, 0);
3874 }
3875 if (tdvp) {
3876 /*
3877 * nameidone has to happen before we vnode_put(tdvp)
3878 * since it may need to release the fs_nodelock on the tdvp
3879 */
3880 nameidone(&tond);
3881
3882 if (tvp)
3883 vnode_put(tvp);
3884 vnode_put(tdvp);
3885 }
3886 if (fdvp) {
3887 /*
3888 * nameidone has to happen before we vnode_put(fdvp)
3889 * since it may need to release the fs_nodelock on the fdvp
3890 */
3891 nameidone(&fromnd);
3892
3893 if (fvp)
3894 vnode_put(fvp);
3895 vnode_put(fdvp);
3896 }
3897 return (error);
3898 }
3899
3900 /*
3901 * Make a directory file.
3902 */
3903 /* ARGSUSED */
3904 static int
3905 mkdir1(vfs_context_t ctx, user_addr_t path, struct vnode_attr *vap)
3906 {
3907 vnode_t vp, dvp;
3908 int error;
3909 int update_flags = 0;
3910 struct nameidata nd;
3911
3912 AUDIT_ARG(mode, vap->va_mode);
3913 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
3914 UIO_USERSPACE, path, ctx);
3915 nd.ni_cnd.cn_flags |= WILLBEDIR;
3916 error = namei(&nd);
3917 if (error)
3918 return (error);
3919 dvp = nd.ni_dvp;
3920 vp = nd.ni_vp;
3921
3922 if (vp != NULL) {
3923 error = EEXIST;
3924 goto out;
3925 }
3926
3927 /* authorize addition of a directory to the parent */
3928 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_SUBDIRECTORY, ctx)) != 0)
3929 goto out;
3930
3931 VATTR_SET(vap, va_type, VDIR);
3932
3933 /* make the directory */
3934 if ((error = vn_create(dvp, &vp, &nd.ni_cnd, vap, 0, ctx)) != 0)
3935 goto out;
3936
3937 // Make sure the name & parent pointers are hooked up
3938 if (vp->v_name == NULL)
3939 update_flags |= VNODE_UPDATE_NAME;
3940 if (vp->v_parent == NULLVP)
3941 update_flags |= VNODE_UPDATE_PARENT;
3942
3943 if (update_flags)
3944 vnode_update_identity(vp, dvp, nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, update_flags);
3945
3946 add_fsevent(FSE_CREATE_DIR, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
3947
3948 out:
3949 /*
3950 * nameidone has to happen before we vnode_put(dvp)
3951 * since it may need to release the fs_nodelock on the dvp
3952 */
3953 nameidone(&nd);
3954
3955 if (vp)
3956 vnode_put(vp);
3957 vnode_put(dvp);
3958
3959 return (error);
3960 }
3961
3962
3963 int
3964 mkdir_extended(struct proc *p, register struct mkdir_extended_args *uap, __unused register_t *retval)
3965 {
3966 struct vfs_context context;
3967 int ciferror;
3968 kauth_filesec_t xsecdst;
3969 struct vnode_attr va;
3970
3971 xsecdst = NULL;
3972 if ((uap->xsecurity != USER_ADDR_NULL) &&
3973 ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0))
3974 return ciferror;
3975
3976 context.vc_proc = p;
3977 context.vc_ucred = kauth_cred_get();
3978
3979 VATTR_INIT(&va);
3980 VATTR_SET(&va, va_mode, (uap->mode & ACCESSPERMS) & ~p->p_fd->fd_cmask);
3981 if (xsecdst != NULL)
3982 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
3983
3984 ciferror = mkdir1(&context, uap->path, &va);
3985 if (xsecdst != NULL)
3986 kauth_filesec_free(xsecdst);
3987 return ciferror;
3988 }
3989
3990 int
3991 mkdir(struct proc *p, register struct mkdir_args *uap, __unused register_t *retval)
3992 {
3993 struct vfs_context context;
3994 struct vnode_attr va;
3995
3996 context.vc_proc = p;
3997 context.vc_ucred = kauth_cred_get();
3998
3999 VATTR_INIT(&va);
4000 VATTR_SET(&va, va_mode, (uap->mode & ACCESSPERMS) & ~p->p_fd->fd_cmask);
4001
4002 return(mkdir1(&context, uap->path, &va));
4003 }
4004
4005 /*
4006 * Remove a directory file.
4007 */
4008 /* ARGSUSED */
4009 int
4010 rmdir(struct proc *p, struct rmdir_args *uap, __unused register_t *retval)
4011 {
4012 vnode_t vp, dvp;
4013 int error;
4014 struct nameidata nd;
4015 struct vfs_context context;
4016
4017 context.vc_proc = p;
4018 context.vc_ucred = kauth_cred_get();
4019
4020 NDINIT(&nd, DELETE, LOCKPARENT | AUDITVNPATH1,
4021 UIO_USERSPACE, uap->path, &context);
4022 error = namei(&nd);
4023 if (error)
4024 return (error);
4025 dvp = nd.ni_dvp;
4026 vp = nd.ni_vp;
4027
4028 if (vp->v_type != VDIR) {
4029 /*
4030 * rmdir only deals with directories
4031 */
4032 error = ENOTDIR;
4033 } else if (dvp == vp) {
4034 /*
4035 * No rmdir "." please.
4036 */
4037 error = EINVAL;
4038 } else if (vp->v_flag & VROOT) {
4039 /*
4040 * The root of a mounted filesystem cannot be deleted.
4041 */
4042 error = EBUSY;
4043 } else {
4044 error = vnode_authorize(vp, nd.ni_dvp, KAUTH_VNODE_DELETE, &context);
4045 }
4046 if (!error) {
4047 char *path = NULL;
4048 int len;
4049 fse_info finfo;
4050
4051 if (need_fsevent(FSE_DELETE, dvp)) {
4052 path = get_pathbuff();
4053 len = MAXPATHLEN;
4054 vn_getpath(vp, path, &len);
4055 get_fse_info(vp, &finfo, &context);
4056 }
4057 error = VNOP_RMDIR(dvp, vp, &nd.ni_cnd, &context);
4058
4059 if (!error && path != NULL) {
4060 add_fsevent(FSE_DELETE, &context,
4061 FSE_ARG_STRING, len, path,
4062 FSE_ARG_FINFO, &finfo,
4063 FSE_ARG_DONE);
4064 }
4065 if (path != NULL)
4066 release_pathbuff(path);
4067 }
4068 /*
4069 * nameidone has to happen before we vnode_put(dvp)
4070 * since it may need to release the fs_nodelock on the dvp
4071 */
4072 nameidone(&nd);
4073
4074 vnode_put(dvp);
4075 vnode_put(vp);
4076
4077 return (error);
4078 }
4079
4080
4081 /*
4082 * Read a block of directory entries in a file system independent format.
4083 */
4084 int
4085 getdirentries(p, uap, retval)
4086 struct proc *p;
4087 register struct getdirentries_args *uap;
4088 register_t *retval;
4089 {
4090 struct vnode *vp;
4091 struct vfs_context context;
4092 struct fileproc *fp;
4093 uio_t auio;
4094 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
4095 long loff;
4096 int error, eofflag;
4097 int fd = uap->fd;
4098 char uio_buf[ UIO_SIZEOF(1) ];
4099
4100 AUDIT_ARG(fd, uap->fd);
4101 error = fp_getfvp(p, fd, &fp, &vp);
4102 if (error)
4103 return (error);
4104
4105 if ((fp->f_fglob->fg_flag & FREAD) == 0) {
4106 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
4107 error = EBADF;
4108 goto out;
4109 }
4110 if ( (error = vnode_getwithref(vp)) ) {
4111 goto out;
4112 }
4113
4114 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
4115
4116 unionread:
4117 if (vp->v_type != VDIR) {
4118 (void)vnode_put(vp);
4119 error = EINVAL;
4120 goto out;
4121 }
4122 context.vc_proc = p;
4123 context.vc_ucred = fp->f_fglob->fg_cred;
4124
4125 loff = fp->f_fglob->fg_offset;
4126 auio = uio_createwithbuffer(1, loff, spacetype, UIO_READ,
4127 &uio_buf[0], sizeof(uio_buf));
4128 uio_addiov(auio, uap->buf, uap->count);
4129
4130 error = VNOP_READDIR(vp, auio, 0, &eofflag, (int *)NULL, &context);
4131 fp->f_fglob->fg_offset = uio_offset(auio);
4132 if (error) {
4133 (void)vnode_put(vp);
4134 goto out;
4135 }
4136
4137 #if UNION
4138 {
4139 if ((uap->count == uio_resid(auio)) &&
4140 (vp->v_op == union_vnodeop_p)) {
4141 struct vnode *lvp;
4142
4143 lvp = union_dircache(vp, p);
4144 if (lvp != NULLVP) {
4145 struct vnode_attr va;
4146 /*
4147 * If the directory is opaque,
4148 * then don't show lower entries
4149 */
4150 VATTR_INIT(&va);
4151 VATTR_WANTED(&va, va_flags);
4152 error = vnode_getattr(vp, &va, &context);
4153 if (va.va_flags & OPAQUE) {
4154 vnode_put(lvp);
4155 lvp = NULL;
4156 }
4157 }
4158
4159 if (lvp != NULLVP) {
4160 error = VNOP_OPEN(lvp, FREAD, &context);
4161 if (error) {
4162 vnode_put(lvp);
4163 goto out;
4164 }
4165 vnode_ref(lvp);
4166 fp->f_fglob->fg_data = (caddr_t) lvp;
4167 fp->f_fglob->fg_offset = 0;
4168 error = VNOP_CLOSE(vp, FREAD, &context);
4169 vnode_rele(vp);
4170 vnode_put(vp);
4171 if (error)
4172 goto out;
4173 vp = lvp;
4174 goto unionread;
4175 }
4176 }
4177 }
4178 #endif /* UNION */
4179
4180 if (((user_ssize_t)uap->count == uio_resid(auio)) &&
4181 (vp->v_flag & VROOT) &&
4182 (vp->v_mount->mnt_flag & MNT_UNION)) {
4183 struct vnode *tvp = vp;
4184 vp = vp->v_mount->mnt_vnodecovered;
4185 vnode_getwithref(vp);
4186 vnode_ref(vp);
4187 fp->f_fglob->fg_data = (caddr_t) vp;
4188 fp->f_fglob->fg_offset = 0;
4189 vnode_rele(tvp);
4190 vnode_put(tvp);
4191 goto unionread;
4192 }
4193 vnode_put(vp);
4194 error = copyout((caddr_t)&loff, uap->basep, sizeof(long));
4195 // LP64todo - fix this
4196 *retval = uap->count - uio_resid(auio);
4197 out:
4198 file_drop(fd);
4199 return (error);
4200 }
4201
4202 /*
4203 * Set the mode mask for creation of filesystem nodes.
4204 */
4205 #warning XXX implement xsecurity
4206
4207 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
4208 static int
4209 umask1(struct proc *p, int newmask, __unused kauth_filesec_t fsec, register_t *retval)
4210 {
4211 register struct filedesc *fdp;
4212
4213 AUDIT_ARG(mask, newmask);
4214 fdp = p->p_fd;
4215 *retval = fdp->fd_cmask;
4216 fdp->fd_cmask = newmask & ALLPERMS;
4217 return (0);
4218 }
4219
4220
4221 int
4222 umask_extended(struct proc *p, struct umask_extended_args *uap, register_t *retval)
4223 {
4224 int ciferror;
4225 kauth_filesec_t xsecdst;
4226
4227 xsecdst = KAUTH_FILESEC_NONE;
4228 if (uap->xsecurity != USER_ADDR_NULL) {
4229 if ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
4230 return ciferror;
4231 } else {
4232 xsecdst = KAUTH_FILESEC_NONE;
4233 }
4234
4235 ciferror = umask1(p, uap->newmask, xsecdst, retval);
4236
4237 if (xsecdst != KAUTH_FILESEC_NONE)
4238 kauth_filesec_free(xsecdst);
4239 return ciferror;
4240 }
4241
4242 int
4243 umask(struct proc *p, struct umask_args *uap, register_t *retval)
4244 {
4245 return(umask1(p, uap->newmask, UMASK_NOXSECURITY, retval));
4246 }
4247
4248 /*
4249 * Void all references to file by ripping underlying filesystem
4250 * away from vnode.
4251 */
4252 /* ARGSUSED */
4253 int
4254 revoke(struct proc *p, register struct revoke_args *uap, __unused register_t *retval)
4255 {
4256 register struct vnode *vp;
4257 struct vnode_attr va;
4258 struct vfs_context context;
4259 int error;
4260 struct nameidata nd;
4261
4262 context.vc_proc = p;
4263 context.vc_ucred = kauth_cred_get();
4264
4265 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
4266 UIO_USERSPACE, uap->path, &context);
4267 error = namei(&nd);
4268 if (error)
4269 return (error);
4270 vp = nd.ni_vp;
4271
4272 nameidone(&nd);
4273
4274 VATTR_INIT(&va);
4275 VATTR_WANTED(&va, va_uid);
4276 if ((error = vnode_getattr(vp, &va, &context)))
4277 goto out;
4278 if (kauth_cred_getuid(context.vc_ucred) != va.va_uid &&
4279 (error = suser(context.vc_ucred, &p->p_acflag)))
4280 goto out;
4281 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
4282 VNOP_REVOKE(vp, REVOKEALL, &context);
4283 out:
4284 vnode_put(vp);
4285 return (error);
4286 }
4287
4288
4289 /*
4290 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
4291 * The following system calls are designed to support features
4292 * which are specific to the HFS & HFS Plus volume formats
4293 */
4294
4295 #ifdef __APPLE_API_OBSOLETE
4296
4297 /************************************************/
4298 /* *** Following calls will be deleted soon *** */
4299 /************************************************/
4300
4301 /*
4302 * Make a complex file. A complex file is one with multiple forks (data streams)
4303 */
4304 /* ARGSUSED */
4305 int
4306 mkcomplex(__unused struct proc *p, __unused struct mkcomplex_args *uap, __unused register_t *retval)
4307 {
4308 return (ENOTSUP);
4309 }
4310
4311 /*
4312 * Extended stat call which returns volumeid and vnodeid as well as other info
4313 */
4314 /* ARGSUSED */
4315 int
4316 statv(__unused struct proc *p,
4317 __unused struct statv_args *uap,
4318 __unused register_t *retval)
4319 {
4320 return (ENOTSUP); /* We'll just return an error for now */
4321
4322 } /* end of statv system call */
4323
4324 /*
4325 * Extended lstat call which returns volumeid and vnodeid as well as other info
4326 */
4327 /* ARGSUSED */
4328 int
4329 lstatv(__unused struct proc *p,
4330 __unused struct lstatv_args *uap,
4331 __unused register_t *retval)
4332 {
4333 return (ENOTSUP); /* We'll just return an error for now */
4334 } /* end of lstatv system call */
4335
4336 /*
4337 * Extended fstat call which returns volumeid and vnodeid as well as other info
4338 */
4339 /* ARGSUSED */
4340 int
4341 fstatv(__unused struct proc *p,
4342 __unused struct fstatv_args *uap,
4343 __unused register_t *retval)
4344 {
4345 return (ENOTSUP); /* We'll just return an error for now */
4346 } /* end of fstatv system call */
4347
4348
4349 /************************************************/
4350 /* *** Preceding calls will be deleted soon *** */
4351 /************************************************/
4352
4353 #endif /* __APPLE_API_OBSOLETE */
4354
4355 /*
4356 * Obtain attribute information on objects in a directory while enumerating
4357 * the directory. This call does not yet support union mounted directories.
4358 * TO DO
4359 * 1.union mounted directories.
4360 */
4361
4362 /* ARGSUSED */
4363 int
4364 getdirentriesattr (struct proc *p, struct getdirentriesattr_args *uap, register_t *retval)
4365 {
4366 struct vnode *vp;
4367 struct fileproc *fp;
4368 uio_t auio = NULL;
4369 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
4370 uint64_t actualcount;
4371 u_long tmpcount;
4372 u_long newstate;
4373 int error, eofflag;
4374 u_long loff;
4375 struct attrlist attributelist;
4376 struct vfs_context context;
4377 int fd = uap->fd;
4378 char uio_buf[ UIO_SIZEOF(1) ];
4379 kauth_action_t action;
4380
4381 AUDIT_ARG(fd, fd);
4382
4383 /* Get the attributes into kernel space */
4384 if ((error = copyin(uap->alist, (caddr_t) &attributelist, sizeof (attributelist))))
4385 return(error);
4386 actualcount = fuulong(uap->count);
4387 if (actualcount == -1ULL)
4388 return(-1);
4389
4390 if ( (error = fp_getfvp(p, fd, &fp, &vp)) )
4391 return (error);
4392
4393 if ((fp->f_fglob->fg_flag & FREAD) == 0) {
4394 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
4395 error = EBADF;
4396 goto out;
4397 }
4398 if ( (error = vnode_getwithref(vp)) )
4399 goto out;
4400
4401 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
4402
4403 if (vp->v_type != VDIR) {
4404 (void)vnode_put(vp);
4405 error = EINVAL;
4406 goto out;
4407 }
4408
4409 /* set up the uio structure which will contain the users return buffer */
4410 loff = fp->f_fglob->fg_offset;
4411 auio = uio_createwithbuffer(1, loff, spacetype, UIO_READ,
4412 &uio_buf[0], sizeof(uio_buf));
4413 uio_addiov(auio, uap->buffer, uap->buffersize);
4414
4415 context.vc_proc = p;
4416 context.vc_ucred = kauth_cred_get();
4417 tmpcount = (u_long) actualcount;
4418
4419 /*
4420 * If the only item requested is file names, we can let that past with
4421 * just LIST_DIRECTORY. If they want any other attributes, that means
4422 * they need SEARCH as well.
4423 */
4424 action = KAUTH_VNODE_LIST_DIRECTORY;
4425 if ((attributelist.commonattr & ~ATTR_CMN_NAME) ||
4426 attributelist.fileattr || attributelist.dirattr)
4427 action |= KAUTH_VNODE_SEARCH;
4428
4429 if ((error = vnode_authorize(vp, NULL, action, &context)) == 0)
4430 error = VNOP_READDIRATTR(vp, &attributelist, auio,
4431 tmpcount, uap->options, &newstate, &eofflag,
4432 &tmpcount, &context);
4433 (void)vnode_put(vp);
4434 actualcount = tmpcount;
4435
4436 if (error)
4437 goto out;
4438 fp->f_fglob->fg_offset = uio_offset(auio); /* should be multiple of dirent, not variable */
4439
4440 if ((error = suulong(uap->count, actualcount)) != 0)
4441 goto out;
4442 if ((error = suulong(uap->newstate, (uint64_t)newstate)) != 0)
4443 goto out;
4444 if ((error = suulong(uap->basep, (uint64_t)loff)) != 0)
4445 goto out;
4446
4447 *retval = eofflag; /* similar to getdirentries */
4448 error = 0;
4449 out:
4450 file_drop(fd);
4451 return (error); /* return error earlier, an retval of 0 or 1 now */
4452
4453 } /* end of getdirentryattr system call */
4454
4455 /*
4456 * Exchange data between two files
4457 */
4458
4459 /* ARGSUSED */
4460 int
4461 exchangedata (struct proc *p, register struct exchangedata_args *uap, __unused register_t *retval)
4462 {
4463
4464 struct nameidata fnd, snd;
4465 struct vfs_context context;
4466 struct vnode *fvp, *svp;
4467 int error;
4468 u_long nameiflags;
4469 char *fpath = NULL;
4470 char *spath = NULL;
4471 int flen, slen;
4472 fse_info f_finfo, s_finfo;
4473
4474 context.vc_proc = p;
4475 context.vc_ucred = kauth_cred_get();
4476
4477 nameiflags = 0;
4478 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
4479
4480 NDINIT(&fnd, LOOKUP, nameiflags | AUDITVNPATH1,
4481 UIO_USERSPACE, uap->path1, &context);
4482
4483 error = namei(&fnd);
4484 if (error)
4485 goto out2;
4486
4487 nameidone(&fnd);
4488 fvp = fnd.ni_vp;
4489
4490 NDINIT(&snd, LOOKUP, nameiflags | AUDITVNPATH2,
4491 UIO_USERSPACE, uap->path2, &context);
4492
4493 error = namei(&snd);
4494 if (error) {
4495 vnode_put(fvp);
4496 goto out2;
4497 }
4498 nameidone(&snd);
4499 svp = snd.ni_vp;
4500
4501 /*
4502 * if the files are the same, return an inval error
4503 */
4504 if (svp == fvp) {
4505 error = EINVAL;
4506 goto out;
4507 }
4508
4509 /*
4510 * if the files are on different volumes, return an error
4511 */
4512 if (svp->v_mount != fvp->v_mount) {
4513 error = EXDEV;
4514 goto out;
4515 }
4516 if (((error = vnode_authorize(fvp, NULL, KAUTH_VNODE_READ_DATA | KAUTH_VNODE_WRITE_DATA, &context)) != 0) ||
4517 ((error = vnode_authorize(svp, NULL, KAUTH_VNODE_READ_DATA | KAUTH_VNODE_WRITE_DATA, &context)) != 0))
4518 goto out;
4519
4520 if (need_fsevent(FSE_EXCHANGE, fvp) || kauth_authorize_fileop_has_listeners()) {
4521 fpath = get_pathbuff();
4522 spath = get_pathbuff();
4523 flen = MAXPATHLEN;
4524 slen = MAXPATHLEN;
4525 if (vn_getpath(fvp, fpath, &flen) != 0 || fpath[0] == '\0') {
4526 printf("exchange: vn_getpath(fvp=0x%x) failed <<%s>>\n",
4527 fvp, fpath);
4528 }
4529 if (vn_getpath(svp, spath, &slen) != 0 || spath[0] == '\0') {
4530 printf("exchange: vn_getpath(svp=0x%x) failed <<%s>>\n",
4531 svp, spath);
4532 }
4533 get_fse_info(fvp, &f_finfo, &context);
4534 get_fse_info(svp, &s_finfo, &context);
4535 }
4536 /* Ok, make the call */
4537 error = VNOP_EXCHANGE(fvp, svp, 0, &context);
4538
4539 if (error == 0) {
4540 char *tmpname;
4541
4542 if (fpath != NULL && spath != NULL) {
4543 /* call out to allow 3rd party notification of exchangedata.
4544 * Ignore result of kauth_authorize_fileop call.
4545 */
4546 kauth_authorize_fileop(vfs_context_ucred(&context), KAUTH_FILEOP_EXCHANGE,
4547 (uintptr_t)fpath, (uintptr_t)spath);
4548 }
4549 name_cache_lock();
4550
4551 tmpname = fvp->v_name;
4552 fvp->v_name = svp->v_name;
4553 svp->v_name = tmpname;
4554
4555 if (fvp->v_parent != svp->v_parent) {
4556 struct vnode *tmp;
4557
4558 tmp = fvp->v_parent;
4559 fvp->v_parent = svp->v_parent;
4560 svp->v_parent = tmp;
4561 }
4562 name_cache_unlock();
4563
4564 if (fpath != NULL && spath != NULL) {
4565 add_fsevent(FSE_EXCHANGE, &context,
4566 FSE_ARG_STRING, flen, fpath,
4567 FSE_ARG_FINFO, &f_finfo,
4568 FSE_ARG_STRING, slen, spath,
4569 FSE_ARG_FINFO, &s_finfo,
4570 FSE_ARG_DONE);
4571 }
4572 }
4573 if (spath != NULL)
4574 release_pathbuff(spath);
4575 if (fpath != NULL)
4576 release_pathbuff(fpath);
4577
4578 out:
4579 vnode_put(svp);
4580 vnode_put(fvp);
4581 out2:
4582 return (error);
4583 }
4584
4585
4586 #ifdef __APPLE_API_OBSOLETE
4587
4588 /************************************************/
4589 /* *** Following calls will be deleted soon *** */
4590 /************************************************/
4591
4592 /*
4593 * Check users access to a file
4594 */
4595
4596 /* ARGSUSED */
4597 #warning "checkuseraccess copies a cred in from user space but"
4598 #warning "user space has no way of knowing what one looks like"
4599 #warning "this code should use the access_extended spoof-as functionality"
4600 int
4601 checkuseraccess (struct proc *p, register struct checkuseraccess_args *uap, __unused register_t *retval)
4602 {
4603 register struct vnode *vp;
4604 int error;
4605 struct nameidata nd;
4606 struct ucred cred; /* XXX ILLEGAL */
4607 int flags; /*what will actually get passed to access*/
4608 u_long nameiflags;
4609 struct vfs_context context;
4610
4611 /* Make sure that the number of groups is correct before we do anything */
4612
4613 if ((uap->ngroups <= 0) || (uap->ngroups > NGROUPS))
4614 return (EINVAL);
4615
4616 /* Verify that the caller is root */
4617
4618 if ((error = suser(kauth_cred_get(), &p->p_acflag)))
4619 return(error);
4620
4621 /* Fill in the credential structure */
4622
4623 cred.cr_ref = 0;
4624 cred.cr_uid = uap->userid;
4625 cred.cr_ngroups = uap->ngroups;
4626 if ((error = copyin(CAST_USER_ADDR_T(uap->groups), (caddr_t) &(cred.cr_groups), (sizeof(gid_t))*uap->ngroups)))
4627 return (error);
4628
4629 context.vc_proc = p;
4630 context.vc_ucred = &cred;
4631
4632 /* Get our hands on the file */
4633 nameiflags = 0;
4634 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
4635 NDINIT(&nd, LOOKUP, nameiflags | AUDITVNPATH1,
4636 UIO_USERSPACE, CAST_USER_ADDR_T(uap->path), &context);
4637
4638 if ((error = namei(&nd)))
4639 return (error);
4640 nameidone(&nd);
4641 vp = nd.ni_vp;
4642
4643 /* Flags == 0 means only check for existence. */
4644
4645 flags = 0;
4646
4647 if (uap->accessrequired) {
4648 if (uap->accessrequired & R_OK)
4649 flags |= KAUTH_VNODE_READ_DATA;
4650 if (uap->accessrequired & W_OK)
4651 flags |= KAUTH_VNODE_WRITE_DATA;
4652 if (uap->accessrequired & X_OK)
4653 flags |= KAUTH_VNODE_EXECUTE;
4654 }
4655 error = vnode_authorize(vp, NULL, flags, &context);
4656
4657 vnode_put(vp);
4658
4659 if (error)
4660 return (error);
4661
4662 return (0);
4663
4664 } /* end of checkuseraccess system call */
4665
4666 /************************************************/
4667 /* *** Preceding calls will be deleted soon *** */
4668 /************************************************/
4669
4670 #endif /* __APPLE_API_OBSOLETE */
4671
4672
4673
4674 /* ARGSUSED */
4675
4676 int
4677 searchfs (struct proc *p, register struct searchfs_args *uap, __unused register_t *retval)
4678 {
4679 register struct vnode *vp;
4680 int error=0;
4681 int fserror = 0;
4682 struct nameidata nd;
4683 struct user_fssearchblock searchblock;
4684 struct searchstate *state;
4685 struct attrlist *returnattrs;
4686 void *searchparams1,*searchparams2;
4687 uio_t auio = NULL;
4688 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
4689 u_long nummatches;
4690 int mallocsize;
4691 u_long nameiflags;
4692 struct vfs_context context;
4693 char uio_buf[ UIO_SIZEOF(1) ];
4694
4695 context.vc_proc = p;
4696 context.vc_ucred = kauth_cred_get();
4697
4698 /* Start by copying in fsearchblock paramater list */
4699 if (IS_64BIT_PROCESS(p)) {
4700 error = copyin(uap->searchblock, (caddr_t) &searchblock, sizeof(searchblock));
4701 }
4702 else {
4703 struct fssearchblock tmp_searchblock;
4704 error = copyin(uap->searchblock, (caddr_t) &tmp_searchblock, sizeof(tmp_searchblock));
4705 // munge into 64-bit version
4706 searchblock.returnattrs = CAST_USER_ADDR_T(tmp_searchblock.returnattrs);
4707 searchblock.returnbuffer = CAST_USER_ADDR_T(tmp_searchblock.returnbuffer);
4708 searchblock.returnbuffersize = tmp_searchblock.returnbuffersize;
4709 searchblock.maxmatches = tmp_searchblock.maxmatches;
4710 searchblock.timelimit = tmp_searchblock.timelimit;
4711 searchblock.searchparams1 = CAST_USER_ADDR_T(tmp_searchblock.searchparams1);
4712 searchblock.sizeofsearchparams1 = tmp_searchblock.sizeofsearchparams1;
4713 searchblock.searchparams2 = CAST_USER_ADDR_T(tmp_searchblock.searchparams2);
4714 searchblock.sizeofsearchparams2 = tmp_searchblock.sizeofsearchparams2;
4715 searchblock.searchattrs = tmp_searchblock.searchattrs;
4716 }
4717 if (error)
4718 return(error);
4719
4720 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
4721 */
4722 if (searchblock.sizeofsearchparams1 > SEARCHFS_MAX_SEARCHPARMS ||
4723 searchblock.sizeofsearchparams2 > SEARCHFS_MAX_SEARCHPARMS)
4724 return(EINVAL);
4725
4726 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
4727 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
4728 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
4729 /* block. */
4730
4731 mallocsize = searchblock.sizeofsearchparams1 + searchblock.sizeofsearchparams2 +
4732 sizeof(struct attrlist) + sizeof(struct searchstate);
4733
4734 MALLOC(searchparams1, void *, mallocsize, M_TEMP, M_WAITOK);
4735
4736 /* Now set up the various pointers to the correct place in our newly allocated memory */
4737
4738 searchparams2 = (void *) (((caddr_t) searchparams1) + searchblock.sizeofsearchparams1);
4739 returnattrs = (struct attrlist *) (((caddr_t) searchparams2) + searchblock.sizeofsearchparams2);
4740 state = (struct searchstate *) (((caddr_t) returnattrs) + sizeof (struct attrlist));
4741
4742 /* Now copy in the stuff given our local variables. */
4743
4744 if ((error = copyin(searchblock.searchparams1, searchparams1, searchblock.sizeofsearchparams1)))
4745 goto freeandexit;
4746
4747 if ((error = copyin(searchblock.searchparams2, searchparams2, searchblock.sizeofsearchparams2)))
4748 goto freeandexit;
4749
4750 if ((error = copyin(searchblock.returnattrs, (caddr_t) returnattrs, sizeof(struct attrlist))))
4751 goto freeandexit;
4752
4753 if ((error = copyin(uap->state, (caddr_t) state, sizeof(struct searchstate))))
4754 goto freeandexit;
4755
4756 /* set up the uio structure which will contain the users return buffer */
4757
4758 auio = uio_createwithbuffer(1, 0, spacetype, UIO_READ,
4759 &uio_buf[0], sizeof(uio_buf));
4760 uio_addiov(auio, searchblock.returnbuffer, searchblock.returnbuffersize);
4761
4762 nameiflags = 0;
4763 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
4764 NDINIT(&nd, LOOKUP, nameiflags | AUDITVNPATH1,
4765 UIO_USERSPACE, uap->path, &context);
4766
4767 error = namei(&nd);
4768 if (error)
4769 goto freeandexit;
4770
4771 nameidone(&nd);
4772 vp = nd.ni_vp;
4773
4774
4775 /*
4776 * If searchblock.maxmatches == 0, then skip the search. This has happened
4777 * before and sometimes the underlyning code doesnt deal with it well.
4778 */
4779 if (searchblock.maxmatches == 0) {
4780 nummatches = 0;
4781 goto saveandexit;
4782 }
4783
4784 /*
4785 Allright, we have everything we need, so lets make that call.
4786
4787 We keep special track of the return value from the file system:
4788 EAGAIN is an acceptable error condition that shouldn't keep us
4789 from copying out any results...
4790 */
4791
4792 fserror = VNOP_SEARCHFS(vp,
4793 searchparams1,
4794 searchparams2,
4795 &searchblock.searchattrs,
4796 searchblock.maxmatches,
4797 &searchblock.timelimit,
4798 returnattrs,
4799 &nummatches,
4800 uap->scriptcode,
4801 uap->options,
4802 auio,
4803 state,
4804 &context);
4805
4806 saveandexit:
4807
4808 vnode_put(vp);
4809
4810 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4811 search state. Everything was already put into he return buffer by the vop call. */
4812
4813 if ((error = copyout((caddr_t) state, uap->state, sizeof(struct searchstate))) != 0)
4814 goto freeandexit;
4815
4816 if ((error = suulong(uap->nummatches, (uint64_t)nummatches)) != 0)
4817 goto freeandexit;
4818
4819 error = fserror;
4820
4821 freeandexit:
4822
4823 FREE(searchparams1,M_TEMP);
4824
4825 return(error);
4826
4827
4828 } /* end of searchfs system call */
4829
4830
4831 /*
4832 * Make a filesystem-specific control call:
4833 */
4834 /* ARGSUSED */
4835 int
4836 fsctl (struct proc *p, struct fsctl_args *uap, __unused register_t *retval)
4837 {
4838 int error;
4839 boolean_t is64bit;
4840 struct nameidata nd;
4841 u_long nameiflags;
4842 u_long cmd = uap->cmd;
4843 register u_int size;
4844 #define STK_PARAMS 128
4845 char stkbuf[STK_PARAMS];
4846 caddr_t data, memp;
4847 struct vfs_context context;
4848
4849 context.vc_proc = p;
4850 context.vc_ucred = kauth_cred_get();
4851
4852 size = IOCPARM_LEN(cmd);
4853 if (size > IOCPARM_MAX) return (EINVAL);
4854
4855 is64bit = proc_is64bit(p);
4856
4857 memp = NULL;
4858 if (size > sizeof (stkbuf)) {
4859 if ((memp = (caddr_t)kalloc(size)) == 0) return ENOMEM;
4860 data = memp;
4861 } else {
4862 data = &stkbuf[0];
4863 };
4864
4865 if (cmd & IOC_IN) {
4866 if (size) {
4867 error = copyin(uap->data, data, size);
4868 if (error) goto FSCtl_Exit;
4869 } else {
4870 if (is64bit) {
4871 *(user_addr_t *)data = uap->data;
4872 }
4873 else {
4874 *(uint32_t *)data = (uint32_t)uap->data;
4875 }
4876 };
4877 } else if ((cmd & IOC_OUT) && size) {
4878 /*
4879 * Zero the buffer so the user always
4880 * gets back something deterministic.
4881 */
4882 bzero(data, size);
4883 } else if (cmd & IOC_VOID) {
4884 if (is64bit) {
4885 *(user_addr_t *)data = uap->data;
4886 }
4887 else {
4888 *(uint32_t *)data = (uint32_t)uap->data;
4889 }
4890 }
4891
4892 /* Get the vnode for the file we are getting info on: */
4893 nameiflags = 0;
4894 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
4895 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, uap->path, &context);
4896 if ((error = namei(&nd))) goto FSCtl_Exit;
4897
4898 /* Invoke the filesystem-specific code */
4899 error = VNOP_IOCTL(nd.ni_vp, IOCBASECMD(cmd), data, uap->options, &context);
4900
4901 vnode_put(nd.ni_vp);
4902 nameidone(&nd);
4903
4904 /*
4905 * Copy any data to user, size was
4906 * already set and checked above.
4907 */
4908 if (error == 0 && (cmd & IOC_OUT) && size)
4909 error = copyout(data, uap->data, size);
4910
4911 FSCtl_Exit:
4912 if (memp) kfree(memp, size);
4913
4914 return error;
4915 }
4916 /* end of fsctl system call */
4917
4918 /*
4919 * An in-kernel sync for power management to call.
4920 */
4921 __private_extern__ int
4922 sync_internal(void)
4923 {
4924 int error;
4925
4926 struct sync_args data;
4927
4928 int retval[2];
4929
4930
4931 error = sync(current_proc(), &data, &retval[0]);
4932
4933
4934 return (error);
4935 } /* end of sync_internal call */
4936
4937
4938 /*
4939 * Retrieve the data of an extended attribute.
4940 */
4941 int
4942 getxattr(struct proc *p, struct getxattr_args *uap, user_ssize_t *retval)
4943 {
4944 struct vnode *vp;
4945 struct nameidata nd;
4946 char attrname[XATTR_MAXNAMELEN+1];
4947 struct vfs_context context;
4948 uio_t auio = NULL;
4949 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
4950 size_t attrsize = 0;
4951 size_t namelen;
4952 u_long nameiflags;
4953 int error;
4954 char uio_buf[ UIO_SIZEOF(1) ];
4955
4956 context.vc_proc = p;
4957 context.vc_ucred = kauth_cred_get();
4958
4959 if (uap->options & XATTR_NOSECURITY)
4960 return (EINVAL);
4961
4962 nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
4963 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
4964 if ((error = namei(&nd))) {
4965 return (error);
4966 }
4967 vp = nd.ni_vp;
4968 nameidone(&nd);
4969
4970 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
4971 goto out;
4972 }
4973 if (xattr_protected(attrname)) {
4974 error = EPERM;
4975 goto out;
4976 }
4977 if (uap->value && uap->size > 0) {
4978 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_READ,
4979 &uio_buf[0], sizeof(uio_buf));
4980 uio_addiov(auio, uap->value, uap->size);
4981 }
4982
4983 error = vn_getxattr(vp, attrname, auio, &attrsize, uap->options, &context);
4984 out:
4985 vnode_put(vp);
4986
4987 if (auio) {
4988 *retval = uap->size - uio_resid(auio);
4989 } else {
4990 *retval = (user_ssize_t)attrsize;
4991 }
4992
4993 return (error);
4994 }
4995
4996 /*
4997 * Retrieve the data of an extended attribute.
4998 */
4999 int
5000 fgetxattr(struct proc *p, struct fgetxattr_args *uap, user_ssize_t *retval)
5001 {
5002 struct vnode *vp;
5003 char attrname[XATTR_MAXNAMELEN+1];
5004 struct vfs_context context;
5005 uio_t auio = NULL;
5006 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5007 size_t attrsize = 0;
5008 size_t namelen;
5009 int error;
5010 char uio_buf[ UIO_SIZEOF(1) ];
5011
5012 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
5013 return (EINVAL);
5014
5015 if ( (error = file_vnode(uap->fd, &vp)) ) {
5016 return (error);
5017 }
5018 if ( (error = vnode_getwithref(vp)) ) {
5019 file_drop(uap->fd);
5020 return(error);
5021 }
5022 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
5023 goto out;
5024 }
5025 if (xattr_protected(attrname)) {
5026 error = EPERM;
5027 goto out;
5028 }
5029 if (uap->value && uap->size > 0) {
5030 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_READ,
5031 &uio_buf[0], sizeof(uio_buf));
5032 uio_addiov(auio, uap->value, uap->size);
5033 }
5034 context.vc_proc = p;
5035 context.vc_ucred = kauth_cred_get();
5036
5037 error = vn_getxattr(vp, attrname, auio, &attrsize, uap->options, &context);
5038 out:
5039 (void)vnode_put(vp);
5040 file_drop(uap->fd);
5041
5042 if (auio) {
5043 *retval = uap->size - uio_resid(auio);
5044 } else {
5045 *retval = (user_ssize_t)attrsize;
5046 }
5047 return (error);
5048 }
5049
5050 /*
5051 * Set the data of an extended attribute.
5052 */
5053 int
5054 setxattr(struct proc *p, struct setxattr_args *uap, int *retval)
5055 {
5056 struct vnode *vp;
5057 struct nameidata nd;
5058 char attrname[XATTR_MAXNAMELEN+1];
5059 struct vfs_context context;
5060 uio_t auio = NULL;
5061 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5062 size_t namelen;
5063 u_long nameiflags;
5064 int error;
5065 char uio_buf[ UIO_SIZEOF(1) ];
5066
5067 context.vc_proc = p;
5068 context.vc_ucred = kauth_cred_get();
5069
5070 if (uap->options & XATTR_NOSECURITY)
5071 return (EINVAL);
5072
5073 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
5074 return (error);
5075 }
5076 if (xattr_protected(attrname))
5077 return(EPERM);
5078 if (uap->value == 0 || uap->size == 0) {
5079 return (EINVAL);
5080 }
5081
5082 nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
5083 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
5084 if ((error = namei(&nd))) {
5085 return (error);
5086 }
5087 vp = nd.ni_vp;
5088 nameidone(&nd);
5089
5090 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_WRITE,
5091 &uio_buf[0], sizeof(uio_buf));
5092 uio_addiov(auio, uap->value, uap->size);
5093
5094 error = vn_setxattr(vp, attrname, auio, uap->options, &context);
5095 vnode_put(vp);
5096 *retval = 0;
5097 return (error);
5098 }
5099
5100 /*
5101 * Set the data of an extended attribute.
5102 */
5103 int
5104 fsetxattr(struct proc *p, struct fsetxattr_args *uap, int *retval)
5105 {
5106 struct vnode *vp;
5107 char attrname[XATTR_MAXNAMELEN+1];
5108 struct vfs_context context;
5109 uio_t auio = NULL;
5110 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5111 size_t namelen;
5112 int error;
5113 char uio_buf[ UIO_SIZEOF(1) ];
5114
5115 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
5116 return (EINVAL);
5117
5118 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
5119 return (error);
5120 }
5121 if (xattr_protected(attrname))
5122 return(EPERM);
5123 if (uap->value == 0 || uap->size == 0) {
5124 return (EINVAL);
5125 }
5126 if ( (error = file_vnode(uap->fd, &vp)) ) {
5127 return (error);
5128 }
5129 if ( (error = vnode_getwithref(vp)) ) {
5130 file_drop(uap->fd);
5131 return(error);
5132 }
5133 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_WRITE,
5134 &uio_buf[0], sizeof(uio_buf));
5135 uio_addiov(auio, uap->value, uap->size);
5136 context.vc_proc = p;
5137 context.vc_ucred = kauth_cred_get();
5138
5139 error = vn_setxattr(vp, attrname, auio, uap->options, &context);
5140 vnode_put(vp);
5141 file_drop(uap->fd);
5142 *retval = 0;
5143 return (error);
5144 }
5145
5146 /*
5147 * Remove an extended attribute.
5148 */
5149 #warning "code duplication"
5150 int
5151 removexattr(struct proc *p, struct removexattr_args *uap, int *retval)
5152 {
5153 struct vnode *vp;
5154 struct nameidata nd;
5155 char attrname[XATTR_MAXNAMELEN+1];
5156 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5157 struct vfs_context context;
5158 size_t namelen;
5159 u_long nameiflags;
5160 int error;
5161
5162 context.vc_proc = p;
5163 context.vc_ucred = kauth_cred_get();
5164
5165 if (uap->options & XATTR_NOSECURITY)
5166 return (EINVAL);
5167
5168 error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen);
5169 if (error != 0) {
5170 return (error);
5171 }
5172 if (xattr_protected(attrname))
5173 return(EPERM);
5174 nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
5175 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
5176 if ((error = namei(&nd))) {
5177 return (error);
5178 }
5179 vp = nd.ni_vp;
5180 nameidone(&nd);
5181
5182 error = vn_removexattr(vp, attrname, uap->options, &context);
5183 vnode_put(vp);
5184 *retval = 0;
5185 return (error);
5186 }
5187
5188 /*
5189 * Remove an extended attribute.
5190 */
5191 #warning "code duplication"
5192 int
5193 fremovexattr(struct proc *p, struct fremovexattr_args *uap, int *retval)
5194 {
5195 struct vnode *vp;
5196 char attrname[XATTR_MAXNAMELEN+1];
5197 struct vfs_context context;
5198 size_t namelen;
5199 int error;
5200
5201 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
5202 return (EINVAL);
5203
5204 error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen);
5205 if (error != 0) {
5206 return (error);
5207 }
5208 if (xattr_protected(attrname))
5209 return(EPERM);
5210 if ( (error = file_vnode(uap->fd, &vp)) ) {
5211 return (error);
5212 }
5213 if ( (error = vnode_getwithref(vp)) ) {
5214 file_drop(uap->fd);
5215 return(error);
5216 }
5217 context.vc_proc = p;
5218 context.vc_ucred = kauth_cred_get();
5219
5220 error = vn_removexattr(vp, attrname, uap->options, &context);
5221 vnode_put(vp);
5222 file_drop(uap->fd);
5223 *retval = 0;
5224 return (error);
5225 }
5226
5227 /*
5228 * Retrieve the list of extended attribute names.
5229 */
5230 #warning "code duplication"
5231 int
5232 listxattr(struct proc *p, struct listxattr_args *uap, user_ssize_t *retval)
5233 {
5234 struct vnode *vp;
5235 struct nameidata nd;
5236 struct vfs_context context;
5237 uio_t auio = NULL;
5238 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5239 size_t attrsize = 0;
5240 u_long nameiflags;
5241 int error;
5242 char uio_buf[ UIO_SIZEOF(1) ];
5243
5244 context.vc_proc = p;
5245 context.vc_ucred = kauth_cred_get();
5246
5247 if (uap->options & XATTR_NOSECURITY)
5248 return (EINVAL);
5249
5250 nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
5251 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
5252 if ((error = namei(&nd))) {
5253 return (error);
5254 }
5255 vp = nd.ni_vp;
5256 nameidone(&nd);
5257 if (uap->namebuf != 0 && uap->bufsize > 0) {
5258 // LP64todo - fix this!
5259 auio = uio_createwithbuffer(1, 0, spacetype,
5260 UIO_READ, &uio_buf[0], sizeof(uio_buf));
5261 uio_addiov(auio, uap->namebuf, uap->bufsize);
5262 }
5263
5264 error = vn_listxattr(vp, auio, &attrsize, uap->options, &context);
5265
5266 vnode_put(vp);
5267 if (auio) {
5268 *retval = (user_ssize_t)uap->bufsize - uio_resid(auio);
5269 } else {
5270 *retval = (user_ssize_t)attrsize;
5271 }
5272 return (error);
5273 }
5274
5275 /*
5276 * Retrieve the list of extended attribute names.
5277 */
5278 #warning "code duplication"
5279 int
5280 flistxattr(struct proc *p, struct flistxattr_args *uap, user_ssize_t *retval)
5281 {
5282 struct vnode *vp;
5283 struct vfs_context context;
5284 uio_t auio = NULL;
5285 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5286 size_t attrsize = 0;
5287 int error;
5288 char uio_buf[ UIO_SIZEOF(1) ];
5289
5290 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
5291 return (EINVAL);
5292
5293 if ( (error = file_vnode(uap->fd, &vp)) ) {
5294 return (error);
5295 }
5296 if ( (error = vnode_getwithref(vp)) ) {
5297 file_drop(uap->fd);
5298 return(error);
5299 }
5300 if (uap->namebuf != 0 && uap->bufsize > 0) {
5301 // LP64todo - fix this!
5302 auio = uio_createwithbuffer(1, 0, spacetype,
5303 UIO_READ, &uio_buf[0], sizeof(uio_buf));
5304 uio_addiov(auio, uap->namebuf, uap->bufsize);
5305 }
5306 context.vc_proc = p;
5307 context.vc_ucred = kauth_cred_get();
5308
5309 error = vn_listxattr(vp, auio, &attrsize, uap->options, &context);
5310
5311 vnode_put(vp);
5312 file_drop(uap->fd);
5313 if (auio) {
5314 *retval = (user_ssize_t)uap->bufsize - uio_resid(auio);
5315 } else {
5316 *retval = (user_ssize_t)attrsize;
5317 }
5318 return (error);
5319 }
5320
5321 /*
5322 * Common routine to handle various flavors of statfs data heading out
5323 * to user space.
5324 */
5325 static int
5326 munge_statfs(struct mount *mp, struct vfsstatfs *sfsp,
5327 user_addr_t bufp, int *sizep, boolean_t is_64_bit,
5328 boolean_t partial_copy)
5329 {
5330 int error;
5331 int my_size, copy_size;
5332
5333 if (is_64_bit) {
5334 struct user_statfs sfs;
5335 my_size = copy_size = sizeof(sfs);
5336 bzero(&sfs, my_size);
5337 sfs.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
5338 sfs.f_type = mp->mnt_vtable->vfc_typenum;
5339 sfs.f_reserved1 = (short)sfsp->f_fssubtype;
5340 sfs.f_bsize = (user_long_t)sfsp->f_bsize;
5341 sfs.f_iosize = (user_long_t)sfsp->f_iosize;
5342 sfs.f_blocks = (user_long_t)sfsp->f_blocks;
5343 sfs.f_bfree = (user_long_t)sfsp->f_bfree;
5344 sfs.f_bavail = (user_long_t)sfsp->f_bavail;
5345 sfs.f_files = (user_long_t)sfsp->f_files;
5346 sfs.f_ffree = (user_long_t)sfsp->f_ffree;
5347 sfs.f_fsid = sfsp->f_fsid;
5348 sfs.f_owner = sfsp->f_owner;
5349 strncpy(&sfs.f_fstypename[0], &sfsp->f_fstypename[0], MFSNAMELEN-1);
5350 strncpy(&sfs.f_mntonname[0], &sfsp->f_mntonname[0], MNAMELEN-1);
5351 strncpy(&sfs.f_mntfromname[0], &sfsp->f_mntfromname[0], MNAMELEN-1);
5352
5353 if (partial_copy) {
5354 copy_size -= (sizeof(sfs.f_reserved3) + sizeof(sfs.f_reserved4));
5355 }
5356 error = copyout((caddr_t)&sfs, bufp, copy_size);
5357 }
5358 else {
5359 struct statfs sfs;
5360 my_size = copy_size = sizeof(sfs);
5361 bzero(&sfs, my_size);
5362
5363 sfs.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
5364 sfs.f_type = mp->mnt_vtable->vfc_typenum;
5365 sfs.f_reserved1 = (short)sfsp->f_fssubtype;
5366
5367 /*
5368 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
5369 * have to fudge the numbers here in that case. We inflate the blocksize in order
5370 * to reflect the filesystem size as best we can.
5371 */
5372 if ((sfsp->f_blocks > LONG_MAX)
5373 /* Hack for 4061702 . I think the real fix is for Carbon to
5374 * look for some volume capability and not depend on hidden
5375 * semantics agreed between a FS and carbon.
5376 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
5377 * for Carbon to set bNoVolumeSizes volume attribute.
5378 * Without this the webdavfs files cannot be copied onto
5379 * disk as they look huge. This change should not affect
5380 * XSAN as they should not setting these to -1..
5381 */
5382 && (sfsp->f_blocks != 0xffffffffffffffff)
5383 && (sfsp->f_bfree != 0xffffffffffffffff)
5384 && (sfsp->f_bavail != 0xffffffffffffffff)) {
5385 int shift;
5386
5387 /*
5388 * Work out how far we have to shift the block count down to make it fit.
5389 * Note that it's possible to have to shift so far that the resulting
5390 * blocksize would be unreportably large. At that point, we will clip
5391 * any values that don't fit.
5392 *
5393 * For safety's sake, we also ensure that f_iosize is never reported as
5394 * being smaller than f_bsize.
5395 */
5396 for (shift = 0; shift < 32; shift++) {
5397 if ((sfsp->f_blocks >> shift) <= LONG_MAX)
5398 break;
5399 if ((sfsp->f_bsize << (shift + 1)) > LONG_MAX)
5400 break;
5401 }
5402 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
5403 sfs.f_blocks = (long)__SHIFT_OR_CLIP(sfsp->f_blocks, shift);
5404 sfs.f_bfree = (long)__SHIFT_OR_CLIP(sfsp->f_bfree, shift);
5405 sfs.f_bavail = (long)__SHIFT_OR_CLIP(sfsp->f_bavail, shift);
5406 #undef __SHIFT_OR_CLIP
5407 sfs.f_bsize = (long)(sfsp->f_bsize << shift);
5408 sfs.f_iosize = lmax(sfsp->f_iosize, sfsp->f_bsize);
5409 } else {
5410 /* filesystem is small enough to be reported honestly */
5411 sfs.f_bsize = (long)sfsp->f_bsize;
5412 sfs.f_iosize = (long)sfsp->f_iosize;
5413 sfs.f_blocks = (long)sfsp->f_blocks;
5414 sfs.f_bfree = (long)sfsp->f_bfree;
5415 sfs.f_bavail = (long)sfsp->f_bavail;
5416 }
5417 sfs.f_files = (long)sfsp->f_files;
5418 sfs.f_ffree = (long)sfsp->f_ffree;
5419 sfs.f_fsid = sfsp->f_fsid;
5420 sfs.f_owner = sfsp->f_owner;
5421 strncpy(&sfs.f_fstypename[0], &sfsp->f_fstypename[0], MFSNAMELEN-1);
5422 strncpy(&sfs.f_mntonname[0], &sfsp->f_mntonname[0], MNAMELEN-1);
5423 strncpy(&sfs.f_mntfromname[0], &sfsp->f_mntfromname[0], MNAMELEN-1);
5424
5425 if (partial_copy) {
5426 copy_size -= (sizeof(sfs.f_reserved3) + sizeof(sfs.f_reserved4));
5427 }
5428 error = copyout((caddr_t)&sfs, bufp, copy_size);
5429 }
5430
5431 if (sizep != NULL) {
5432 *sizep = my_size;
5433 }
5434 return(error);
5435 }
5436
5437 /*
5438 * copy stat structure into user_stat structure.
5439 */
5440 void munge_stat(struct stat *sbp, struct user_stat *usbp)
5441 {
5442 usbp->st_dev = sbp->st_dev;
5443 usbp->st_ino = sbp->st_ino;
5444 usbp->st_mode = sbp->st_mode;
5445 usbp->st_nlink = sbp->st_nlink;
5446 usbp->st_uid = sbp->st_uid;
5447 usbp->st_gid = sbp->st_gid;
5448 usbp->st_rdev = sbp->st_rdev;
5449 #ifndef _POSIX_SOURCE
5450 usbp->st_atimespec.tv_sec = sbp->st_atimespec.tv_sec;
5451 usbp->st_atimespec.tv_nsec = sbp->st_atimespec.tv_nsec;
5452 usbp->st_mtimespec.tv_sec = sbp->st_mtimespec.tv_sec;
5453 usbp->st_mtimespec.tv_nsec = sbp->st_mtimespec.tv_nsec;
5454 usbp->st_ctimespec.tv_sec = sbp->st_ctimespec.tv_sec;
5455 usbp->st_ctimespec.tv_nsec = sbp->st_ctimespec.tv_nsec;
5456 #else
5457 usbp->st_atime = sbp->st_atime;
5458 usbp->st_atimensec = sbp->st_atimensec;
5459 usbp->st_mtime = sbp->st_mtime;
5460 usbp->st_mtimensec = sbp->st_mtimensec;
5461 usbp->st_ctime = sbp->st_ctime;
5462 usbp->st_ctimensec = sbp->st_ctimensec;
5463 #endif
5464 usbp->st_size = sbp->st_size;
5465 usbp->st_blocks = sbp->st_blocks;
5466 usbp->st_blksize = sbp->st_blksize;
5467 usbp->st_flags = sbp->st_flags;
5468 usbp->st_gen = sbp->st_gen;
5469 usbp->st_lspare = sbp->st_lspare;
5470 usbp->st_qspare[0] = sbp->st_qspare[0];
5471 usbp->st_qspare[1] = sbp->st_qspare[1];
5472 }