]> git.saurik.com Git - apple/xnu.git/blame - bsd/vfs/vfs_xattr.c
xnu-4570.71.2.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_xattr.c
CommitLineData
91447636 1/*
316670eb 2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
91447636 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636 27 */
2d21ac55
A
28/*
29 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
30 * support for mandatory and extensible security protections. This notice
31 * is included in support of clause 2.2 (b) of the Apple Public License,
32 * Version 2.0.
33 */
34
91447636
A
35#include <sys/param.h>
36
37#include <sys/fcntl.h>
38#include <sys/fsevents.h>
39#include <sys/kernel.h>
40#include <sys/kauth.h>
41#include <sys/malloc.h>
2d21ac55 42#include <sys/mount_internal.h>
91447636
A
43#include <sys/namei.h>
44#include <sys/proc_internal.h>
45#include <sys/stat.h>
46#include <sys/uio.h>
47#include <sys/utfconv.h>
48#include <sys/vnode.h>
49#include <sys/vnode_internal.h>
91447636
A
50#include <sys/xattr.h>
51
4452a7af 52#include <libkern/OSByteOrder.h>
91447636
A
53#include <vm/vm_kern.h>
54
2d21ac55
A
55#if CONFIG_MACF
56#include <security/mac_framework.h>
57#endif
58
59
60#if NAMEDSTREAMS
61
316670eb
A
62static int shadow_sequence;
63
91447636 64/*
b0d623f7 65 * We use %p to prevent loss of precision for pointers on varying architectures.
91447636 66 */
316670eb
A
67
68#define SHADOW_NAME_FMT ".vfs_rsrc_stream_%p%08x%p"
69#define SHADOW_DIR_FMT ".vfs_rsrc_streams_%p%x"
70#define SHADOW_DIR_CONTAINER "/var/run"
71
2d21ac55 72#define MAKE_SHADOW_NAME(VP, NAME) \
316670eb
A
73 snprintf((NAME), sizeof((NAME)), (SHADOW_NAME_FMT), \
74 ((void*)(VM_KERNEL_ADDRPERM(VP))), \
39236c6e 75 (VP)->v_id, \
316670eb 76 ((void*)(VM_KERNEL_ADDRPERM((VP)->v_data))))
2d21ac55 77
316670eb
A
78/* The full path to the shadow directory */
79#define MAKE_SHADOW_DIRNAME(VP, NAME) \
80 snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_CONTAINER "/" SHADOW_DIR_FMT), \
81 ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence)
82
83/* The shadow directory as a 'leaf' entry */
84#define MAKE_SHADOW_DIR_LEAF(VP, NAME) \
85 snprintf((NAME), sizeof((NAME)), (SHADOW_DIR_FMT), \
86 ((void*)(VM_KERNEL_ADDRPERM(VP))), shadow_sequence)
2d21ac55 87
2d21ac55
A
88static int default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context);
89
90static int default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context);
91447636 91
2d21ac55 92static int default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context);
91447636 93
2d21ac55
A
94static int getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize, int *creator, vfs_context_t context);
95
39236c6e 96static int get_shadow_dir(vnode_t *sdvpp);
2d21ac55 97
39236c6e 98#endif /* NAMEDSTREAMS */
2d21ac55
A
99
100/*
101 * Default xattr support routines.
102 */
91447636 103
39236c6e
A
104static int default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size, int options,
105 vfs_context_t context);
106static int default_setxattr(vnode_t vp, const char *name, uio_t uio, int options,
107 vfs_context_t context);
91447636 108static int default_listxattr(vnode_t vp, uio_t uio, size_t *size, int options,
39236c6e
A
109 vfs_context_t context);
110static int default_removexattr(vnode_t vp, const char *name, int options,
111 vfs_context_t context);
91447636
A
112
113/*
114 * Retrieve the data of an extended attribute.
115 */
116int
117vn_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
118 int options, vfs_context_t context)
119{
120 int error;
121
39236c6e 122 if (!XATTR_VNODE_SUPPORTED(vp)) {
91447636
A
123 return (EPERM);
124 }
2d21ac55
A
125#if NAMEDSTREAMS
126 /* getxattr calls are not allowed for streams. */
127 if (vp->v_flag & VISNAMEDSTREAM) {
128 error = EPERM;
91447636 129 goto out;
2d21ac55
A
130 }
131#endif
132 /*
133 * Non-kernel request need extra checks performed.
134 *
135 * The XATTR_NOSECURITY flag implies a kernel request.
136 */
137 if (!(options & XATTR_NOSECURITY)) {
138#if CONFIG_MACF
139 error = mac_vnode_check_getextattr(context, vp, name, uio);
140 if (error)
141 goto out;
142#endif /* MAC */
143 if ((error = xattr_validatename(name))) {
144 goto out;
145 }
146 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context))) {
147 goto out;
148 }
149 /* The offset can only be non-zero for resource forks. */
150 if (uio != NULL && uio_offset(uio) != 0 &&
151 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
152 error = EINVAL;
153 goto out;
154 }
155 }
91447636
A
156
157 /* The offset can only be non-zero for resource forks. */
158 if (uio != NULL && uio_offset(uio) != 0 &&
159 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
160 error = EINVAL;
161 goto out;
162 }
163
164 error = VNOP_GETXATTR(vp, name, uio, size, options, context);
2d21ac55 165 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
166 /*
167 * A filesystem may keep some EAs natively and return ENOTSUP for others.
91447636
A
168 */
169 error = default_getxattr(vp, name, uio, size, options, context);
170 }
171out:
172 return (error);
173}
174
175/*
176 * Set the data of an extended attribute.
177 */
178int
179vn_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
180{
181 int error;
182
39236c6e 183 if (!XATTR_VNODE_SUPPORTED(vp)) {
91447636
A
184 return (EPERM);
185 }
2d21ac55
A
186#if NAMEDSTREAMS
187 /* setxattr calls are not allowed for streams. */
188 if (vp->v_flag & VISNAMEDSTREAM) {
189 error = EPERM;
190 goto out;
191 }
192#endif
91447636
A
193 if ((options & (XATTR_REPLACE|XATTR_CREATE)) == (XATTR_REPLACE|XATTR_CREATE)) {
194 return (EINVAL);
195 }
196 if ((error = xattr_validatename(name))) {
197 return (error);
198 }
2d21ac55
A
199 if (!(options & XATTR_NOSECURITY)) {
200#if CONFIG_MACF
201 error = mac_vnode_check_setextattr(context, vp, name, uio);
202 if (error)
203 goto out;
204#endif /* MAC */
205 error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context);
206 if (error)
207 goto out;
208 }
91447636
A
209 /* The offset can only be non-zero for resource forks. */
210 if (uio_offset(uio) != 0 &&
211 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0 ) {
212 error = EINVAL;
213 goto out;
214 }
215
216 error = VNOP_SETXATTR(vp, name, uio, options, context);
217#ifdef DUAL_EAS
218 /*
219 * An EJUSTRETURN is from a filesystem which keeps this xattr
220 * natively as well as in a dot-underscore file. In this case the
221 * EJUSTRETURN means the filesytem has done nothing, but identifies the
222 * EA as one which may be represented natively and/or in a DU, and
223 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in
224 * in vn_setxattr can we do the getxattrs needed to ascertain whether
225 * the XATTR_{CREATE,REPLACE} should yield an error.
226 */
227 if (error == EJUSTRETURN) {
228 int native = 0, dufile = 0;
229 size_t sz; /* not used */
230
231 native = VNOP_GETXATTR(vp, name, NULL, &sz, 0, context) ? 0 : 1;
232 dufile = default_getxattr(vp, name, NULL, &sz, 0, context) ? 0 : 1;
233 if (options & XATTR_CREATE && (native || dufile)) {
234 error = EEXIST;
235 goto out;
236 }
237 if (options & XATTR_REPLACE && !(native || dufile)) {
238 error = ENOATTR;
239 goto out;
240 }
241 /*
242 * Having determined no CREATE/REPLACE error should result, we
243 * zero those bits, so both backing stores get written to.
244 */
245 options &= ~(XATTR_CREATE | XATTR_REPLACE);
246 error = VNOP_SETXATTR(vp, name, uio, options, context);
247 /* the mainline path here is to have error==ENOTSUP ... */
248 }
249#endif /* DUAL_EAS */
2d21ac55 250 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
251 /*
252 * A filesystem may keep some EAs natively and return ENOTSUP for others.
91447636
A
253 */
254 error = default_setxattr(vp, name, uio, options, context);
255 }
2d21ac55 256#if CONFIG_MACF
39037602
A
257 if ((error == 0) && !(options & XATTR_NOSECURITY)) {
258 mac_vnode_notify_setextattr(context, vp, name, uio);
259 if (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL)
260 mac_vnode_label_update_extattr(vnode_mount(vp), vp, name);
261 }
2d21ac55 262#endif
91447636
A
263out:
264 return (error);
265}
266
267/*
268 * Remove an extended attribute.
269 */
270int
271vn_removexattr(vnode_t vp, const char * name, int options, vfs_context_t context)
272{
273 int error;
274
39236c6e 275 if (!XATTR_VNODE_SUPPORTED(vp)) {
91447636
A
276 return (EPERM);
277 }
2d21ac55
A
278#if NAMEDSTREAMS
279 /* removexattr calls are not allowed for streams. */
280 if (vp->v_flag & VISNAMEDSTREAM) {
281 error = EPERM;
282 goto out;
283 }
284#endif
91447636
A
285 if ((error = xattr_validatename(name))) {
286 return (error);
287 }
2d21ac55
A
288 if (!(options & XATTR_NOSECURITY)) {
289#if CONFIG_MACF
290 error = mac_vnode_check_deleteextattr(context, vp, name);
291 if (error)
292 goto out;
293#endif /* MAC */
294 error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context);
295 if (error)
296 goto out;
297 }
91447636 298 error = VNOP_REMOVEXATTR(vp, name, options, context);
2d21ac55 299 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
300 /*
301 * A filesystem may keep some EAs natively and return ENOTSUP for others.
91447636
A
302 */
303 error = default_removexattr(vp, name, options, context);
304#ifdef DUAL_EAS
305 } else if (error == EJUSTRETURN) {
306 /*
307 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well
308 * as in a dot-underscore file. EJUSTRETURN means the filesytem did remove
309 * a native xattr, so failure to find it in a DU file during
310 * default_removexattr should not be considered an error.
311 */
312 error = default_removexattr(vp, name, options, context);
313 if (error == ENOATTR)
314 error = 0;
315#endif /* DUAL_EAS */
316 }
2d21ac55 317#if CONFIG_MACF
39037602
A
318 if ((error == 0) && !(options & XATTR_NOSECURITY)) {
319 mac_vnode_notify_deleteextattr(context, vp, name);
320 if (vfs_flags(vnode_mount(vp)) & MNT_MULTILABEL)
321 mac_vnode_label_update_extattr(vnode_mount(vp), vp, name);
322 }
2d21ac55 323#endif
91447636
A
324out:
325 return (error);
326}
327
328/*
329 * Retrieve the list of extended attribute names.
330 */
331int
332vn_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t context)
333{
334 int error;
335
39236c6e 336 if (!XATTR_VNODE_SUPPORTED(vp)) {
91447636
A
337 return (EPERM);
338 }
2d21ac55
A
339#if NAMEDSTREAMS
340 /* listxattr calls are not allowed for streams. */
341 if (vp->v_flag & VISNAMEDSTREAM) {
342 return (EPERM);
343 }
344#endif
345
346 if (!(options & XATTR_NOSECURITY)) {
347#if CONFIG_MACF
348 error = mac_vnode_check_listextattr(context, vp);
349 if (error)
350 goto out;
351#endif /* MAC */
352
353 error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context);
354 if (error)
355 goto out;
356 }
91447636
A
357
358 error = VNOP_LISTXATTR(vp, uio, size, options, context);
2d21ac55 359 if (error == ENOTSUP && !(options & XATTR_NODEFAULT)) {
91447636
A
360 /*
361 * A filesystem may keep some but not all EAs natively, in which case
362 * the native EA names will have been uiomove-d out (or *size updated)
39236c6e 363 * and the default_listxattr here will finish the job.
91447636
A
364 */
365 error = default_listxattr(vp, uio, size, options, context);
366 }
367out:
368 return (error);
369}
370
371int
372xattr_validatename(const char *name)
373{
374 int namelen;
375
376 if (name == NULL || name[0] == '\0') {
377 return (EINVAL);
378 }
5ba3f43e 379 namelen = strlen(name);
6601e61a 380 if (name[namelen] != '\0')
91447636 381 return (ENAMETOOLONG);
2d21ac55
A
382
383 if (utf8_validatestr((const unsigned char *)name, namelen) != 0)
91447636 384 return (EINVAL);
6601e61a 385
91447636
A
386 return (0);
387}
388
389
390/*
391 * Determine whether an EA is a protected system attribute.
392 */
393int
394xattr_protected(const char *attrname)
395{
396 return(!strncmp(attrname, "com.apple.system.", 17));
397}
398
399
2d21ac55 400#if NAMEDSTREAMS
39236c6e 401
2d21ac55
A
402/*
403 * Obtain a named stream from vnode vp.
404 */
405errno_t
406vnode_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, int flags, vfs_context_t context)
407{
408 int error;
409
5ba3f43e 410 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) {
2d21ac55 411 error = VNOP_GETNAMEDSTREAM(vp, svpp, name, op, flags, context);
5ba3f43e
A
412 } else {
413 if (flags)
414 error = ENOTSUP;
415 else
416 error = default_getnamedstream(vp, svpp, name, op, context);
417 }
2d21ac55
A
418
419 if (error == 0) {
c910b4d9 420 uint32_t streamflags = VISNAMEDSTREAM;
2d21ac55 421 vnode_t svp = *svpp;
c910b4d9 422
b0d623f7 423 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
c910b4d9 424 streamflags |= VISSHADOW;
b0d623f7
A
425 }
426
2d21ac55 427 /* Tag the vnode. */
c910b4d9
A
428 vnode_lock_spin(svp);
429 svp->v_flag |= streamflags;
2d21ac55 430 vnode_unlock(svp);
b0d623f7
A
431
432 /* Tag the parent so we know to flush credentials for streams on setattr */
433 vnode_lock_spin(vp);
434 vp->v_lflag |= VL_HASSTREAMS;
435 vnode_unlock(vp);
436
437 /* Make the file it's parent.
438 * Note: This parent link helps us distinguish vnodes for
439 * shadow stream files from vnodes for resource fork on file
440 * systems that support namedstream natively (both have
441 * VISNAMEDSTREAM set) by allowing access to mount structure
442 * for checking MNTK_NAMED_STREAMS bit at many places in the
443 * code.
cf7d32b8 444 */
2d21ac55
A
445 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
446 }
447
448 return (error);
449}
450
451/*
452 * Make a named stream for vnode vp.
453 */
454errno_t
455vnode_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t context)
456{
457 int error;
458
459 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
460 error = VNOP_MAKENAMEDSTREAM(vp, svpp, name, flags, context);
461 else
462 error = default_makenamedstream(vp, svpp, name, context);
463
464 if (error == 0) {
c910b4d9 465 uint32_t streamflags = VISNAMEDSTREAM;
2d21ac55
A
466 vnode_t svp = *svpp;
467
468 /* Tag the vnode. */
c910b4d9
A
469 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
470 streamflags |= VISSHADOW;
471 }
b0d623f7 472
c910b4d9
A
473 /* Tag the vnode. */
474 vnode_lock_spin(svp);
475 svp->v_flag |= streamflags;
476 vnode_unlock(svp);
477
b0d623f7
A
478 /* Tag the parent so we know to flush credentials for streams on setattr */
479 vnode_lock_spin(vp);
480 vp->v_lflag |= VL_HASSTREAMS;
481 vnode_unlock(vp);
482
483 /* Make the file it's parent.
484 * Note: This parent link helps us distinguish vnodes for
485 * shadow stream files from vnodes for resource fork on file
486 * systems that support namedstream natively (both have
487 * VISNAMEDSTREAM set) by allowing access to mount structure
488 * for checking MNTK_NAMED_STREAMS bit at many places in the
489 * code.
cf7d32b8 490 */
2d21ac55
A
491 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
492 }
493 return (error);
494}
495
496/*
497 * Remove a named stream from vnode vp.
498 */
499errno_t
500vnode_removenamedstream(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t context)
501{
502 int error;
503
504 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
505 error = VNOP_REMOVENAMEDSTREAM(vp, svp, name, flags, context);
506 else
507 error = default_removenamedstream(vp, name, context);
508
509 return (error);
510}
511
512#define NS_IOBUFSIZE (128 * 1024)
513
514/*
515 * Release a named stream shadow file.
cf7d32b8
A
516 *
517 * Note: This function is called from two places where we do not need
518 * to check if the vnode has any references held before deleting the
519 * shadow file. Once from vclean() when the vnode is being reclaimed
520 * and we do not hold any references on the vnode. Second time from
521 * default_getnamedstream() when we get an error during shadow stream
522 * file initialization so that other processes who are waiting for the
523 * shadow stream file initialization by the creator will get opportunity
524 * to create and initialize the file again.
2d21ac55
A
525 */
526errno_t
39236c6e 527vnode_relenamedstream(vnode_t vp, vnode_t svp) {
2d21ac55
A
528 vnode_t dvp;
529 struct componentname cn;
b0d623f7 530 char tmpname[80];
2d21ac55 531 errno_t err;
39236c6e
A
532
533 /*
534 * We need to use the kernel context here. If we used the supplied
535 * VFS context we have no clue whether or not it originated from userland
536 * where it could be subject to a chroot jail. We need to ensure that all
537 * filesystem access to shadow files is done on the same FS regardless of
538 * userland process restrictions.
539 */
540 vfs_context_t kernelctx = vfs_context_kernel();
2d21ac55 541
2d21ac55
A
542 cache_purge(svp);
543
544 vnode_lock(svp);
545 MAKE_SHADOW_NAME(vp, tmpname);
546 vnode_unlock(svp);
547
548 cn.cn_nameiop = DELETE;
549 cn.cn_flags = ISLASTCN;
39236c6e 550 cn.cn_context = kernelctx;
2d21ac55
A
551 cn.cn_pnbuf = tmpname;
552 cn.cn_pnlen = sizeof(tmpname);
553 cn.cn_nameptr = cn.cn_pnbuf;
554 cn.cn_namelen = strlen(tmpname);
555
39236c6e
A
556 /*
557 * Obtain the vnode for the shadow files directory. Make sure to
558 * use the kernel ctx as described above.
559 */
560 err = get_shadow_dir(&dvp);
2d21ac55
A
561 if (err != 0) {
562 return err;
563 }
b0d623f7 564
39236c6e 565 (void) VNOP_REMOVE(dvp, svp, &cn, 0, kernelctx);
2d21ac55
A
566 vnode_put(dvp);
567
568 return (0);
569}
570
571/*
572 * Flush a named stream shadow file.
39236c6e
A
573 *
574 * 'vp' represents the AppleDouble file.
575 * 'svp' represents the shadow file.
2d21ac55
A
576 */
577errno_t
578vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
579{
580 struct vnode_attr va;
581 uio_t auio = NULL;
582 caddr_t bufptr = NULL;
583 size_t bufsize = 0;
584 size_t offset;
585 size_t iosize;
586 size_t datasize;
587 int error;
39236c6e
A
588 /*
589 * The kernel context must be used for all I/O to the shadow file
590 * and its namespace operations
591 */
592 vfs_context_t kernelctx = vfs_context_kernel();
593
594 /* The supplied context is used for access to the AD file itself */
2d21ac55
A
595
596 VATTR_INIT(&va);
597 VATTR_WANTED(&va, va_data_size);
598 if (VNOP_GETATTR(svp, &va, context) != 0 ||
599 !VATTR_IS_SUPPORTED(&va, va_data_size)) {
600 return (0);
601 }
602 datasize = va.va_data_size;
6d2010ae 603 if (datasize == 0) {
2d21ac55
A
604 (void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
605 return (0);
606 }
607
608 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
3e170ce0 609 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize, VM_KERN_MEMORY_FILE)) {
2d21ac55
A
610 return (ENOMEM);
611 }
b0d623f7 612 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
613 offset = 0;
614
615 /*
616 * Copy the shadow stream file data into the resource fork.
617 */
39236c6e 618 error = VNOP_OPEN(svp, 0, kernelctx);
2d21ac55
A
619 if (error) {
620 printf("vnode_flushnamedstream: err %d opening file\n", error);
621 goto out;
622 }
623 while (offset < datasize) {
624 iosize = MIN(datasize - offset, iosize);
625
b0d623f7 626 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
2d21ac55 627 uio_addiov(auio, (uintptr_t)bufptr, iosize);
39236c6e 628 error = VNOP_READ(svp, auio, 0, kernelctx);
2d21ac55
A
629 if (error) {
630 break;
631 }
632 /* Since there's no truncate xattr we must remove the resource fork. */
633 if (offset == 0) {
634 error = default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
635 if ((error != 0) && (error != ENOATTR)) {
636 break;
637 }
638 }
b0d623f7 639 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
2d21ac55
A
640 uio_addiov(auio, (uintptr_t)bufptr, iosize);
641 error = vn_setxattr(vp, XATTR_RESOURCEFORK_NAME, auio, XATTR_NOSECURITY, context);
642 if (error) {
643 break;
644 }
645 offset += iosize;
646 }
39236c6e
A
647
648 /* close shadowfile */
649 (void) VNOP_CLOSE(svp, 0, kernelctx);
2d21ac55
A
650out:
651 if (bufptr) {
652 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
653 }
654 if (auio) {
655 uio_free(auio);
656 }
657 return (error);
658}
659
39236c6e 660
4b17d6b6
A
661/*
662 * Verify that the vnode 'vp' is a vnode that lives in the shadow
663 * directory. We can't just query the parent pointer directly since
664 * the shadowfile is hooked up to the actual file it's a stream for.
665 */
39236c6e 666errno_t vnode_verifynamedstream(vnode_t vp) {
4b17d6b6
A
667 int error;
668 struct vnode *shadow_dvp = NULL;
669 struct vnode *shadowfile = NULL;
670 struct componentname cn;
39236c6e
A
671
672 /*
673 * We need to use the kernel context here. If we used the supplied
674 * VFS context we have no clue whether or not it originated from userland
675 * where it could be subject to a chroot jail. We need to ensure that all
676 * filesystem access to shadow files is done on the same FS regardless of
677 * userland process restrictions.
678 */
679 vfs_context_t kernelctx = vfs_context_kernel();
4b17d6b6 680 char tmpname[80];
39236c6e 681
4b17d6b6
A
682
683 /* Get the shadow directory vnode */
39236c6e 684 error = get_shadow_dir(&shadow_dvp);
4b17d6b6
A
685 if (error) {
686 return error;
687 }
688
689 /* Re-generate the shadow name in the buffer */
690 MAKE_SHADOW_NAME (vp, tmpname);
691
692 /* Look up item in shadow dir */
693 bzero(&cn, sizeof(cn));
694 cn.cn_nameiop = LOOKUP;
695 cn.cn_flags = ISLASTCN | CN_ALLOWRSRCFORK;
39236c6e 696 cn.cn_context = kernelctx;
4b17d6b6
A
697 cn.cn_pnbuf = tmpname;
698 cn.cn_pnlen = sizeof(tmpname);
699 cn.cn_nameptr = cn.cn_pnbuf;
700 cn.cn_namelen = strlen(tmpname);
701
39236c6e 702 if (VNOP_LOOKUP (shadow_dvp, &shadowfile, &cn, kernelctx) == 0) {
4b17d6b6
A
703 /* is the pointer the same? */
704 if (shadowfile == vp) {
705 error = 0;
706 }
707 else {
708 error = EPERM;
709 }
710 /* drop the iocount acquired */
711 vnode_put (shadowfile);
712 }
713
714 /* Drop iocount on shadow dir */
715 vnode_put (shadow_dvp);
716 return error;
717}
2d21ac55 718
39236c6e
A
719/*
720 * Access or create the shadow file as needed.
721 *
722 * 'makestream' with non-zero value means that we need to guarantee we were the
723 * creator of the shadow file.
724 *
725 * 'context' is the user supplied context for the original VFS operation that
726 * caused us to need a shadow file.
727 *
728 * int pointed to by 'creator' is nonzero if we created the shadowfile.
729 */
2d21ac55
A
730static int
731getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
732 int *creator, vfs_context_t context)
733{
734 vnode_t dvp = NULLVP;
735 vnode_t svp = NULLVP;
736 struct componentname cn;
737 struct vnode_attr va;
b0d623f7 738 char tmpname[80];
2d21ac55
A
739 size_t datasize = 0;
740 int error = 0;
6d2010ae 741 int retries = 0;
39236c6e 742 vfs_context_t kernelctx = vfs_context_kernel();
2d21ac55 743
6d2010ae 744retry_create:
2d21ac55 745 *creator = 0;
2d21ac55
A
746 /* Establish a unique file name. */
747 MAKE_SHADOW_NAME(vp, tmpname);
748 bzero(&cn, sizeof(cn));
749 cn.cn_nameiop = LOOKUP;
750 cn.cn_flags = ISLASTCN;
751 cn.cn_context = context;
752 cn.cn_pnbuf = tmpname;
753 cn.cn_pnlen = sizeof(tmpname);
754 cn.cn_nameptr = cn.cn_pnbuf;
755 cn.cn_namelen = strlen(tmpname);
756
757 /* Pick up uid, gid, mode and date from original file. */
758 VATTR_INIT(&va);
759 VATTR_WANTED(&va, va_uid);
760 VATTR_WANTED(&va, va_gid);
761 VATTR_WANTED(&va, va_mode);
762 VATTR_WANTED(&va, va_create_time);
763 VATTR_WANTED(&va, va_modify_time);
764 if (VNOP_GETATTR(vp, &va, context) != 0 ||
765 !VATTR_IS_SUPPORTED(&va, va_uid) ||
766 !VATTR_IS_SUPPORTED(&va, va_gid) ||
767 !VATTR_IS_SUPPORTED(&va, va_mode)) {
768 va.va_uid = KAUTH_UID_NONE;
769 va.va_gid = KAUTH_GID_NONE;
770 va.va_mode = S_IRUSR | S_IWUSR;
771 }
772 va.va_vaflags = VA_EXCLUSIVE;
773 VATTR_SET(&va, va_type, VREG);
774 /* We no longer change the access, but we still hide it. */
775 VATTR_SET(&va, va_flags, UF_HIDDEN);
776
777 /* Obtain the vnode for the shadow files directory. */
39236c6e 778 if (get_shadow_dir(&dvp) != 0) {
2d21ac55
A
779 error = ENOTDIR;
780 goto out;
781 }
782 if (!makestream) {
783 /* See if someone else already has it open. */
39236c6e 784 if (VNOP_LOOKUP(dvp, &svp, &cn, kernelctx) == 0) {
2d21ac55
A
785 /* Double check existence by asking for size. */
786 VATTR_INIT(&va);
787 VATTR_WANTED(&va, va_data_size);
788 if (VNOP_GETATTR(svp, &va, context) == 0 &&
789 VATTR_IS_SUPPORTED(&va, va_data_size)) {
790 goto out; /* OK to use. */
791 }
792 }
793
39236c6e
A
794 /*
795 * Otherwise make sure the resource fork data exists.
796 * Use the supplied context for accessing the AD file.
797 */
2d21ac55
A
798 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &datasize,
799 XATTR_NOSECURITY, context);
800 /*
801 * To maintain binary compatibility with legacy Carbon
802 * emulated resource fork support, if the resource fork
803 * doesn't exist but the Finder Info does, then act as
804 * if an empty resource fork is present (see 4724359).
805 */
806 if ((error == ENOATTR) &&
807 (vn_getxattr(vp, XATTR_FINDERINFO_NAME, NULL, &datasize,
808 XATTR_NOSECURITY, context) == 0)) {
809 datasize = 0;
810 error = 0;
811 } else {
812 if (error) {
813 goto out;
814 }
815
816 /* If the resource fork exists, its size is expected to be non-zero. */
817 if (datasize == 0) {
818 error = ENOATTR;
819 goto out;
820 }
821 }
822 }
823 /* Create the shadow stream file. */
39236c6e 824 error = VNOP_CREATE(dvp, &svp, &cn, &va, kernelctx);
2d21ac55 825 if (error == 0) {
7e4a7d39 826 vnode_recycle(svp);
2d21ac55 827 *creator = 1;
6d2010ae
A
828 }
829 else if ((error == EEXIST) && !makestream) {
39236c6e 830 error = VNOP_LOOKUP(dvp, &svp, &cn, kernelctx);
2d21ac55 831 }
6d2010ae
A
832 else if ((error == ENOENT) && !makestream) {
833 /*
834 * We could have raced with a rmdir on the shadow directory
835 * post-lookup. Retry from the beginning, 1x only, to
836 * try and see if we need to re-create the shadow directory
837 * in get_shadow_dir.
838 */
839 if (retries == 0) {
840 retries++;
841 if (dvp) {
842 vnode_put (dvp);
843 dvp = NULLVP;
844 }
845 if (svp) {
846 vnode_put (svp);
847 svp = NULLVP;
848 }
849 goto retry_create;
850 }
851 /* Otherwise, just error out normally below */
852 }
853
2d21ac55
A
854out:
855 if (dvp) {
856 vnode_put(dvp);
857 }
858 if (error) {
859 /* On errors, clean up shadow stream file. */
860 if (svp) {
861 vnode_put(svp);
862 svp = NULLVP;
863 }
864 }
865 *svpp = svp;
866 if (rsrcsize) {
867 *rsrcsize = datasize;
868 }
869 return (error);
870}
871
872
873static int
874default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context)
875{
876 vnode_t svp = NULLVP;
877 uio_t auio = NULL;
878 caddr_t bufptr = NULL;
879 size_t bufsize = 0;
880 size_t datasize = 0;
881 int creator;
882 int error;
883
39236c6e
A
884 /* need the kernel context for accessing the shadowfile */
885 vfs_context_t kernelctx = vfs_context_kernel();
886
2d21ac55
A
887 /*
888 * Only the "com.apple.ResourceFork" stream is supported here.
889 */
890 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
891 *svpp = NULLVP;
892 return (ENOATTR);
893 }
894retry:
895 /*
896 * Obtain a shadow file for the resource fork I/O.
39236c6e
A
897 *
898 * Need to pass along the supplied context so that getshadowfile
899 * can access the AD file as needed, using it.
2d21ac55
A
900 */
901 error = getshadowfile(vp, &svp, 0, &datasize, &creator, context);
902 if (error) {
903 *svpp = NULLVP;
904 return (error);
905 }
906
907 /*
908 * The creator of the shadow file provides its file data,
b0d623f7
A
909 * all other threads should wait until its ready. In order to
910 * prevent a deadlock during error codepaths, we need to check if the
911 * vnode is being created, or if it has failed out. Regardless of success or
912 * failure, we set the VISSHADOW bit on the vnode, so we check that
913 * if the vnode's flags don't have VISNAMEDSTREAM set. If it doesn't,
914 * then we can infer the creator isn't done yet. If it's there, but
915 * VISNAMEDSTREAM is not set, then we can infer it errored out and we should
916 * try again.
2d21ac55
A
917 */
918 if (!creator) {
919 vnode_lock(svp);
920 if (svp->v_flag & VISNAMEDSTREAM) {
921 /* data is ready, go use it */
922 vnode_unlock(svp);
923 goto out;
924 } else {
b0d623f7
A
925 /* It's not ready, wait for it (sleep using v_parent as channel) */
926 if ((svp->v_flag & VISSHADOW)) {
927 /*
928 * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other
929 * thread is done with this vnode. Just unlock the vnode and try again
930 */
931 vnode_unlock(svp);
932 }
933 else {
934 /* Otherwise, sleep if the shadow file is not created yet */
935 msleep((caddr_t)&svp->v_parent, &svp->v_lock, PINOD | PDROP,
936 "getnamedstream", NULL);
937 }
2d21ac55
A
938 vnode_put(svp);
939 svp = NULLVP;
940 goto retry;
941 }
942 }
943
944 /*
945 * Copy the real resource fork data into shadow stream file.
946 */
947 if (op == NS_OPEN && datasize != 0) {
948 size_t offset;
949 size_t iosize;
950
951 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
3e170ce0 952 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize, VM_KERN_MEMORY_FILE)) {
2d21ac55
A
953 error = ENOMEM;
954 goto out;
955 }
956
b0d623f7 957 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
958 offset = 0;
959
39236c6e
A
960 /* open the shadow file */
961 error = VNOP_OPEN(svp, 0, kernelctx);
2d21ac55
A
962 if (error) {
963 goto out;
964 }
965 while (offset < datasize) {
966 size_t tmpsize;
967
968 iosize = MIN(datasize - offset, iosize);
969
b0d623f7 970 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
2d21ac55 971 uio_addiov(auio, (uintptr_t)bufptr, iosize);
39236c6e 972 /* use supplied ctx for AD file */
2d21ac55
A
973 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, auio, &tmpsize,
974 XATTR_NOSECURITY, context);
975 if (error) {
976 break;
977 }
978
b0d623f7 979 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
2d21ac55 980 uio_addiov(auio, (uintptr_t)bufptr, iosize);
39236c6e
A
981 /* kernel context for writing shadowfile */
982 error = VNOP_WRITE(svp, auio, 0, kernelctx);
2d21ac55
A
983 if (error) {
984 break;
985 }
986 offset += iosize;
987 }
39236c6e
A
988
989 /* close shadow file */
990 (void) VNOP_CLOSE(svp, 0, kernelctx);
2d21ac55
A
991 }
992out:
993 /* Wake up anyone waiting for svp file content */
994 if (creator) {
995 if (error == 0) {
996 vnode_lock(svp);
b0d623f7
A
997 /* VISSHADOW would be set later on anyway, so we set it now */
998 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
2d21ac55
A
999 wakeup((caddr_t)&svp->v_parent);
1000 vnode_unlock(svp);
1001 } else {
b0d623f7
A
1002 /* On post create errors, get rid of the shadow file. This
1003 * way if there is another process waiting for initialization
1004 * of the shadowfile by the current process will wake up and
1005 * retry by creating and initializing the shadow file again.
1006 * Also add the VISSHADOW bit here to indicate we're done operating
1007 * on this vnode.
cf7d32b8 1008 */
39236c6e 1009 (void)vnode_relenamedstream(vp, svp);
b0d623f7
A
1010 vnode_lock (svp);
1011 svp->v_flag |= VISSHADOW;
2d21ac55 1012 wakeup((caddr_t)&svp->v_parent);
b0d623f7 1013 vnode_unlock(svp);
2d21ac55
A
1014 }
1015 }
1016
1017 if (bufptr) {
1018 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
1019 }
1020 if (auio) {
1021 uio_free(auio);
1022 }
1023 if (error) {
1024 /* On errors, clean up shadow stream file. */
1025 if (svp) {
1026 vnode_put(svp);
1027 svp = NULLVP;
1028 }
1029 }
1030 *svpp = svp;
1031 return (error);
1032}
1033
1034static int
1035default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context)
1036{
1037 int creator;
1038 int error;
1039
1040 /*
1041 * Only the "com.apple.ResourceFork" stream is supported here.
1042 */
1043 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
1044 *svpp = NULLVP;
1045 return (ENOATTR);
1046 }
39236c6e
A
1047
1048 /* Supply the context to getshadowfile so it can manipulate the AD file */
2d21ac55
A
1049 error = getshadowfile(vp, svpp, 1, NULL, &creator, context);
1050
1051 /*
1052 * Wake up any waiters over in default_getnamedstream().
1053 */
1054 if ((error == 0) && (*svpp != NULL) && creator) {
1055 vnode_t svp = *svpp;
1056
1057 vnode_lock(svp);
b0d623f7
A
1058 /* If we're the creator, mark it as a named stream */
1059 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
2d21ac55
A
1060 /* Wakeup any waiters on the v_parent channel */
1061 wakeup((caddr_t)&svp->v_parent);
1062 vnode_unlock(svp);
b0d623f7 1063
2d21ac55 1064 }
b0d623f7 1065
2d21ac55
A
1066 return (error);
1067}
1068
1069static int
1070default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context)
1071{
1072 /*
1073 * Only the "com.apple.ResourceFork" stream is supported here.
1074 */
1075 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
1076 return (ENOATTR);
1077 }
1078 /*
1079 * XXX - what about other opened instances?
1080 */
1081 return default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
1082}
1083
1084static int
39236c6e 1085get_shadow_dir(vnode_t *sdvpp) {
2d21ac55
A
1086 vnode_t dvp = NULLVP;
1087 vnode_t sdvp = NULLVP;
1088 struct componentname cn;
1089 struct vnode_attr va;
b0d623f7 1090 char tmpname[80];
2d21ac55
A
1091 uint32_t tmp_fsid;
1092 int error;
39236c6e 1093 vfs_context_t kernelctx = vfs_context_kernel();
6d2010ae
A
1094
1095 bzero(tmpname, sizeof(tmpname));
316670eb 1096 MAKE_SHADOW_DIRNAME(rootvnode, tmpname);
6d2010ae
A
1097 /*
1098 * Look up the shadow directory to ensure that it still exists.
1099 * By looking it up, we get an iocounted dvp to use, and avoid some coherency issues
1100 * in caching it when multiple threads may be trying to manipulate the pointers.
39236c6e
A
1101 *
1102 * Make sure to use the kernel context. We want a singular view of
1103 * the shadow dir regardless of chrooted processes.
6d2010ae 1104 */
39236c6e 1105 error = vnode_lookup(tmpname, 0, &sdvp, kernelctx);
6d2010ae
A
1106 if (error == 0) {
1107 /*
1108 * If we get here, then we have successfully looked up the shadow dir,
1109 * and it has an iocount from the lookup. Return the vp in the output argument.
1110 */
1111 *sdvpp = sdvp;
1112 return (0);
2d21ac55 1113 }
6d2010ae
A
1114 /* In the failure case, no iocount is acquired */
1115 sdvp = NULLVP;
1116 bzero (tmpname, sizeof(tmpname));
2d21ac55 1117
316670eb 1118 /*
39236c6e
A
1119 * Obtain the vnode for "/var/run" directory using the kernel
1120 * context.
1121 *
316670eb
A
1122 * This is defined in the SHADOW_DIR_CONTAINER macro
1123 */
39236c6e 1124 if (vnode_lookup(SHADOW_DIR_CONTAINER, 0, &dvp, kernelctx) != 0) {
2d21ac55
A
1125 error = ENOTSUP;
1126 goto out;
1127 }
1128
316670eb
A
1129 /*
1130 * Create the shadow stream directory.
1131 * 'dvp' below suggests the parent directory so
1132 * we only need to provide the leaf entry name
1133 */
1134 MAKE_SHADOW_DIR_LEAF(rootvnode, tmpname);
2d21ac55
A
1135 bzero(&cn, sizeof(cn));
1136 cn.cn_nameiop = LOOKUP;
1137 cn.cn_flags = ISLASTCN;
39236c6e 1138 cn.cn_context = kernelctx;
2d21ac55
A
1139 cn.cn_pnbuf = tmpname;
1140 cn.cn_pnlen = sizeof(tmpname);
1141 cn.cn_nameptr = cn.cn_pnbuf;
1142 cn.cn_namelen = strlen(tmpname);
1143
1144 /*
1145 * owned by root, only readable by root, hidden
1146 */
1147 VATTR_INIT(&va);
1148 VATTR_SET(&va, va_uid, 0);
1149 VATTR_SET(&va, va_gid, 0);
1150 VATTR_SET(&va, va_mode, S_IRUSR | S_IXUSR);
1151 VATTR_SET(&va, va_type, VDIR);
1152 VATTR_SET(&va, va_flags, UF_HIDDEN);
1153 va.va_vaflags = VA_EXCLUSIVE;
1154
39236c6e 1155 error = VNOP_MKDIR(dvp, &sdvp, &cn, &va, kernelctx);
2d21ac55
A
1156
1157 /*
1158 * There can be only one winner for an exclusive create.
1159 */
6d2010ae 1160 if (error == EEXIST) {
2d21ac55 1161 /* loser has to look up directory */
39236c6e 1162 error = VNOP_LOOKUP(dvp, &sdvp, &cn, kernelctx);
2d21ac55
A
1163 if (error == 0) {
1164 /* Make sure its in fact a directory */
1165 if (sdvp->v_type != VDIR) {
1166 goto baddir;
1167 }
39236c6e 1168 /* Obtain the fsid for /var/run directory */
2d21ac55
A
1169 VATTR_INIT(&va);
1170 VATTR_WANTED(&va, va_fsid);
39236c6e 1171 if (VNOP_GETATTR(dvp, &va, kernelctx) != 0 ||
2d21ac55
A
1172 !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1173 goto baddir;
1174 }
1175 tmp_fsid = va.va_fsid;
1176
1177 VATTR_INIT(&va);
1178 VATTR_WANTED(&va, va_uid);
1179 VATTR_WANTED(&va, va_gid);
1180 VATTR_WANTED(&va, va_mode);
1181 VATTR_WANTED(&va, va_fsid);
1182 VATTR_WANTED(&va, va_dirlinkcount);
1183 VATTR_WANTED(&va, va_acl);
1184 /* Provide defaults for attrs that may not be supported */
1185 va.va_dirlinkcount = 1;
1186 va.va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
1187
39236c6e 1188 if (VNOP_GETATTR(sdvp, &va, kernelctx) != 0 ||
2d21ac55
A
1189 !VATTR_IS_SUPPORTED(&va, va_uid) ||
1190 !VATTR_IS_SUPPORTED(&va, va_gid) ||
1191 !VATTR_IS_SUPPORTED(&va, va_mode) ||
1192 !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1193 goto baddir;
1194 }
1195 /*
1196 * Make sure its what we want:
1197 * - owned by root
1198 * - not writable by anyone
39236c6e 1199 * - on same file system as /var/run
2d21ac55
A
1200 * - not a hard-linked directory
1201 * - no ACLs (they might grant write access)
1202 */
1203 if ((va.va_uid != 0) || (va.va_gid != 0) ||
1204 (va.va_mode & (S_IWUSR | S_IRWXG | S_IRWXO)) ||
1205 (va.va_fsid != tmp_fsid) ||
1206 (va.va_dirlinkcount != 1) ||
1207 (va.va_acl != (kauth_acl_t) KAUTH_FILESEC_NONE)) {
1208 goto baddir;
1209 }
1210 }
1211 }
1212out:
1213 if (dvp) {
1214 vnode_put(dvp);
1215 }
1216 if (error) {
1217 /* On errors, clean up shadow stream directory. */
1218 if (sdvp) {
1219 vnode_put(sdvp);
1220 sdvp = NULLVP;
1221 }
1222 }
1223 *sdvpp = sdvp;
1224 return (error);
1225
1226baddir:
1227 /* This is not the dir we're looking for, move along */
1228 ++shadow_sequence; /* try something else next time */
1229 error = ENOTDIR;
1230 goto out;
1231}
39236c6e 1232#endif /* NAMEDSTREAMS */
2d21ac55
A
1233
1234
39236c6e 1235#if CONFIG_APPLEDOUBLE
91447636
A
1236/*
1237 * Default Implementation (Non-native EA)
1238 */
1239
1240
1241/*
1242 Typical "._" AppleDouble Header File layout:
1243 ------------------------------------------------------------
1244 MAGIC 0x00051607
1245 VERSION 0x00020000
1246 FILLER 0
1247 COUNT 2
1248 .-- AD ENTRY[0] Finder Info Entry (must be first)
1249 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
1250 | '-> FINDER INFO
1251 | ///////////// Fixed Size Data (32 bytes)
1252 | EXT ATTR HDR
1253 | /////////////
1254 | ATTR ENTRY[0] --.
1255 | ATTR ENTRY[1] --+--.
1256 | ATTR ENTRY[2] --+--+--.
1257 | ... | | |
1258 | ATTR ENTRY[N] --+--+--+--.
1259 | ATTR DATA 0 <-' | | |
1260 | //////////// | | |
1261 | ATTR DATA 1 <----' | |
1262 | ///////////// | |
1263 | ATTR DATA 2 <-------' |
1264 | ///////////// |
1265 | ... |
1266 | ATTR DATA N <----------'
1267 | /////////////
1268 | Attribute Free Space
1269 |
1270 '----> RESOURCE FORK
1271 ///////////// Variable Sized Data
1272 /////////////
1273 /////////////
1274 /////////////
1275 /////////////
1276 /////////////
1277 ...
1278 /////////////
1279
1280 ------------------------------------------------------------
1281
1282 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1283 stored as part of the Finder Info. The length in the Finder
1284 Info AppleDouble entry includes the length of the extended
1285 attribute header, attribute entries, and attribute data.
1286*/
1287
1288
1289/*
1290 * On Disk Data Structures
1291 *
1292 * Note: Motorola 68K alignment and big-endian.
1293 *
1294 * See RFC 1740 for additional information about the AppleDouble file format.
1295 *
1296 */
1297
1298#define ADH_MAGIC 0x00051607
1299#define ADH_VERSION 0x00020000
1300#define ADH_MACOSX "Mac OS X "
1301
1302/*
1303 * AppleDouble Entry ID's
1304 */
1305#define AD_DATA 1 /* Data fork */
1306#define AD_RESOURCE 2 /* Resource fork */
1307