]> git.saurik.com Git - apple/xnu.git/blame - bsd/vfs/vfs_xattr.c
xnu-3789.60.24.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 }
6601e61a
A
379 namelen = strnlen(name, XATTR_MAXNAMELEN);
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
410 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
411 error = VNOP_GETNAMEDSTREAM(vp, svpp, name, op, flags, context);
412 else
413 error = default_getnamedstream(vp, svpp, name, op, context);
414
415 if (error == 0) {
c910b4d9 416 uint32_t streamflags = VISNAMEDSTREAM;
2d21ac55 417 vnode_t svp = *svpp;
c910b4d9 418
b0d623f7 419 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
c910b4d9 420 streamflags |= VISSHADOW;
b0d623f7
A
421 }
422
2d21ac55 423 /* Tag the vnode. */
c910b4d9
A
424 vnode_lock_spin(svp);
425 svp->v_flag |= streamflags;
2d21ac55 426 vnode_unlock(svp);
b0d623f7
A
427
428 /* Tag the parent so we know to flush credentials for streams on setattr */
429 vnode_lock_spin(vp);
430 vp->v_lflag |= VL_HASSTREAMS;
431 vnode_unlock(vp);
432
433 /* Make the file it's parent.
434 * Note: This parent link helps us distinguish vnodes for
435 * shadow stream files from vnodes for resource fork on file
436 * systems that support namedstream natively (both have
437 * VISNAMEDSTREAM set) by allowing access to mount structure
438 * for checking MNTK_NAMED_STREAMS bit at many places in the
439 * code.
cf7d32b8 440 */
2d21ac55
A
441 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
442 }
443
444 return (error);
445}
446
447/*
448 * Make a named stream for vnode vp.
449 */
450errno_t
451vnode_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t context)
452{
453 int error;
454
455 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
456 error = VNOP_MAKENAMEDSTREAM(vp, svpp, name, flags, context);
457 else
458 error = default_makenamedstream(vp, svpp, name, context);
459
460 if (error == 0) {
c910b4d9 461 uint32_t streamflags = VISNAMEDSTREAM;
2d21ac55
A
462 vnode_t svp = *svpp;
463
464 /* Tag the vnode. */
c910b4d9
A
465 if ((vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0) {
466 streamflags |= VISSHADOW;
467 }
b0d623f7 468
c910b4d9
A
469 /* Tag the vnode. */
470 vnode_lock_spin(svp);
471 svp->v_flag |= streamflags;
472 vnode_unlock(svp);
473
b0d623f7
A
474 /* Tag the parent so we know to flush credentials for streams on setattr */
475 vnode_lock_spin(vp);
476 vp->v_lflag |= VL_HASSTREAMS;
477 vnode_unlock(vp);
478
479 /* Make the file it's parent.
480 * Note: This parent link helps us distinguish vnodes for
481 * shadow stream files from vnodes for resource fork on file
482 * systems that support namedstream natively (both have
483 * VISNAMEDSTREAM set) by allowing access to mount structure
484 * for checking MNTK_NAMED_STREAMS bit at many places in the
485 * code.
cf7d32b8 486 */
2d21ac55
A
487 vnode_update_identity(svp, vp, NULL, 0, 0, VNODE_UPDATE_PARENT);
488 }
489 return (error);
490}
491
492/*
493 * Remove a named stream from vnode vp.
494 */
495errno_t
496vnode_removenamedstream(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t context)
497{
498 int error;
499
500 if (vp->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS)
501 error = VNOP_REMOVENAMEDSTREAM(vp, svp, name, flags, context);
502 else
503 error = default_removenamedstream(vp, name, context);
504
505 return (error);
506}
507
508#define NS_IOBUFSIZE (128 * 1024)
509
510/*
511 * Release a named stream shadow file.
cf7d32b8
A
512 *
513 * Note: This function is called from two places where we do not need
514 * to check if the vnode has any references held before deleting the
515 * shadow file. Once from vclean() when the vnode is being reclaimed
516 * and we do not hold any references on the vnode. Second time from
517 * default_getnamedstream() when we get an error during shadow stream
518 * file initialization so that other processes who are waiting for the
519 * shadow stream file initialization by the creator will get opportunity
520 * to create and initialize the file again.
2d21ac55
A
521 */
522errno_t
39236c6e 523vnode_relenamedstream(vnode_t vp, vnode_t svp) {
2d21ac55
A
524 vnode_t dvp;
525 struct componentname cn;
b0d623f7 526 char tmpname[80];
2d21ac55 527 errno_t err;
39236c6e
A
528
529 /*
530 * We need to use the kernel context here. If we used the supplied
531 * VFS context we have no clue whether or not it originated from userland
532 * where it could be subject to a chroot jail. We need to ensure that all
533 * filesystem access to shadow files is done on the same FS regardless of
534 * userland process restrictions.
535 */
536 vfs_context_t kernelctx = vfs_context_kernel();
2d21ac55 537
2d21ac55
A
538 cache_purge(svp);
539
540 vnode_lock(svp);
541 MAKE_SHADOW_NAME(vp, tmpname);
542 vnode_unlock(svp);
543
544 cn.cn_nameiop = DELETE;
545 cn.cn_flags = ISLASTCN;
39236c6e 546 cn.cn_context = kernelctx;
2d21ac55
A
547 cn.cn_pnbuf = tmpname;
548 cn.cn_pnlen = sizeof(tmpname);
549 cn.cn_nameptr = cn.cn_pnbuf;
550 cn.cn_namelen = strlen(tmpname);
551
39236c6e
A
552 /*
553 * Obtain the vnode for the shadow files directory. Make sure to
554 * use the kernel ctx as described above.
555 */
556 err = get_shadow_dir(&dvp);
2d21ac55
A
557 if (err != 0) {
558 return err;
559 }
b0d623f7 560
39236c6e 561 (void) VNOP_REMOVE(dvp, svp, &cn, 0, kernelctx);
2d21ac55
A
562 vnode_put(dvp);
563
564 return (0);
565}
566
567/*
568 * Flush a named stream shadow file.
39236c6e
A
569 *
570 * 'vp' represents the AppleDouble file.
571 * 'svp' represents the shadow file.
2d21ac55
A
572 */
573errno_t
574vnode_flushnamedstream(vnode_t vp, vnode_t svp, vfs_context_t context)
575{
576 struct vnode_attr va;
577 uio_t auio = NULL;
578 caddr_t bufptr = NULL;
579 size_t bufsize = 0;
580 size_t offset;
581 size_t iosize;
582 size_t datasize;
583 int error;
39236c6e
A
584 /*
585 * The kernel context must be used for all I/O to the shadow file
586 * and its namespace operations
587 */
588 vfs_context_t kernelctx = vfs_context_kernel();
589
590 /* The supplied context is used for access to the AD file itself */
2d21ac55
A
591
592 VATTR_INIT(&va);
593 VATTR_WANTED(&va, va_data_size);
594 if (VNOP_GETATTR(svp, &va, context) != 0 ||
595 !VATTR_IS_SUPPORTED(&va, va_data_size)) {
596 return (0);
597 }
598 datasize = va.va_data_size;
6d2010ae 599 if (datasize == 0) {
2d21ac55
A
600 (void) default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
601 return (0);
602 }
603
604 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
3e170ce0 605 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize, VM_KERN_MEMORY_FILE)) {
2d21ac55
A
606 return (ENOMEM);
607 }
b0d623f7 608 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
609 offset = 0;
610
611 /*
612 * Copy the shadow stream file data into the resource fork.
613 */
39236c6e 614 error = VNOP_OPEN(svp, 0, kernelctx);
2d21ac55
A
615 if (error) {
616 printf("vnode_flushnamedstream: err %d opening file\n", error);
617 goto out;
618 }
619 while (offset < datasize) {
620 iosize = MIN(datasize - offset, iosize);
621
b0d623f7 622 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
2d21ac55 623 uio_addiov(auio, (uintptr_t)bufptr, iosize);
39236c6e 624 error = VNOP_READ(svp, auio, 0, kernelctx);
2d21ac55
A
625 if (error) {
626 break;
627 }
628 /* Since there's no truncate xattr we must remove the resource fork. */
629 if (offset == 0) {
630 error = default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
631 if ((error != 0) && (error != ENOATTR)) {
632 break;
633 }
634 }
b0d623f7 635 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
2d21ac55
A
636 uio_addiov(auio, (uintptr_t)bufptr, iosize);
637 error = vn_setxattr(vp, XATTR_RESOURCEFORK_NAME, auio, XATTR_NOSECURITY, context);
638 if (error) {
639 break;
640 }
641 offset += iosize;
642 }
39236c6e
A
643
644 /* close shadowfile */
645 (void) VNOP_CLOSE(svp, 0, kernelctx);
2d21ac55
A
646out:
647 if (bufptr) {
648 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
649 }
650 if (auio) {
651 uio_free(auio);
652 }
653 return (error);
654}
655
39236c6e 656
4b17d6b6
A
657/*
658 * Verify that the vnode 'vp' is a vnode that lives in the shadow
659 * directory. We can't just query the parent pointer directly since
660 * the shadowfile is hooked up to the actual file it's a stream for.
661 */
39236c6e 662errno_t vnode_verifynamedstream(vnode_t vp) {
4b17d6b6
A
663 int error;
664 struct vnode *shadow_dvp = NULL;
665 struct vnode *shadowfile = NULL;
666 struct componentname cn;
39236c6e
A
667
668 /*
669 * We need to use the kernel context here. If we used the supplied
670 * VFS context we have no clue whether or not it originated from userland
671 * where it could be subject to a chroot jail. We need to ensure that all
672 * filesystem access to shadow files is done on the same FS regardless of
673 * userland process restrictions.
674 */
675 vfs_context_t kernelctx = vfs_context_kernel();
4b17d6b6 676 char tmpname[80];
39236c6e 677
4b17d6b6
A
678
679 /* Get the shadow directory vnode */
39236c6e 680 error = get_shadow_dir(&shadow_dvp);
4b17d6b6
A
681 if (error) {
682 return error;
683 }
684
685 /* Re-generate the shadow name in the buffer */
686 MAKE_SHADOW_NAME (vp, tmpname);
687
688 /* Look up item in shadow dir */
689 bzero(&cn, sizeof(cn));
690 cn.cn_nameiop = LOOKUP;
691 cn.cn_flags = ISLASTCN | CN_ALLOWRSRCFORK;
39236c6e 692 cn.cn_context = kernelctx;
4b17d6b6
A
693 cn.cn_pnbuf = tmpname;
694 cn.cn_pnlen = sizeof(tmpname);
695 cn.cn_nameptr = cn.cn_pnbuf;
696 cn.cn_namelen = strlen(tmpname);
697
39236c6e 698 if (VNOP_LOOKUP (shadow_dvp, &shadowfile, &cn, kernelctx) == 0) {
4b17d6b6
A
699 /* is the pointer the same? */
700 if (shadowfile == vp) {
701 error = 0;
702 }
703 else {
704 error = EPERM;
705 }
706 /* drop the iocount acquired */
707 vnode_put (shadowfile);
708 }
709
710 /* Drop iocount on shadow dir */
711 vnode_put (shadow_dvp);
712 return error;
713}
2d21ac55 714
39236c6e
A
715/*
716 * Access or create the shadow file as needed.
717 *
718 * 'makestream' with non-zero value means that we need to guarantee we were the
719 * creator of the shadow file.
720 *
721 * 'context' is the user supplied context for the original VFS operation that
722 * caused us to need a shadow file.
723 *
724 * int pointed to by 'creator' is nonzero if we created the shadowfile.
725 */
2d21ac55
A
726static int
727getshadowfile(vnode_t vp, vnode_t *svpp, int makestream, size_t *rsrcsize,
728 int *creator, vfs_context_t context)
729{
730 vnode_t dvp = NULLVP;
731 vnode_t svp = NULLVP;
732 struct componentname cn;
733 struct vnode_attr va;
b0d623f7 734 char tmpname[80];
2d21ac55
A
735 size_t datasize = 0;
736 int error = 0;
6d2010ae 737 int retries = 0;
39236c6e 738 vfs_context_t kernelctx = vfs_context_kernel();
2d21ac55 739
6d2010ae 740retry_create:
2d21ac55 741 *creator = 0;
2d21ac55
A
742 /* Establish a unique file name. */
743 MAKE_SHADOW_NAME(vp, tmpname);
744 bzero(&cn, sizeof(cn));
745 cn.cn_nameiop = LOOKUP;
746 cn.cn_flags = ISLASTCN;
747 cn.cn_context = context;
748 cn.cn_pnbuf = tmpname;
749 cn.cn_pnlen = sizeof(tmpname);
750 cn.cn_nameptr = cn.cn_pnbuf;
751 cn.cn_namelen = strlen(tmpname);
752
753 /* Pick up uid, gid, mode and date from original file. */
754 VATTR_INIT(&va);
755 VATTR_WANTED(&va, va_uid);
756 VATTR_WANTED(&va, va_gid);
757 VATTR_WANTED(&va, va_mode);
758 VATTR_WANTED(&va, va_create_time);
759 VATTR_WANTED(&va, va_modify_time);
760 if (VNOP_GETATTR(vp, &va, context) != 0 ||
761 !VATTR_IS_SUPPORTED(&va, va_uid) ||
762 !VATTR_IS_SUPPORTED(&va, va_gid) ||
763 !VATTR_IS_SUPPORTED(&va, va_mode)) {
764 va.va_uid = KAUTH_UID_NONE;
765 va.va_gid = KAUTH_GID_NONE;
766 va.va_mode = S_IRUSR | S_IWUSR;
767 }
768 va.va_vaflags = VA_EXCLUSIVE;
769 VATTR_SET(&va, va_type, VREG);
770 /* We no longer change the access, but we still hide it. */
771 VATTR_SET(&va, va_flags, UF_HIDDEN);
772
773 /* Obtain the vnode for the shadow files directory. */
39236c6e 774 if (get_shadow_dir(&dvp) != 0) {
2d21ac55
A
775 error = ENOTDIR;
776 goto out;
777 }
778 if (!makestream) {
779 /* See if someone else already has it open. */
39236c6e 780 if (VNOP_LOOKUP(dvp, &svp, &cn, kernelctx) == 0) {
2d21ac55
A
781 /* Double check existence by asking for size. */
782 VATTR_INIT(&va);
783 VATTR_WANTED(&va, va_data_size);
784 if (VNOP_GETATTR(svp, &va, context) == 0 &&
785 VATTR_IS_SUPPORTED(&va, va_data_size)) {
786 goto out; /* OK to use. */
787 }
788 }
789
39236c6e
A
790 /*
791 * Otherwise make sure the resource fork data exists.
792 * Use the supplied context for accessing the AD file.
793 */
2d21ac55
A
794 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, NULL, &datasize,
795 XATTR_NOSECURITY, context);
796 /*
797 * To maintain binary compatibility with legacy Carbon
798 * emulated resource fork support, if the resource fork
799 * doesn't exist but the Finder Info does, then act as
800 * if an empty resource fork is present (see 4724359).
801 */
802 if ((error == ENOATTR) &&
803 (vn_getxattr(vp, XATTR_FINDERINFO_NAME, NULL, &datasize,
804 XATTR_NOSECURITY, context) == 0)) {
805 datasize = 0;
806 error = 0;
807 } else {
808 if (error) {
809 goto out;
810 }
811
812 /* If the resource fork exists, its size is expected to be non-zero. */
813 if (datasize == 0) {
814 error = ENOATTR;
815 goto out;
816 }
817 }
818 }
819 /* Create the shadow stream file. */
39236c6e 820 error = VNOP_CREATE(dvp, &svp, &cn, &va, kernelctx);
2d21ac55 821 if (error == 0) {
7e4a7d39 822 vnode_recycle(svp);
2d21ac55 823 *creator = 1;
6d2010ae
A
824 }
825 else if ((error == EEXIST) && !makestream) {
39236c6e 826 error = VNOP_LOOKUP(dvp, &svp, &cn, kernelctx);
2d21ac55 827 }
6d2010ae
A
828 else if ((error == ENOENT) && !makestream) {
829 /*
830 * We could have raced with a rmdir on the shadow directory
831 * post-lookup. Retry from the beginning, 1x only, to
832 * try and see if we need to re-create the shadow directory
833 * in get_shadow_dir.
834 */
835 if (retries == 0) {
836 retries++;
837 if (dvp) {
838 vnode_put (dvp);
839 dvp = NULLVP;
840 }
841 if (svp) {
842 vnode_put (svp);
843 svp = NULLVP;
844 }
845 goto retry_create;
846 }
847 /* Otherwise, just error out normally below */
848 }
849
2d21ac55
A
850out:
851 if (dvp) {
852 vnode_put(dvp);
853 }
854 if (error) {
855 /* On errors, clean up shadow stream file. */
856 if (svp) {
857 vnode_put(svp);
858 svp = NULLVP;
859 }
860 }
861 *svpp = svp;
862 if (rsrcsize) {
863 *rsrcsize = datasize;
864 }
865 return (error);
866}
867
868
869static int
870default_getnamedstream(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation op, vfs_context_t context)
871{
872 vnode_t svp = NULLVP;
873 uio_t auio = NULL;
874 caddr_t bufptr = NULL;
875 size_t bufsize = 0;
876 size_t datasize = 0;
877 int creator;
878 int error;
879
39236c6e
A
880 /* need the kernel context for accessing the shadowfile */
881 vfs_context_t kernelctx = vfs_context_kernel();
882
2d21ac55
A
883 /*
884 * Only the "com.apple.ResourceFork" stream is supported here.
885 */
886 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
887 *svpp = NULLVP;
888 return (ENOATTR);
889 }
890retry:
891 /*
892 * Obtain a shadow file for the resource fork I/O.
39236c6e
A
893 *
894 * Need to pass along the supplied context so that getshadowfile
895 * can access the AD file as needed, using it.
2d21ac55
A
896 */
897 error = getshadowfile(vp, &svp, 0, &datasize, &creator, context);
898 if (error) {
899 *svpp = NULLVP;
900 return (error);
901 }
902
903 /*
904 * The creator of the shadow file provides its file data,
b0d623f7
A
905 * all other threads should wait until its ready. In order to
906 * prevent a deadlock during error codepaths, we need to check if the
907 * vnode is being created, or if it has failed out. Regardless of success or
908 * failure, we set the VISSHADOW bit on the vnode, so we check that
909 * if the vnode's flags don't have VISNAMEDSTREAM set. If it doesn't,
910 * then we can infer the creator isn't done yet. If it's there, but
911 * VISNAMEDSTREAM is not set, then we can infer it errored out and we should
912 * try again.
2d21ac55
A
913 */
914 if (!creator) {
915 vnode_lock(svp);
916 if (svp->v_flag & VISNAMEDSTREAM) {
917 /* data is ready, go use it */
918 vnode_unlock(svp);
919 goto out;
920 } else {
b0d623f7
A
921 /* It's not ready, wait for it (sleep using v_parent as channel) */
922 if ((svp->v_flag & VISSHADOW)) {
923 /*
924 * No VISNAMEDSTREAM, but we did see VISSHADOW, indicating that the other
925 * thread is done with this vnode. Just unlock the vnode and try again
926 */
927 vnode_unlock(svp);
928 }
929 else {
930 /* Otherwise, sleep if the shadow file is not created yet */
931 msleep((caddr_t)&svp->v_parent, &svp->v_lock, PINOD | PDROP,
932 "getnamedstream", NULL);
933 }
2d21ac55
A
934 vnode_put(svp);
935 svp = NULLVP;
936 goto retry;
937 }
938 }
939
940 /*
941 * Copy the real resource fork data into shadow stream file.
942 */
943 if (op == NS_OPEN && datasize != 0) {
944 size_t offset;
945 size_t iosize;
946
947 iosize = bufsize = MIN(datasize, NS_IOBUFSIZE);
3e170ce0 948 if (kmem_alloc(kernel_map, (vm_offset_t *)&bufptr, bufsize, VM_KERN_MEMORY_FILE)) {
2d21ac55
A
949 error = ENOMEM;
950 goto out;
951 }
952
b0d623f7 953 auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
2d21ac55
A
954 offset = 0;
955
39236c6e
A
956 /* open the shadow file */
957 error = VNOP_OPEN(svp, 0, kernelctx);
2d21ac55
A
958 if (error) {
959 goto out;
960 }
961 while (offset < datasize) {
962 size_t tmpsize;
963
964 iosize = MIN(datasize - offset, iosize);
965
b0d623f7 966 uio_reset(auio, offset, UIO_SYSSPACE, UIO_READ);
2d21ac55 967 uio_addiov(auio, (uintptr_t)bufptr, iosize);
39236c6e 968 /* use supplied ctx for AD file */
2d21ac55
A
969 error = vn_getxattr(vp, XATTR_RESOURCEFORK_NAME, auio, &tmpsize,
970 XATTR_NOSECURITY, context);
971 if (error) {
972 break;
973 }
974
b0d623f7 975 uio_reset(auio, offset, UIO_SYSSPACE, UIO_WRITE);
2d21ac55 976 uio_addiov(auio, (uintptr_t)bufptr, iosize);
39236c6e
A
977 /* kernel context for writing shadowfile */
978 error = VNOP_WRITE(svp, auio, 0, kernelctx);
2d21ac55
A
979 if (error) {
980 break;
981 }
982 offset += iosize;
983 }
39236c6e
A
984
985 /* close shadow file */
986 (void) VNOP_CLOSE(svp, 0, kernelctx);
2d21ac55
A
987 }
988out:
989 /* Wake up anyone waiting for svp file content */
990 if (creator) {
991 if (error == 0) {
992 vnode_lock(svp);
b0d623f7
A
993 /* VISSHADOW would be set later on anyway, so we set it now */
994 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
2d21ac55
A
995 wakeup((caddr_t)&svp->v_parent);
996 vnode_unlock(svp);
997 } else {
b0d623f7
A
998 /* On post create errors, get rid of the shadow file. This
999 * way if there is another process waiting for initialization
1000 * of the shadowfile by the current process will wake up and
1001 * retry by creating and initializing the shadow file again.
1002 * Also add the VISSHADOW bit here to indicate we're done operating
1003 * on this vnode.
cf7d32b8 1004 */
39236c6e 1005 (void)vnode_relenamedstream(vp, svp);
b0d623f7
A
1006 vnode_lock (svp);
1007 svp->v_flag |= VISSHADOW;
2d21ac55 1008 wakeup((caddr_t)&svp->v_parent);
b0d623f7 1009 vnode_unlock(svp);
2d21ac55
A
1010 }
1011 }
1012
1013 if (bufptr) {
1014 kmem_free(kernel_map, (vm_offset_t)bufptr, bufsize);
1015 }
1016 if (auio) {
1017 uio_free(auio);
1018 }
1019 if (error) {
1020 /* On errors, clean up shadow stream file. */
1021 if (svp) {
1022 vnode_put(svp);
1023 svp = NULLVP;
1024 }
1025 }
1026 *svpp = svp;
1027 return (error);
1028}
1029
1030static int
1031default_makenamedstream(vnode_t vp, vnode_t *svpp, const char *name, vfs_context_t context)
1032{
1033 int creator;
1034 int error;
1035
1036 /*
1037 * Only the "com.apple.ResourceFork" stream is supported here.
1038 */
1039 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
1040 *svpp = NULLVP;
1041 return (ENOATTR);
1042 }
39236c6e
A
1043
1044 /* Supply the context to getshadowfile so it can manipulate the AD file */
2d21ac55
A
1045 error = getshadowfile(vp, svpp, 1, NULL, &creator, context);
1046
1047 /*
1048 * Wake up any waiters over in default_getnamedstream().
1049 */
1050 if ((error == 0) && (*svpp != NULL) && creator) {
1051 vnode_t svp = *svpp;
1052
1053 vnode_lock(svp);
b0d623f7
A
1054 /* If we're the creator, mark it as a named stream */
1055 svp->v_flag |= (VISNAMEDSTREAM | VISSHADOW);
2d21ac55
A
1056 /* Wakeup any waiters on the v_parent channel */
1057 wakeup((caddr_t)&svp->v_parent);
1058 vnode_unlock(svp);
b0d623f7 1059
2d21ac55 1060 }
b0d623f7 1061
2d21ac55
A
1062 return (error);
1063}
1064
1065static int
1066default_removenamedstream(vnode_t vp, const char *name, vfs_context_t context)
1067{
1068 /*
1069 * Only the "com.apple.ResourceFork" stream is supported here.
1070 */
1071 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
1072 return (ENOATTR);
1073 }
1074 /*
1075 * XXX - what about other opened instances?
1076 */
1077 return default_removexattr(vp, XATTR_RESOURCEFORK_NAME, 0, context);
1078}
1079
1080static int
39236c6e 1081get_shadow_dir(vnode_t *sdvpp) {
2d21ac55
A
1082 vnode_t dvp = NULLVP;
1083 vnode_t sdvp = NULLVP;
1084 struct componentname cn;
1085 struct vnode_attr va;
b0d623f7 1086 char tmpname[80];
2d21ac55
A
1087 uint32_t tmp_fsid;
1088 int error;
39236c6e 1089 vfs_context_t kernelctx = vfs_context_kernel();
6d2010ae
A
1090
1091 bzero(tmpname, sizeof(tmpname));
316670eb 1092 MAKE_SHADOW_DIRNAME(rootvnode, tmpname);
6d2010ae
A
1093 /*
1094 * Look up the shadow directory to ensure that it still exists.
1095 * By looking it up, we get an iocounted dvp to use, and avoid some coherency issues
1096 * in caching it when multiple threads may be trying to manipulate the pointers.
39236c6e
A
1097 *
1098 * Make sure to use the kernel context. We want a singular view of
1099 * the shadow dir regardless of chrooted processes.
6d2010ae 1100 */
39236c6e 1101 error = vnode_lookup(tmpname, 0, &sdvp, kernelctx);
6d2010ae
A
1102 if (error == 0) {
1103 /*
1104 * If we get here, then we have successfully looked up the shadow dir,
1105 * and it has an iocount from the lookup. Return the vp in the output argument.
1106 */
1107 *sdvpp = sdvp;
1108 return (0);
2d21ac55 1109 }
6d2010ae
A
1110 /* In the failure case, no iocount is acquired */
1111 sdvp = NULLVP;
1112 bzero (tmpname, sizeof(tmpname));
2d21ac55 1113
316670eb 1114 /*
39236c6e
A
1115 * Obtain the vnode for "/var/run" directory using the kernel
1116 * context.
1117 *
316670eb
A
1118 * This is defined in the SHADOW_DIR_CONTAINER macro
1119 */
39236c6e 1120 if (vnode_lookup(SHADOW_DIR_CONTAINER, 0, &dvp, kernelctx) != 0) {
2d21ac55
A
1121 error = ENOTSUP;
1122 goto out;
1123 }
1124
316670eb
A
1125 /*
1126 * Create the shadow stream directory.
1127 * 'dvp' below suggests the parent directory so
1128 * we only need to provide the leaf entry name
1129 */
1130 MAKE_SHADOW_DIR_LEAF(rootvnode, tmpname);
2d21ac55
A
1131 bzero(&cn, sizeof(cn));
1132 cn.cn_nameiop = LOOKUP;
1133 cn.cn_flags = ISLASTCN;
39236c6e 1134 cn.cn_context = kernelctx;
2d21ac55
A
1135 cn.cn_pnbuf = tmpname;
1136 cn.cn_pnlen = sizeof(tmpname);
1137 cn.cn_nameptr = cn.cn_pnbuf;
1138 cn.cn_namelen = strlen(tmpname);
1139
1140 /*
1141 * owned by root, only readable by root, hidden
1142 */
1143 VATTR_INIT(&va);
1144 VATTR_SET(&va, va_uid, 0);
1145 VATTR_SET(&va, va_gid, 0);
1146 VATTR_SET(&va, va_mode, S_IRUSR | S_IXUSR);
1147 VATTR_SET(&va, va_type, VDIR);
1148 VATTR_SET(&va, va_flags, UF_HIDDEN);
1149 va.va_vaflags = VA_EXCLUSIVE;
1150
39236c6e 1151 error = VNOP_MKDIR(dvp, &sdvp, &cn, &va, kernelctx);
2d21ac55
A
1152
1153 /*
1154 * There can be only one winner for an exclusive create.
1155 */
6d2010ae 1156 if (error == EEXIST) {
2d21ac55 1157 /* loser has to look up directory */
39236c6e 1158 error = VNOP_LOOKUP(dvp, &sdvp, &cn, kernelctx);
2d21ac55
A
1159 if (error == 0) {
1160 /* Make sure its in fact a directory */
1161 if (sdvp->v_type != VDIR) {
1162 goto baddir;
1163 }
39236c6e 1164 /* Obtain the fsid for /var/run directory */
2d21ac55
A
1165 VATTR_INIT(&va);
1166 VATTR_WANTED(&va, va_fsid);
39236c6e 1167 if (VNOP_GETATTR(dvp, &va, kernelctx) != 0 ||
2d21ac55
A
1168 !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1169 goto baddir;
1170 }
1171 tmp_fsid = va.va_fsid;
1172
1173 VATTR_INIT(&va);
1174 VATTR_WANTED(&va, va_uid);
1175 VATTR_WANTED(&va, va_gid);
1176 VATTR_WANTED(&va, va_mode);
1177 VATTR_WANTED(&va, va_fsid);
1178 VATTR_WANTED(&va, va_dirlinkcount);
1179 VATTR_WANTED(&va, va_acl);
1180 /* Provide defaults for attrs that may not be supported */
1181 va.va_dirlinkcount = 1;
1182 va.va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE;
1183
39236c6e 1184 if (VNOP_GETATTR(sdvp, &va, kernelctx) != 0 ||
2d21ac55
A
1185 !VATTR_IS_SUPPORTED(&va, va_uid) ||
1186 !VATTR_IS_SUPPORTED(&va, va_gid) ||
1187 !VATTR_IS_SUPPORTED(&va, va_mode) ||
1188 !VATTR_IS_SUPPORTED(&va, va_fsid)) {
1189 goto baddir;
1190 }
1191 /*
1192 * Make sure its what we want:
1193 * - owned by root
1194 * - not writable by anyone
39236c6e 1195 * - on same file system as /var/run
2d21ac55
A
1196 * - not a hard-linked directory
1197 * - no ACLs (they might grant write access)
1198 */
1199 if ((va.va_uid != 0) || (va.va_gid != 0) ||
1200 (va.va_mode & (S_IWUSR | S_IRWXG | S_IRWXO)) ||
1201 (va.va_fsid != tmp_fsid) ||
1202 (va.va_dirlinkcount != 1) ||
1203 (va.va_acl != (kauth_acl_t) KAUTH_FILESEC_NONE)) {
1204 goto baddir;
1205 }
1206 }
1207 }
1208out:
1209 if (dvp) {
1210 vnode_put(dvp);
1211 }
1212 if (error) {
1213 /* On errors, clean up shadow stream directory. */
1214 if (sdvp) {
1215 vnode_put(sdvp);
1216 sdvp = NULLVP;
1217 }
1218 }
1219 *sdvpp = sdvp;
1220 return (error);
1221
1222baddir:
1223 /* This is not the dir we're looking for, move along */
1224 ++shadow_sequence; /* try something else next time */
1225 error = ENOTDIR;
1226 goto out;
1227}
39236c6e 1228#endif /* NAMEDSTREAMS */
2d21ac55
A
1229
1230
39236c6e 1231#if CONFIG_APPLEDOUBLE
91447636
A
1232/*
1233 * Default Implementation (Non-native EA)
1234 */
1235
1236
1237/*
1238 Typical "._" AppleDouble Header File layout:
1239 ------------------------------------------------------------
1240 MAGIC 0x00051607
1241 VERSION 0x00020000
1242 FILLER 0
1243 COUNT 2
1244 .-- AD ENTRY[0] Finder Info Entry (must be first)
1245 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
1246 | '-> FINDER INFO
1247 | ///////////// Fixed Size Data (32 bytes)
1248 | EXT ATTR HDR
1249 | /////////////
1250 | ATTR ENTRY[0] --.
1251 | ATTR ENTRY[1] --+--.
1252 | ATTR ENTRY[2] --+--+--.
1253 | ... | | |
1254 | ATTR ENTRY[N] --+--+--+--.
1255 | ATTR DATA 0 <-' | | |
1256 | //////////// | | |
1257 | ATTR DATA 1 <----' | |
1258 | ///////////// | |
1259 | ATTR DATA 2 <-------' |
1260 | ///////////// |
1261 | ... |
1262 | ATTR DATA N <----------'
1263 | /////////////
1264 | Attribute Free Space
1265 |
1266 '----> RESOURCE FORK
1267 ///////////// Variable Sized Data
1268 /////////////
1269 /////////////
1270 /////////////
1271 /////////////
1272 /////////////
1273 ...
1274 /////////////
1275
1276 ------------------------------------------------------------
1277
1278 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1279 stored as part of the Finder Info. The length in the Finder
1280 Info AppleDouble entry includes the length of the extended
1281 attribute header, attribute entries, and attribute data.
1282*/
1283
1284
1285/*
1286 * On Disk Data Structures
1287 *
1288 * Note: Motorola 68K alignment and big-endian.
1289 *
1290 * See RFC 1740 for additional information about the AppleDouble file format.
1291 *
1292 */
1293
1294#define ADH_MAGIC 0x00051607
1295#define ADH_VERSION 0x00020000
1296#define ADH_MACOSX "Mac OS X "
1297
1298/*
1299 * AppleDouble Entry ID's
1300 */
1301#define AD_DATA 1 /* Data fork */
1302#define AD_RESOURCE 2 /* Resource fork */
1303