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