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