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