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