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