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