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