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