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