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