]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_xattr.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_xattr.c
1 /*
2 * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include <sys/param.h>
24
25 #include <sys/fcntl.h>
26 #include <sys/fsevents.h>
27 #include <sys/kernel.h>
28 #include <sys/kauth.h>
29 #include <sys/malloc.h>
30 #include <sys/namei.h>
31 #include <sys/proc_internal.h>
32 #include <sys/stat.h>
33 #include <sys/uio.h>
34 #include <sys/utfconv.h>
35 #include <sys/vnode.h>
36 #include <sys/vnode_internal.h>
37
38 #include <sys/xattr.h>
39
40 #include <libkern/OSByteOrder.h>
41 #include <vm/vm_kern.h>
42
43 /*
44 * Default xattr support routines.
45 */
46 static int default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
47 int options, vfs_context_t context);
48
49 static int default_setxattr(vnode_t vp, const char *name, uio_t uio,
50 int options, vfs_context_t context);
51
52 static int default_removexattr(vnode_t vp, const char *name, int options, vfs_context_t context);
53
54 static int default_listxattr(vnode_t vp, uio_t uio, size_t *size, int options,
55 vfs_context_t context);
56
57
58
59 /*
60 * Retrieve the data of an extended attribute.
61 */
62 int
63 vn_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
64 int options, vfs_context_t context)
65 {
66 int error;
67
68 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
69 return (EPERM);
70 }
71 if ((error = xattr_validatename(name))) {
72 return (error);
73 }
74 if (!(options & XATTR_NOSECURITY) && (error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context)))
75 goto out;
76
77 /* The offset can only be non-zero for resource forks. */
78 if (uio != NULL && uio_offset(uio) != 0 &&
79 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
80 error = EINVAL;
81 goto out;
82 }
83
84 error = VNOP_GETXATTR(vp, name, uio, size, options, context);
85 if (error == ENOTSUP) {
86 /*
87 * A filesystem may keep some EAs natively and return ENOTSUP for others.
88 * SMB returns ENOTSUP for finderinfo and resource forks.
89 */
90 error = default_getxattr(vp, name, uio, size, options, context);
91 }
92 out:
93 return (error);
94 }
95
96 /*
97 * Set the data of an extended attribute.
98 */
99 int
100 vn_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
101 {
102 int error;
103
104 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
105 return (EPERM);
106 }
107 if ((options & (XATTR_REPLACE|XATTR_CREATE)) == (XATTR_REPLACE|XATTR_CREATE)) {
108 return (EINVAL);
109 }
110 if ((error = xattr_validatename(name))) {
111 return (error);
112 }
113 if (!(options & XATTR_NOSECURITY) && (error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context)))
114 goto out;
115
116 /* The offset can only be non-zero for resource forks. */
117 if (uio_offset(uio) != 0 &&
118 bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0 ) {
119 error = EINVAL;
120 goto out;
121 }
122
123 error = VNOP_SETXATTR(vp, name, uio, options, context);
124 #ifdef DUAL_EAS
125 /*
126 * An EJUSTRETURN is from a filesystem which keeps this xattr
127 * natively as well as in a dot-underscore file. In this case the
128 * EJUSTRETURN means the filesytem has done nothing, but identifies the
129 * EA as one which may be represented natively and/or in a DU, and
130 * since XATTR_CREATE or XATTR_REPLACE was specified, only up here in
131 * in vn_setxattr can we do the getxattrs needed to ascertain whether
132 * the XATTR_{CREATE,REPLACE} should yield an error.
133 */
134 if (error == EJUSTRETURN) {
135 int native = 0, dufile = 0;
136 size_t sz; /* not used */
137
138 native = VNOP_GETXATTR(vp, name, NULL, &sz, 0, context) ? 0 : 1;
139 dufile = default_getxattr(vp, name, NULL, &sz, 0, context) ? 0 : 1;
140 if (options & XATTR_CREATE && (native || dufile)) {
141 error = EEXIST;
142 goto out;
143 }
144 if (options & XATTR_REPLACE && !(native || dufile)) {
145 error = ENOATTR;
146 goto out;
147 }
148 /*
149 * Having determined no CREATE/REPLACE error should result, we
150 * zero those bits, so both backing stores get written to.
151 */
152 options &= ~(XATTR_CREATE | XATTR_REPLACE);
153 error = VNOP_SETXATTR(vp, name, uio, options, context);
154 /* the mainline path here is to have error==ENOTSUP ... */
155 }
156 #endif /* DUAL_EAS */
157 if (error == ENOTSUP) {
158 /*
159 * A filesystem may keep some EAs natively and return ENOTSUP for others.
160 * SMB returns ENOTSUP for finderinfo and resource forks.
161 */
162 error = default_setxattr(vp, name, uio, options, context);
163 }
164 out:
165 return (error);
166 }
167
168 /*
169 * Remove an extended attribute.
170 */
171 int
172 vn_removexattr(vnode_t vp, const char * name, int options, vfs_context_t context)
173 {
174 int error;
175
176 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
177 return (EPERM);
178 }
179 if ((error = xattr_validatename(name))) {
180 return (error);
181 }
182 if (!(options & XATTR_NOSECURITY) && (error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_EXTATTRIBUTES, context)))
183 goto out;
184 error = VNOP_REMOVEXATTR(vp, name, options, context);
185 if (error == ENOTSUP) {
186 /*
187 * A filesystem may keep some EAs natively and return ENOTSUP for others.
188 * SMB returns ENOTSUP for finderinfo and resource forks.
189 */
190 error = default_removexattr(vp, name, options, context);
191 #ifdef DUAL_EAS
192 } else if (error == EJUSTRETURN) {
193 /*
194 * EJUSTRETURN is from a filesystem which keeps this xattr natively as well
195 * as in a dot-underscore file. EJUSTRETURN means the filesytem did remove
196 * a native xattr, so failure to find it in a DU file during
197 * default_removexattr should not be considered an error.
198 */
199 error = default_removexattr(vp, name, options, context);
200 if (error == ENOATTR)
201 error = 0;
202 #endif /* DUAL_EAS */
203 }
204 out:
205 return (error);
206 }
207
208 /*
209 * Retrieve the list of extended attribute names.
210 */
211 int
212 vn_listxattr(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t context)
213 {
214 int error;
215
216 if (!(vp->v_type == VREG || vp->v_type == VDIR || vp->v_type == VLNK)) {
217 return (EPERM);
218 }
219 if (!(options & XATTR_NOSECURITY) && (error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_EXTATTRIBUTES, context)))
220 goto out;
221
222 error = VNOP_LISTXATTR(vp, uio, size, options, context);
223 if (error == ENOTSUP) {
224 /*
225 * A filesystem may keep some but not all EAs natively, in which case
226 * the native EA names will have been uiomove-d out (or *size updated)
227 * and the default_listxattr here will finish the job. Note SMB takes
228 * advantage of this for its finder-info and resource forks.
229 */
230 error = default_listxattr(vp, uio, size, options, context);
231 }
232 out:
233 return (error);
234 }
235
236 int
237 xattr_validatename(const char *name)
238 {
239 int namelen;
240
241 if (name == NULL || name[0] == '\0') {
242 return (EINVAL);
243 }
244 namelen = strlen(name);
245 if (namelen > XATTR_MAXNAMELEN) {
246 return (ENAMETOOLONG);
247 }
248 if (utf8_validatestr(name, namelen) != 0) {
249 return (EINVAL);
250 }
251 return (0);
252 }
253
254
255 /*
256 * Determine whether an EA is a protected system attribute.
257 */
258 int
259 xattr_protected(const char *attrname)
260 {
261 return(!strncmp(attrname, "com.apple.system.", 17));
262 }
263
264
265 /*
266 * Default Implementation (Non-native EA)
267 */
268
269
270 /*
271 Typical "._" AppleDouble Header File layout:
272 ------------------------------------------------------------
273 MAGIC 0x00051607
274 VERSION 0x00020000
275 FILLER 0
276 COUNT 2
277 .-- AD ENTRY[0] Finder Info Entry (must be first)
278 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
279 | '-> FINDER INFO
280 | ///////////// Fixed Size Data (32 bytes)
281 | EXT ATTR HDR
282 | /////////////
283 | ATTR ENTRY[0] --.
284 | ATTR ENTRY[1] --+--.
285 | ATTR ENTRY[2] --+--+--.
286 | ... | | |
287 | ATTR ENTRY[N] --+--+--+--.
288 | ATTR DATA 0 <-' | | |
289 | //////////// | | |
290 | ATTR DATA 1 <----' | |
291 | ///////////// | |
292 | ATTR DATA 2 <-------' |
293 | ///////////// |
294 | ... |
295 | ATTR DATA N <----------'
296 | /////////////
297 | Attribute Free Space
298 |
299 '----> RESOURCE FORK
300 ///////////// Variable Sized Data
301 /////////////
302 /////////////
303 /////////////
304 /////////////
305 /////////////
306 ...
307 /////////////
308
309 ------------------------------------------------------------
310
311 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
312 stored as part of the Finder Info. The length in the Finder
313 Info AppleDouble entry includes the length of the extended
314 attribute header, attribute entries, and attribute data.
315 */
316
317
318 /*
319 * On Disk Data Structures
320 *
321 * Note: Motorola 68K alignment and big-endian.
322 *
323 * See RFC 1740 for additional information about the AppleDouble file format.
324 *
325 */
326
327 #define ADH_MAGIC 0x00051607
328 #define ADH_VERSION 0x00020000
329 #define ADH_MACOSX "Mac OS X "
330
331 /*
332 * AppleDouble Entry ID's
333 */
334 #define AD_DATA 1 /* Data fork */
335 #define AD_RESOURCE 2 /* Resource fork */
336 #define AD_REALNAME 3 /* FileÕs name on home file system */
337 #define AD_COMMENT 4 /* Standard Mac comment */
338 #define AD_ICONBW 5 /* Mac black & white icon */
339 #define AD_ICONCOLOR 6 /* Mac color icon */
340 #define AD_UNUSED 7 /* Not used */
341 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
342 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
343 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
344 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
345 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
346 #define AD_AFPNAME 13 /* Short name on AFP server */
347 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
348 #define AD_AFPDIRID 15 /* AFP directory ID */
349 #define AD_ATTRIBUTES AD_FINDERINFO
350
351
352 #define ATTR_FILE_PREFIX "._"
353 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
354
355 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
356
357 /* Implementation Limits */
358 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
359 #define ATTR_MAX_HDR_SIZE 65536
360 /*
361 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
362 * size supported (including the attribute entries). All of
363 * the attribute entries must reside within this limit. If
364 * any of the attribute data crosses the ATTR_MAX_HDR_SIZE
365 * boundry, then all of the attribute data I/O is performed
366 * seperately from the attribute header I/O.
367 */
368
369
370 #pragma options align=mac68k
371
372 #define FINDERINFOSIZE 32
373
374 typedef struct apple_double_entry {
375 u_int32_t type; /* entry type: see list, 0 invalid */
376 u_int32_t offset; /* entry data offset from the beginning of the file. */
377 u_int32_t length; /* entry data length in bytes. */
378 } apple_double_entry_t;
379
380
381 typedef struct apple_double_header {
382 u_int32_t magic; /* == ADH_MAGIC */
383 u_int32_t version; /* format version: 2 = 0x00020000 */
384 u_int32_t filler[4];
385 u_int16_t numEntries; /* number of entries which follow */
386 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */
387 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */
388 u_int8_t pad[2]; /* get better alignment inside attr_header */
389 } apple_double_header_t;
390
391 #define ADHDRSIZE (4+4+16+2)
392
393 /* Entries are aligned on 4 byte boundaries */
394 typedef struct attr_entry {
395 u_int32_t offset; /* file offset to data */
396 u_int32_t length; /* size of attribute data */
397 u_int16_t flags;
398 u_int8_t namelen;
399 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
400 } attr_entry_t;
401
402
403 /* Header + entries must fit into 64K */
404 typedef struct attr_header {
405 apple_double_header_t appledouble;
406 u_int32_t magic; /* == ATTR_HDR_MAGIC */
407 u_int32_t debug_tag; /* for debugging == file id of owning file */
408 u_int32_t total_size; /* total size of attribute header + entries + data */
409 u_int32_t data_start; /* file offset to attribute data area */
410 u_int32_t data_length; /* length of attribute data area */
411 u_int32_t reserved[3];
412 u_int16_t flags;
413 u_int16_t num_attrs;
414 } attr_header_t;
415
416
417 /* Empty Resource Fork Header */
418 typedef struct rsrcfork_header {
419 u_int32_t fh_DataOffset;
420 u_int32_t fh_MapOffset;
421 u_int32_t fh_DataLength;
422 u_int32_t fh_MapLength;
423 u_int8_t systemData[112];
424 u_int8_t appData[128];
425 u_int32_t mh_DataOffset;
426 u_int32_t mh_MapOffset;
427 u_int32_t mh_DataLength;
428 u_int32_t mh_MapLength;
429 u_int32_t mh_Next;
430 u_int16_t mh_RefNum;
431 u_int8_t mh_Attr;
432 u_int8_t mh_InMemoryAttr;
433 u_int16_t mh_Types;
434 u_int16_t mh_Names;
435 u_int16_t typeCount;
436 } rsrcfork_header_t;
437
438 #define RF_FIRST_RESOURCE 256
439 #define RF_NULL_MAP_LENGTH 30
440 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
441
442 #pragma options align=reset
443
444 /* Runtime information about the attribute file. */
445 typedef struct attr_info {
446 vfs_context_t context;
447 vnode_t filevp;
448 size_t filesize;
449 size_t iosize;
450 u_int8_t *rawdata;
451 size_t rawsize; /* raw size of AppleDouble file */
452 apple_double_header_t *filehdr;
453 apple_double_entry_t *finderinfo;
454 apple_double_entry_t *rsrcfork;
455 attr_header_t *attrhdr;
456 attr_entry_t *attr_entry;
457 u_int8_t readonly;
458 u_int8_t emptyfinderinfo;
459 } attr_info_t;
460
461
462 #define ATTR_SETTING 1
463
464 #define ATTR_ALIGN 3L /* Use four-byte alignment */
465
466 #define ATTR_ENTRY_LENGTH(namelen) \
467 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
468
469 #define ATTR_NEXT(ae) \
470 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
471
472 #define ATTR_VALID(ae, ai) \
473 ((u_int8_t *)ATTR_NEXT(ae) <= ((ai).rawdata + (ai).rawsize))
474
475
476 #define SWAP16(x) OSSwapBigToHostInt16((x))
477 #define SWAP32(x) OSSwapBigToHostInt32((x))
478 #define SWAP64(x) OSSwapBigToHostInt64((x))
479
480
481 static u_int32_t emptyfinfo[8] = {0};
482
483
484 /*
485 * Local support routines
486 */
487 static void close_xattrfile(vnode_t xvp, int fileflags, vfs_context_t context);
488
489 static int open_xattrfile(vnode_t vp, int fileflags, vnode_t *xvpp, vfs_context_t context);
490
491 static int create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context);
492
493 static int remove_xattrfile(vnode_t xvp, vfs_context_t context);
494
495 static int get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t context);
496
497 static void rel_xattrinfo(attr_info_t *ainfop);
498
499 static int write_xattrinfo(attr_info_t *ainfop);
500
501 static void init_empty_resource_fork(rsrcfork_header_t * rsrcforkhdr);
502
503 static int lock_xattrfile(vnode_t xvp, short locktype, vfs_context_t context);
504
505 static int unlock_xattrfile(vnode_t xvp, vfs_context_t context);
506
507
508 #if BYTE_ORDER == LITTLE_ENDIAN
509 static void swap_adhdr(apple_double_header_t *adh);
510 static void swap_attrhdr(attr_header_t *ah);
511
512 #else
513 #define swap_adhdr(x)
514 #define swap_attrhdr(x)
515 #endif
516
517 static int validate_attrhdr(attr_header_t *ah, size_t bufsize);
518 static int shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context);
519 static int shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context);
520
521
522 /*
523 * Retrieve the data of an extended attribute.
524 */
525 static int
526 default_getxattr(vnode_t vp, const char *name, uio_t uio, size_t *size,
527 __unused int options, vfs_context_t context)
528 {
529 vnode_t xvp = NULL;
530 attr_info_t ainfo;
531 attr_header_t *header;
532 attr_entry_t *entry;
533 u_int8_t *attrdata;
534 size_t datalen;
535 int namelen;
536 int isrsrcfork;
537 int fileflags;
538 int i;
539 int error;
540
541 fileflags = FREAD;
542 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
543 isrsrcfork = 1;
544 /*
545 * Open the file locked (shared) since the Carbon
546 * File Manager may have the Apple Double file open
547 * and could be changing the resource fork.
548 */
549 fileflags |= O_SHLOCK;
550 } else {
551 isrsrcfork = 0;
552 }
553
554 if ((error = open_xattrfile(vp, fileflags, &xvp, context))) {
555 return (error);
556 }
557 if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
558 close_xattrfile(xvp, fileflags, context);
559 return (error);
560 }
561
562 /* Get the Finder Info. */
563 if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
564
565 if (ainfo.finderinfo == NULL || ainfo.emptyfinderinfo) {
566 error = ENOATTR;
567 } else if (uio == NULL) {
568 *size = FINDERINFOSIZE;
569 error = 0;
570 } else if (uio_offset(uio) != 0) {
571 error = EINVAL;
572 } else if (uio_resid(uio) < FINDERINFOSIZE) {
573 error = ERANGE;
574 } else {
575 attrdata = (u_int8_t*)ainfo.filehdr + ainfo.finderinfo->offset;
576 error = uiomove((caddr_t)attrdata, FINDERINFOSIZE, uio);
577 }
578 goto out;
579 }
580
581 /* Read the Resource Fork. */
582 if (isrsrcfork) {
583 if (!vnode_isreg(vp)) {
584 error = EPERM;
585 } else if (ainfo.rsrcfork == NULL) {
586 error = ENOATTR;
587 } else if (uio == NULL) {
588 *size = (size_t)ainfo.rsrcfork->length;
589 } else {
590 uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset);
591 error = VNOP_READ(xvp, uio, 0, context);
592 if (error == 0)
593 uio_setoffset(uio, uio_offset(uio) - ainfo.rsrcfork->offset);
594 }
595 goto out;
596 }
597
598 if (ainfo.attrhdr == NULL || ainfo.attr_entry == NULL) {
599 error = ENOATTR;
600 goto out;
601 }
602 if (uio_offset(uio) != 0) {
603 error = EINVAL;
604 goto out;
605 }
606 error = ENOATTR;
607 namelen = strlen(name) + 1;
608 header = ainfo.attrhdr;
609 entry = ainfo.attr_entry;
610 /*
611 * Search for attribute name in the header.
612 */
613 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
614 if (strncmp(entry->name, name, namelen) == 0) {
615 datalen = (size_t)entry->length;
616 if (uio == NULL) {
617 *size = datalen;
618 error = 0;
619 break;
620 }
621 if (uio_resid(uio) < datalen) {
622 error = ERANGE;
623 break;
624 }
625 if (entry->offset + datalen < ATTR_MAX_HDR_SIZE) {
626 attrdata = ((u_int8_t *)header + entry->offset);
627 error = uiomove((caddr_t)attrdata, datalen, uio);
628 } else {
629 uio_setoffset(uio, entry->offset);
630 error = VNOP_READ(xvp, uio, 0, context);
631 uio_setoffset(uio, 0);
632 }
633 break;
634 }
635 entry = ATTR_NEXT(entry);
636 }
637 out:
638 rel_xattrinfo(&ainfo);
639 close_xattrfile(xvp, fileflags, context);
640
641 return (error);
642 }
643
644 /*
645 * Set the data of an extended attribute.
646 */
647 static int
648 default_setxattr(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t context)
649 {
650 vnode_t xvp = NULL;
651 attr_info_t ainfo;
652 attr_header_t *header;
653 attr_entry_t *entry;
654 attr_entry_t *lastentry;
655 u_int8_t *attrdata;
656 size_t datalen;
657 size_t entrylen;
658 size_t datafreespace;
659 int namelen;
660 int found = 0;
661 int i;
662 int splitdata;
663 int fileflags;
664 int error;
665
666 datalen = uio_resid(uio);
667 namelen = strlen(name) + 1;
668 entrylen = ATTR_ENTRY_LENGTH(namelen);
669
670 if (datalen > ATTR_MAX_SIZE) {
671 return (E2BIG); /* EINVAL instead ? */
672 }
673 start:
674 /*
675 * Open the file locked since setting an attribute
676 * can change the layout of the Apple Double file.
677 */
678 fileflags = FREAD | FWRITE | O_EXLOCK;
679 if ((error = open_xattrfile(vp, O_CREAT | fileflags, &xvp, context))) {
680 return (error);
681 }
682 if ((error = get_xattrinfo(xvp, ATTR_SETTING, &ainfo, context))) {
683 close_xattrfile(xvp, fileflags, context);
684 return (error);
685 }
686
687 /* Set the Finder Info. */
688 if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
689 if (ainfo.finderinfo && !ainfo.emptyfinderinfo) {
690 /* attr exists and "create" was specified? */
691 if (options & XATTR_CREATE) {
692 error = EEXIST;
693 goto out;
694 }
695 } else {
696 /* attr doesn't exists and "replace" was specified? */
697 if (options & XATTR_REPLACE) {
698 error = ENOATTR;
699 goto out;
700 }
701 }
702 if (uio_offset(uio) != 0 || datalen != FINDERINFOSIZE) {
703 error = EINVAL;
704 goto out;
705 }
706 if (ainfo.finderinfo) {
707 attrdata = (u_int8_t *)ainfo.filehdr + ainfo.finderinfo->offset;
708 error = uiomove((caddr_t)attrdata, datalen, uio);
709 if (error)
710 goto out;
711 ainfo.iosize = sizeof(attr_header_t);
712 error = write_xattrinfo(&ainfo);
713 goto out;
714 }
715 error = ENOATTR;
716 goto out;
717 }
718
719 /* Write the Resource Fork. */
720 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
721 u_int32_t endoffset;
722
723 if (!vnode_isreg(vp)) {
724 error = EPERM;
725 goto out;
726 }
727 if (ainfo.rsrcfork && ainfo.rsrcfork->length) {
728 /* attr exists and "create" was specified? */
729 if (options & XATTR_CREATE) {
730 error = EEXIST;
731 goto out;
732 }
733 } else {
734 /* attr doesn't exists and "replace" was specified? */
735 if (options & XATTR_REPLACE) {
736 error = ENOATTR;
737 goto out;
738 }
739 }
740 endoffset = uio_resid(uio) + uio_offset(uio); /* new size */
741 uio_setoffset(uio, uio_offset(uio) + ainfo.rsrcfork->offset);
742 error = VNOP_WRITE(xvp, uio, 0, context);
743 if (error)
744 goto out;
745 uio_setoffset(uio, uio_offset(uio) - ainfo.rsrcfork->offset);
746 if (endoffset > ainfo.rsrcfork->length) {
747 ainfo.rsrcfork->length = endoffset;
748 ainfo.iosize = sizeof(attr_header_t);
749 error = write_xattrinfo(&ainfo);
750 goto out;
751 }
752 goto out;
753 }
754
755 if (ainfo.attrhdr == NULL) {
756 error = ENOATTR;
757 goto out;
758 }
759 header = ainfo.attrhdr;
760 entry = ainfo.attr_entry;
761
762 /* Check if data area crosses the maximum header size. */
763 if ((header->data_start + header->data_length + entrylen + datalen) > ATTR_MAX_HDR_SIZE)
764 splitdata = 1; /* do data I/O separately */
765 else
766 splitdata = 0;
767
768 /*
769 * See if attribute already exists.
770 */
771 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
772 if (strncmp(entry->name, name, namelen) == 0) {
773 found = 1;
774 break;
775 }
776 entry = ATTR_NEXT(entry);
777 }
778
779 if (found) {
780 if (options & XATTR_CREATE) {
781 error = EEXIST;
782 goto out;
783 }
784 if (datalen == entry->length) {
785 if (splitdata) {
786 uio_setoffset(uio, entry->offset);
787 error = VNOP_WRITE(xvp, uio, 0, context);
788 uio_setoffset(uio, 0);
789 if (error) {
790 printf("setxattr: VNOP_WRITE error %d\n", error);
791 }
792 } else {
793 attrdata = (u_int8_t *)header + entry->offset;
794 error = uiomove((caddr_t)attrdata, datalen, uio);
795 if (error)
796 goto out;
797 ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length;
798 error = write_xattrinfo(&ainfo);
799 if (error) {
800 printf("setxattr: write_xattrinfo error %d\n", error);
801 }
802 }
803 goto out;
804 } else {
805 /*
806 * Brute force approach - just remove old entry and set new entry.
807 */
808 found = 0;
809 rel_xattrinfo(&ainfo);
810 close_xattrfile(xvp, fileflags, context);
811 error = default_removexattr(vp, name, options, context);
812 if (error) {
813 goto out;
814 }
815 goto start; /* start over */
816 }
817
818 }
819
820 if (options & XATTR_REPLACE) {
821 error = ENOATTR; /* nothing there to replace */
822 goto out;
823 }
824 /* Check if header size limit has been reached. */
825 if ((header->data_start + entrylen) > ATTR_MAX_HDR_SIZE) {
826 error = ENOSPC;
827 goto out;
828 }
829
830 datafreespace = header->total_size - (header->data_start + header->data_length);
831
832 /* Check if we need more space. */
833 if ((datalen + entrylen) > datafreespace) {
834 size_t growsize;
835
836 growsize = roundup((datalen + entrylen) - datafreespace, ATTR_BUF_SIZE);
837
838 /* Clip roundup size when we can still fit in ATTR_MAX_HDR_SIZE. */
839 if (!splitdata && (header->total_size + growsize) > ATTR_MAX_HDR_SIZE) {
840 growsize = ATTR_MAX_HDR_SIZE - header->total_size;
841 }
842
843 ainfo.filesize += growsize;
844 error = vnode_setsize(xvp, ainfo.filesize, 0, context);
845 if (error) {
846 printf("setxattr: VNOP_TRUNCATE error %d\n", error);
847 }
848 if (error)
849 goto out;
850
851 /*
852 * Move the resource fork out of the way.
853 */
854 if (ainfo.rsrcfork) {
855 if (ainfo.rsrcfork->length != 0) {
856 shift_data_down(xvp,
857 ainfo.rsrcfork->offset,
858 ainfo.rsrcfork->length,
859 growsize, context);
860 }
861 ainfo.rsrcfork->offset += growsize;
862 }
863 ainfo.finderinfo->length += growsize;
864 header->total_size += growsize;
865 }
866
867 /* Make space for a new entry. */
868 if (splitdata) {
869 shift_data_down(xvp,
870 header->data_start,
871 header->data_length,
872 entrylen, context);
873 } else {
874 bcopy((u_int8_t *)header + header->data_start,
875 (u_int8_t *)header + header->data_start + entrylen,
876 header->data_length);
877 }
878 header->data_start += entrylen;
879
880 /* Fix up entry data offsets. */
881 lastentry = entry;
882 for (entry = ainfo.attr_entry; entry != lastentry && ATTR_VALID(entry, ainfo); entry = ATTR_NEXT(entry)) {
883 entry->offset += entrylen;
884 }
885
886 /*
887 * If the attribute data area is entirely within
888 * the header buffer, then just update the buffer,
889 * otherwise we'll write it separately to the file.
890 */
891 if (splitdata) {
892 off_t offset;
893
894 /* Write new attribute data after the end of existing data. */
895 offset = header->data_start + header->data_length;
896 uio_setoffset(uio, offset);
897 error = VNOP_WRITE(xvp, uio, 0, context);
898 uio_setoffset(uio, 0);
899 if (error) {
900 printf("setxattr: VNOP_WRITE error %d\n", error);
901 goto out;
902 }
903 } else {
904 attrdata = (u_int8_t *)header + header->data_start + header->data_length;
905
906 error = uiomove((caddr_t)attrdata, datalen, uio);
907 if (error) {
908 printf("setxattr: uiomove error %d\n", error);
909 goto out;
910 }
911 }
912
913 /* Create the attribute entry. */
914 lastentry->length = datalen;
915 lastentry->offset = header->data_start + header->data_length;
916 lastentry->namelen = namelen;
917 lastentry->flags = 0;
918 bcopy(name, &lastentry->name[0], namelen);
919
920 /* Update the attributes header. */
921 header->num_attrs++;
922 header->data_length += datalen;
923
924 if (splitdata) {
925 /* Only write the entries, since the data was written separately. */
926 ainfo.iosize = ainfo.attrhdr->data_start;
927 } else {
928 /* The entry and data are both in the header; write them together. */
929 ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length;
930 }
931 error = write_xattrinfo(&ainfo);
932 if (error) {
933 printf("setxattr: write_xattrinfo error %d\n", error);
934 }
935
936 out:
937 rel_xattrinfo(&ainfo);
938 close_xattrfile(xvp, fileflags, context);
939
940 /* Touch the change time if we changed an attribute. */
941 if (error == 0) {
942 struct vnode_attr va;
943
944 /* Re-write the mtime to cause a ctime change. */
945 VATTR_INIT(&va);
946 VATTR_WANTED(&va, va_modify_time);
947 if (vnode_getattr(vp, &va, context) == 0) {
948 VATTR_INIT(&va);
949 VATTR_SET(&va, va_modify_time, va.va_modify_time);
950 (void) vnode_setattr(vp, &va, context);
951 }
952 }
953 return (error);
954 }
955
956
957 /*
958 * Remove an extended attribute.
959 */
960 static int
961 default_removexattr(vnode_t vp, const char *name, __unused int options, vfs_context_t context)
962 {
963 vnode_t xvp = NULL;
964 attr_info_t ainfo;
965 attr_header_t *header;
966 attr_entry_t *entry;
967 attr_entry_t *oldslot;
968 u_int8_t *attrdata;
969 u_int32_t dataoff;
970 size_t datalen;
971 size_t entrylen;
972 int namelen;
973 int found = 0, lastone = 0;
974 int i;
975 int splitdata;
976 int attrcount = 0;
977 int isrsrcfork;
978 int fileflags;
979 int error;
980
981 fileflags = FREAD | FWRITE;
982 if (bcmp(name, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) == 0) {
983 isrsrcfork = 1;
984 /*
985 * Open the file locked (exclusive) since the Carbon
986 * File Manager may have the Apple Double file open
987 * and could be changing the resource fork.
988 */
989 fileflags |= O_EXLOCK;
990 } else {
991 isrsrcfork = 0;
992 }
993
994 if ((error = open_xattrfile(vp, fileflags, &xvp, context))) {
995 return (error);
996 }
997 if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
998 close_xattrfile(xvp, fileflags, context);
999 return (error);
1000 }
1001 if (ainfo.attrhdr)
1002 attrcount += ainfo.attrhdr->num_attrs;
1003 if (ainfo.rsrcfork)
1004 ++attrcount;
1005 if (ainfo.finderinfo && !ainfo.emptyfinderinfo)
1006 ++attrcount;
1007
1008 /* Clear the Finder Info. */
1009 if (bcmp(name, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME)) == 0) {
1010 if (ainfo.finderinfo == NULL || ainfo.emptyfinderinfo) {
1011 error = ENOATTR;
1012 goto out;
1013 }
1014 /* On removal of last attribute the ._ file is removed. */
1015 if (--attrcount == 0)
1016 goto out;
1017 attrdata = (u_int8_t *)ainfo.filehdr + ainfo.finderinfo->offset;
1018 bzero((caddr_t)attrdata, FINDERINFOSIZE);
1019 ainfo.iosize = sizeof(attr_header_t);
1020 error = write_xattrinfo(&ainfo);
1021 goto out;
1022 }
1023
1024 /* Clear the Resource Fork. */
1025 if (isrsrcfork) {
1026 if (!vnode_isreg(vp)) {
1027 error = EPERM;
1028 goto out;
1029 }
1030 if (ainfo.rsrcfork == NULL || ainfo.rsrcfork->length == 0) {
1031 error = ENOATTR;
1032 goto out;
1033 }
1034 /* On removal of last attribute the ._ file is removed. */
1035 if (--attrcount == 0)
1036 goto out;
1037 /*
1038 * XXX
1039 * If the resource fork isn't the last AppleDouble
1040 * entry then the space needs to be reclaimed by
1041 * shifting the entries after the resource fork.
1042 */
1043 if ((ainfo.rsrcfork->offset + ainfo.rsrcfork->length) == ainfo.filesize) {
1044 ainfo.filesize -= ainfo.rsrcfork->length;
1045 error = vnode_setsize(xvp, ainfo.filesize, 0, context);
1046 }
1047 if (error == 0) {
1048 ainfo.rsrcfork->length = 0;
1049 ainfo.iosize = sizeof(attr_header_t);
1050 error = write_xattrinfo(&ainfo);
1051 }
1052 goto out;
1053 }
1054
1055 if (ainfo.attrhdr == NULL) {
1056 error = ENOATTR;
1057 goto out;
1058 }
1059 namelen = strlen(name) + 1;
1060 header = ainfo.attrhdr;
1061 entry = ainfo.attr_entry;
1062
1063 /*
1064 * See if this attribute exists.
1065 */
1066 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
1067 if (strncmp(entry->name, name, namelen) == 0) {
1068 found = 1;
1069 if ((i+1) == header->num_attrs)
1070 lastone = 1;
1071 break;
1072 }
1073 entry = ATTR_NEXT(entry);
1074 }
1075 if (!found) {
1076 error = ENOATTR;
1077 goto out;
1078 }
1079 /* On removal of last attribute the ._ file is removed. */
1080 if (--attrcount == 0)
1081 goto out;
1082
1083 datalen = entry->length;
1084 dataoff = entry->offset;
1085 entrylen = ATTR_ENTRY_LENGTH(namelen);
1086 if ((header->data_start + header->data_length) > ATTR_MAX_HDR_SIZE)
1087 splitdata = 1;
1088 else
1089 splitdata = 0;
1090
1091 /* Remove the attribute entry. */
1092 if (!lastone) {
1093 bcopy((u_int8_t *)entry + entrylen, (u_int8_t *)entry,
1094 ((size_t)header + header->data_start) - ((size_t)entry + entrylen));
1095 }
1096
1097 /* Adjust the attribute data. */
1098 if (splitdata) {
1099 shift_data_up(xvp,
1100 header->data_start,
1101 dataoff - header->data_start,
1102 entrylen,
1103 context);
1104 if (!lastone) {
1105 shift_data_up(xvp,
1106 dataoff + datalen,
1107 (header->data_start + header->data_length) - (dataoff + datalen),
1108 datalen + entrylen,
1109 context);
1110 }
1111 /* XXX write zeros to freed space ? */
1112 ainfo.iosize = ainfo.attrhdr->data_start - entrylen;
1113 } else {
1114
1115
1116 bcopy((u_int8_t *)header + header->data_start,
1117 (u_int8_t *)header + header->data_start - entrylen,
1118 dataoff - header->data_start);
1119 if (!lastone) {
1120 bcopy((u_int8_t *)header + dataoff + datalen,
1121 (u_int8_t *)header + dataoff - entrylen,
1122 (header->data_start + header->data_length) - (dataoff + datalen));
1123 }
1124 bzero (((u_int8_t *)header + header->data_start + header->data_length) - (datalen + entrylen), (datalen + entrylen));
1125 ainfo.iosize = ainfo.attrhdr->data_start + ainfo.attrhdr->data_length;
1126 }
1127
1128 /* Adjust the header values and entry offsets. */
1129 header->num_attrs--;
1130 header->data_start -= entrylen;
1131 header->data_length -= datalen;
1132
1133 oldslot = entry;
1134 entry = ainfo.attr_entry;
1135 for (i = 0; i < header->num_attrs && ATTR_VALID(entry, ainfo); i++) {
1136 entry->offset -= entrylen;
1137 if (entry >= oldslot)
1138 entry->offset -= datalen;
1139 entry = ATTR_NEXT(entry);
1140 }
1141 error = write_xattrinfo(&ainfo);
1142 if (error) {
1143 printf("removexattr: write_xattrinfo error %d\n", error);
1144 }
1145 out:
1146 rel_xattrinfo(&ainfo);
1147
1148 /* When there are no more attributes remove the ._ file. */
1149 if (attrcount == 0) {
1150 if (fileflags & O_EXLOCK)
1151 (void) unlock_xattrfile(xvp, context);
1152 VNOP_CLOSE(xvp, fileflags, context);
1153 vnode_rele(xvp);
1154 error = remove_xattrfile(xvp, context);
1155 vnode_put(xvp);
1156 } else {
1157 close_xattrfile(xvp, fileflags, context);
1158 }
1159 /* Touch the change time if we changed an attribute. */
1160 if (error == 0) {
1161 struct vnode_attr va;
1162
1163 /* Re-write the mtime to cause a ctime change. */
1164 VATTR_INIT(&va);
1165 VATTR_WANTED(&va, va_modify_time);
1166 if (vnode_getattr(vp, &va, context) == 0) {
1167 VATTR_INIT(&va);
1168 VATTR_SET(&va, va_modify_time, va.va_modify_time);
1169 (void) vnode_setattr(vp, &va, context);
1170 }
1171 }
1172 return (error);
1173
1174 }
1175
1176
1177 /*
1178 * Retrieve the list of extended attribute names.
1179 */
1180 static int
1181 default_listxattr(vnode_t vp, uio_t uio, size_t *size, __unused int options, vfs_context_t context)
1182 {
1183 vnode_t xvp = NULL;
1184 attr_info_t ainfo;
1185 attr_entry_t *entry;
1186 int i, count;
1187 int error;
1188
1189 /*
1190 * We do not zero "*size" here as we don't want to stomp a size set when
1191 * VNOP_LISTXATTR processed any native EAs. That size is initially zeroed by the
1192 * system call layer, up in listxattr or flistxattr.
1193 */
1194
1195 if ((error = open_xattrfile(vp, FREAD, &xvp, context))) {
1196 if (error == ENOATTR)
1197 error = 0;
1198 return (error);
1199 }
1200 if ((error = get_xattrinfo(xvp, 0, &ainfo, context))) {
1201 close_xattrfile(xvp, FREAD, context);
1202 return (error);
1203 }
1204
1205 /* Check for Finder Info. */
1206 if (ainfo.finderinfo && !ainfo.emptyfinderinfo) {
1207 if (uio == NULL) {
1208 *size += sizeof(XATTR_FINDERINFO_NAME);
1209 } else if (uio_resid(uio) < sizeof(XATTR_FINDERINFO_NAME)) {
1210 error = ERANGE;
1211 goto out;
1212 } else {
1213 error = uiomove((caddr_t)XATTR_FINDERINFO_NAME,
1214 sizeof(XATTR_FINDERINFO_NAME), uio);
1215 if (error) {
1216 error = ERANGE;
1217 goto out;
1218 }
1219 }
1220 }
1221
1222 /* Check for Resource Fork. */
1223 if (vnode_isreg(vp) && ainfo.rsrcfork) {
1224 if (uio == NULL) {
1225 *size += sizeof(XATTR_RESOURCEFORK_NAME);
1226 } else if (uio_resid(uio) < sizeof(XATTR_RESOURCEFORK_NAME)) {
1227 error = ERANGE;
1228 goto out;
1229 } else {
1230 error = uiomove((caddr_t)XATTR_RESOURCEFORK_NAME,
1231 sizeof(XATTR_RESOURCEFORK_NAME), uio);
1232 if (error) {
1233 error = ERANGE;
1234 goto out;
1235 }
1236 }
1237 }
1238
1239 /* Check for attributes. */
1240 if (ainfo.attrhdr) {
1241 count = ainfo.attrhdr->num_attrs;
1242 for (i = 0, entry = ainfo.attr_entry; i < count && ATTR_VALID(entry, ainfo); i++) {
1243 if (xattr_protected(entry->name) ||
1244 xattr_validatename(entry->name) != 0) {
1245 entry = ATTR_NEXT(entry);
1246 continue;
1247 }
1248 if (uio == NULL) {
1249 *size += entry->namelen;
1250 entry = ATTR_NEXT(entry);
1251 continue;
1252 }
1253 if (uio_resid(uio) < entry->namelen) {
1254 error = ERANGE;
1255 break;
1256 }
1257 error = uiomove((caddr_t) entry->name, entry->namelen, uio);
1258 if (error) {
1259 if (error != EFAULT)
1260 error = ERANGE;
1261 break;
1262 }
1263 entry = ATTR_NEXT(entry);
1264 }
1265 }
1266 out:
1267 rel_xattrinfo(&ainfo);
1268 close_xattrfile(xvp, FREAD, context);
1269
1270 return (error);
1271 }
1272
1273 static int
1274 open_xattrfile(vnode_t vp, int fileflags, vnode_t *xvpp, vfs_context_t context)
1275 {
1276 vnode_t xvp = NULLVP;
1277 vnode_t dvp = NULLVP;
1278 struct vnode_attr va;
1279 struct nameidata nd;
1280 char smallname[64];
1281 char *filename = NULL;
1282 char *basename = NULL;
1283 size_t len;
1284 errno_t error;
1285 int opened = 0;
1286 int referenced = 0;
1287
1288 if (vnode_isvroot(vp) && vnode_isdir(vp)) {
1289 /*
1290 * For the root directory use "._." to hold the attributes.
1291 */
1292 filename = &smallname[0];
1293 sprintf(filename, "%s%s", ATTR_FILE_PREFIX, ".");
1294 dvp = vp; /* the "._." file resides in the root dir */
1295 goto lookup;
1296 }
1297 if ( (dvp = vnode_getparent(vp)) == NULLVP) {
1298 error = ENOATTR;
1299 goto out;
1300 }
1301 if ( (basename = vnode_getname(vp)) == NULL) {
1302 error = ENOATTR;
1303 goto out;
1304 }
1305
1306 /* "._" Attribute files cannot have attributes */
1307 if (vp->v_type == VREG && strlen(basename) > 2 &&
1308 basename[0] == '.' && basename[1] == '_') {
1309 error = EPERM;
1310 goto out;
1311 }
1312 filename = &smallname[0];
1313 len = snprintf(filename, sizeof(smallname), "%s%s", ATTR_FILE_PREFIX, basename);
1314 if (len >= sizeof(smallname)) {
1315 len++; /* snprintf result doesn't include '\0' */
1316 MALLOC(filename, char *, len, M_TEMP, M_WAITOK);
1317 len = snprintf(filename, len, "%s%s", ATTR_FILE_PREFIX, basename);
1318 }
1319 /*
1320 * Note that the lookup here does not authorize. Since we are looking
1321 * up in the same directory that we already have the file vnode in,
1322 * we must have been given the file vnode legitimately. Read/write
1323 * access has already been authorized in layers above for calls from
1324 * userspace, and the authorization code using this path to read
1325 * file security from the EA must always get access
1326 */
1327 lookup:
1328 NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW | USEDVP | DONOTAUTH, UIO_SYSSPACE,
1329 CAST_USER_ADDR_T(filename), context);
1330 nd.ni_dvp = dvp;
1331
1332 if (fileflags & O_CREAT) {
1333 nd.ni_cnd.cn_nameiop = CREATE;
1334 if (dvp != vp) {
1335 nd.ni_cnd.cn_flags |= LOCKPARENT;
1336 }
1337 if ( (error = namei(&nd))) {
1338 nd.ni_dvp = NULLVP;
1339 error = ENOATTR;
1340 goto out;
1341 }
1342 if ( (xvp = nd.ni_vp) == NULLVP) {
1343 uid_t uid;
1344 gid_t gid;
1345 mode_t umode;
1346
1347 /*
1348 * Pick up uid/gid/mode from target file.
1349 */
1350 VATTR_INIT(&va);
1351 VATTR_WANTED(&va, va_uid);
1352 VATTR_WANTED(&va, va_gid);
1353 VATTR_WANTED(&va, va_mode);
1354 if (VNOP_GETATTR(vp, &va, context) == 0 &&
1355 VATTR_IS_SUPPORTED(&va, va_uid) &&
1356 VATTR_IS_SUPPORTED(&va, va_gid) &&
1357 VATTR_IS_SUPPORTED(&va, va_mode)) {
1358 uid = va.va_uid;
1359 gid = va.va_gid;
1360 umode = va.va_mode & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
1361 } else /* fallback values */ {
1362 uid = KAUTH_UID_NONE;
1363 gid = KAUTH_GID_NONE;
1364 umode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
1365 }
1366
1367 VATTR_INIT(&va);
1368 VATTR_SET(&va, va_type, VREG);
1369 VATTR_SET(&va, va_mode, umode);
1370 if (uid != KAUTH_UID_NONE)
1371 VATTR_SET(&va, va_uid, uid);
1372 if (gid != KAUTH_GID_NONE)
1373 VATTR_SET(&va, va_gid, gid);
1374
1375 error = vn_create(dvp, &nd.ni_vp, &nd.ni_cnd, &va,
1376 VN_CREATE_NOAUTH | VN_CREATE_NOINHERIT,
1377 context);
1378 if (error == 0)
1379 xvp = nd.ni_vp;
1380 }
1381 nameidone(&nd);
1382 if (dvp != vp) {
1383 vnode_put(dvp); /* drop iocount from LOCKPARENT request above */
1384 }
1385 if (error)
1386 goto out;
1387 } else {
1388 if ((error = namei(&nd))) {
1389 nd.ni_dvp = NULLVP;
1390 error = ENOATTR;
1391 goto out;
1392 }
1393 xvp = nd.ni_vp;
1394 nameidone(&nd);
1395 }
1396 nd.ni_dvp = NULLVP;
1397
1398 if (xvp->v_type != VREG) {
1399 error = ENOATTR;
1400 goto out;
1401 }
1402 /*
1403 * Owners must match.
1404 */
1405 VATTR_INIT(&va);
1406 VATTR_WANTED(&va, va_uid);
1407 if (VNOP_GETATTR(vp, &va, context) == 0 && VATTR_IS_SUPPORTED(&va, va_uid)) {
1408 uid_t owner = va.va_uid;
1409
1410 VATTR_INIT(&va);
1411 VATTR_WANTED(&va, va_uid);
1412 if (VNOP_GETATTR(xvp, &va, context) == 0 && (owner != va.va_uid)) {
1413 error = ENOATTR; /* don't use this "._" file */
1414 goto out;
1415 }
1416 }
1417
1418 if ( (error = VNOP_OPEN(xvp, fileflags, context))) {
1419 error = ENOATTR;
1420 goto out;
1421 }
1422 opened = 1;
1423
1424 if ((error = vnode_ref(xvp))) {
1425 goto out;
1426 }
1427 referenced = 1;
1428
1429 /* If create was requested, make sure file header exists. */
1430 if (fileflags & O_CREAT) {
1431 VATTR_INIT(&va);
1432 VATTR_WANTED(&va, va_data_size);
1433 VATTR_WANTED(&va, va_fileid);
1434 VATTR_WANTED(&va, va_nlink);
1435 if ( (error = vnode_getattr(xvp, &va, context)) != 0) {
1436 error = EPERM;
1437 goto out;
1438 }
1439
1440 /* If the file is empty then add a default header. */
1441 if (va.va_data_size == 0) {
1442 /* Don't adopt hard-linked "._" files. */
1443 if (VATTR_IS_SUPPORTED(&va, va_nlink) && va.va_nlink > 1) {
1444 error = EPERM;
1445 goto out;
1446 }
1447 if ( (error = create_xattrfile(xvp, (u_int32_t)va.va_fileid, context)))
1448 goto out;
1449 }
1450 }
1451 /* Apply file locking if requested. */
1452 if (fileflags & (O_EXLOCK | O_SHLOCK)) {
1453 short locktype;
1454
1455 locktype = (fileflags & O_EXLOCK) ? F_WRLCK : F_RDLCK;
1456 error = lock_xattrfile(xvp, locktype, context);
1457 }
1458 out:
1459 if (dvp && (dvp != vp)) {
1460 vnode_put(dvp);
1461 }
1462 if (basename) {
1463 vnode_putname(basename);
1464 }
1465 if (filename && filename != &smallname[0]) {
1466 FREE(filename, M_TEMP);
1467 }
1468 if (error) {
1469 if (xvp != NULLVP) {
1470 if (opened) {
1471 (void) VNOP_CLOSE(xvp, fileflags, context);
1472 }
1473 if (referenced) {
1474 (void) vnode_rele(xvp);
1475 }
1476 (void) vnode_put(xvp);
1477 xvp = NULLVP;
1478 }
1479 if ((error == ENOATTR) && (fileflags & O_CREAT)) {
1480 error = EPERM;
1481 }
1482 }
1483 *xvpp = xvp; /* return a referenced vnode */
1484 return (error);
1485 }
1486
1487 static void
1488 close_xattrfile(vnode_t xvp, int fileflags, vfs_context_t context)
1489 {
1490 // if (fileflags & FWRITE)
1491 // (void) VNOP_FSYNC(xvp, MNT_WAIT, context);
1492
1493 if (fileflags & (O_EXLOCK | O_SHLOCK))
1494 (void) unlock_xattrfile(xvp, context);
1495
1496 (void) VNOP_CLOSE(xvp, fileflags, context);
1497 (void) vnode_rele(xvp);
1498 (void) vnode_put(xvp);
1499 }
1500
1501 static int
1502 remove_xattrfile(vnode_t xvp, vfs_context_t context)
1503 {
1504 vnode_t dvp;
1505 struct nameidata nd;
1506 char *path;
1507 int pathlen;
1508 int error = 0;
1509
1510 path = get_pathbuff();
1511 pathlen = MAXPATHLEN;
1512 vn_getpath(xvp, path, &pathlen);
1513
1514 NDINIT(&nd, DELETE, LOCKPARENT | NOFOLLOW | DONOTAUTH,
1515 UIO_SYSSPACE, CAST_USER_ADDR_T(path), context);
1516 error = namei(&nd);
1517 release_pathbuff(path);
1518 if (error) {
1519 return (error);
1520 }
1521 dvp = nd.ni_dvp;
1522 xvp = nd.ni_vp;
1523
1524 error = VNOP_REMOVE(dvp, xvp, &nd.ni_cnd, 0, context);
1525 nameidone(&nd);
1526 vnode_put(dvp);
1527 vnode_put(xvp);
1528
1529 return (error);
1530 }
1531
1532 static int
1533 get_xattrinfo(vnode_t xvp, int setting, attr_info_t *ainfop, vfs_context_t context)
1534 {
1535 uio_t auio = NULL;
1536 void * buffer = NULL;
1537 apple_double_header_t *filehdr;
1538 attr_header_t *attrhdr;
1539 struct vnode_attr va;
1540 size_t iosize;
1541 int i;
1542 int error;
1543
1544 bzero(ainfop, sizeof(attr_info_t));
1545 ainfop->filevp = xvp;
1546 ainfop->context = context;
1547 VATTR_INIT(&va);
1548 VATTR_WANTED(&va, va_data_size);
1549 VATTR_WANTED(&va, va_fileid);
1550 if ((error = vnode_getattr(xvp, &va, context))) {
1551 goto bail;
1552 }
1553 ainfop->filesize = va.va_data_size;
1554
1555 /* When setting attributes, allow room for the header to grow. */
1556 if (setting)
1557 iosize = ATTR_MAX_HDR_SIZE;
1558 else
1559 iosize = MIN(ATTR_MAX_HDR_SIZE, ainfop->filesize);
1560
1561 if (iosize == 0) {
1562 error = ENOATTR;
1563 goto bail;
1564 }
1565 ainfop->iosize = iosize;
1566 MALLOC(buffer, void *, iosize, M_TEMP, M_WAITOK);
1567 auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_READ);
1568 uio_addiov(auio, (uintptr_t)buffer, iosize);
1569
1570 /* Read the file header. */
1571 error = VNOP_READ(xvp, auio, 0, context);
1572 if (error) {
1573 goto bail;
1574 }
1575 ainfop->rawsize = iosize - uio_resid(auio);
1576 ainfop->rawdata = (u_int8_t *)buffer;
1577
1578 filehdr = (apple_double_header_t *)buffer;
1579
1580 /* Check for Apple Double file. */
1581 if (SWAP32(filehdr->magic) != ADH_MAGIC ||
1582 SWAP32(filehdr->version) != ADH_VERSION ||
1583 SWAP16(filehdr->numEntries) < 1 ||
1584 SWAP16(filehdr->numEntries) > 15) {
1585 error = ENOATTR;
1586 goto bail;
1587 }
1588 if (ADHDRSIZE + (SWAP16(filehdr->numEntries) * sizeof(apple_double_entry_t)) > ainfop->rawsize) {
1589 error = EINVAL;
1590 goto bail;
1591 }
1592
1593 swap_adhdr(filehdr);
1594 ainfop->filehdr = filehdr; /* valid AppleDouble header */
1595 /* rel_xattrinfo is responsible for freeing the header buffer */
1596 buffer = NULL;
1597
1598 /* Check the AppleDouble entries. */
1599 for (i = 0; i < filehdr->numEntries; ++i) {
1600 if (filehdr->entries[i].type == AD_FINDERINFO &&
1601 filehdr->entries[i].length > 0) {
1602 ainfop->finderinfo = &filehdr->entries[i];
1603 attrhdr = (attr_header_t *)filehdr;
1604
1605 if (bcmp((u_int8_t*)ainfop->filehdr + ainfop->finderinfo->offset,
1606 emptyfinfo, sizeof(emptyfinfo)) == 0) {
1607 ainfop->emptyfinderinfo = 1;
1608 }
1609
1610 if (i != 0) {
1611 continue;
1612 }
1613 /* See if we need to convert this AppleDouble file. */
1614 if (filehdr->entries[0].length == FINDERINFOSIZE) {
1615 size_t delta;
1616 size_t writesize;
1617
1618 if (!setting ||
1619 filehdr->entries[1].type != AD_RESOURCE ||
1620 filehdr->numEntries > 2) {
1621 continue; /* not expected layout */
1622 }
1623 delta = ATTR_BUF_SIZE - (filehdr->entries[0].offset + FINDERINFOSIZE);
1624 if (filehdr->entries[1].length) {
1625 /* Make some room. */
1626 shift_data_down(xvp,
1627 filehdr->entries[1].offset,
1628 filehdr->entries[1].length,
1629 delta, context);
1630 writesize = sizeof(attr_header_t);
1631 } else {
1632 rsrcfork_header_t *rsrcforkhdr;
1633
1634 vnode_setsize(xvp, filehdr->entries[1].offset + delta, 0, context);
1635
1636 /* Steal some space for an empty RF header. */
1637 delta -= sizeof(rsrcfork_header_t);
1638
1639 bzero(&attrhdr->appledouble.pad[0], delta);
1640 rsrcforkhdr = (rsrcfork_header_t *)((char *)filehdr + filehdr->entries[1].offset + delta);
1641
1642 /* Fill in Empty Resource Fork Header. */
1643 init_empty_resource_fork(rsrcforkhdr);
1644
1645 filehdr->entries[1].length = sizeof(rsrcfork_header_t);
1646 writesize = ATTR_BUF_SIZE;
1647 }
1648 filehdr->entries[0].length += delta;
1649 filehdr->entries[1].offset += delta;
1650
1651 /* Fill in Attribute Header. */
1652 attrhdr->magic = ATTR_HDR_MAGIC;
1653 attrhdr->debug_tag = (u_int32_t)va.va_fileid;
1654 attrhdr->total_size = filehdr->entries[1].offset;
1655 attrhdr->data_start = sizeof(attr_header_t);
1656 attrhdr->data_length = 0;
1657 attrhdr->reserved[0] = 0;
1658 attrhdr->reserved[1] = 0;
1659 attrhdr->reserved[2] = 0;
1660 attrhdr->flags = 0;
1661 attrhdr->num_attrs = 0;
1662
1663 /* Push out new header */
1664 uio_reset(auio, 0, UIO_SYSSPACE32, UIO_WRITE);
1665 uio_addiov(auio, (uintptr_t)filehdr, writesize);
1666
1667 swap_adhdr(filehdr);
1668 swap_attrhdr(attrhdr);
1669 error = VNOP_WRITE(xvp, auio, 0, context);
1670 swap_adhdr(filehdr);
1671 /* The attribute header gets swapped below. */
1672 }
1673 if (SWAP32 (attrhdr->magic) != ATTR_HDR_MAGIC ||
1674 validate_attrhdr(attrhdr, ainfop->rawsize) != 0) {
1675 printf("get_xattrinfo: invalid attribute header\n");
1676 continue;
1677 }
1678 swap_attrhdr(attrhdr);
1679 ainfop->attrhdr = attrhdr; /* valid attribute header */
1680 ainfop->attr_entry = (attr_entry_t *)&attrhdr[1];
1681 continue;
1682 }
1683 if (filehdr->entries[i].type == AD_RESOURCE &&
1684 (filehdr->entries[i].length > sizeof(rsrcfork_header_t) || setting)) {
1685 ainfop->rsrcfork = &filehdr->entries[i];
1686 if (i != (filehdr->numEntries - 1)) {
1687 printf("get_xattrinfo: resource fork not last entry\n");
1688 ainfop->readonly = 1;
1689 }
1690 continue;
1691 }
1692 }
1693 error = 0;
1694 bail:
1695 if (auio != NULL)
1696 uio_free(auio);
1697 if (buffer != NULL)
1698 FREE(buffer, M_TEMP);
1699 return (error);
1700 }
1701
1702
1703 static int
1704 create_xattrfile(vnode_t xvp, u_int32_t fileid, vfs_context_t context)
1705 {
1706 attr_header_t *xah;
1707 rsrcfork_header_t *rsrcforkhdr;
1708 void * buffer;
1709 uio_t auio;
1710 int rsrcforksize;
1711 int error;
1712
1713 MALLOC(buffer, void *, ATTR_BUF_SIZE, M_TEMP, M_WAITOK);
1714 bzero(buffer, ATTR_BUF_SIZE);
1715
1716 xah = (attr_header_t *)buffer;
1717 auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_WRITE);
1718 uio_addiov(auio, (uintptr_t)buffer, ATTR_BUF_SIZE);
1719 rsrcforksize = sizeof(rsrcfork_header_t);
1720 rsrcforkhdr = (rsrcfork_header_t *) ((char *)buffer + ATTR_BUF_SIZE - rsrcforksize);
1721
1722 /* Fill in Apple Double Header. */
1723 xah->appledouble.magic = SWAP32 (ADH_MAGIC);
1724 xah->appledouble.version = SWAP32 (ADH_VERSION);
1725 xah->appledouble.numEntries = SWAP16 (2);
1726 xah->appledouble.entries[0].type = SWAP32 (AD_FINDERINFO);
1727 xah->appledouble.entries[0].offset = SWAP32 (offsetof(apple_double_header_t, finfo));
1728 xah->appledouble.entries[0].length = SWAP32 (ATTR_BUF_SIZE - offsetof(apple_double_header_t, finfo) - rsrcforksize);
1729 xah->appledouble.entries[1].type = SWAP32 (AD_RESOURCE);
1730 xah->appledouble.entries[1].offset = SWAP32 (ATTR_BUF_SIZE - rsrcforksize);
1731 xah->appledouble.entries[1].length = SWAP32 (rsrcforksize);
1732 bcopy(ADH_MACOSX, xah->appledouble.filler, sizeof(xah->appledouble.filler));
1733
1734 /* Fill in Attribute Header. */
1735 xah->magic = SWAP32 (ATTR_HDR_MAGIC);
1736 xah->debug_tag = SWAP32 (fileid);
1737 xah->total_size = SWAP32 (ATTR_BUF_SIZE - rsrcforksize);
1738 xah->data_start = SWAP32 (sizeof(attr_header_t));
1739
1740 /* Fill in Empty Resource Fork Header. */
1741 init_empty_resource_fork(rsrcforkhdr);
1742
1743 /* Push it out. */
1744 error = VNOP_WRITE(xvp, auio, 0, context);
1745
1746 uio_free(auio);
1747 FREE(buffer, M_TEMP);
1748
1749 return (error);
1750 }
1751
1752 static void
1753 init_empty_resource_fork(rsrcfork_header_t * rsrcforkhdr)
1754 {
1755 bzero(rsrcforkhdr, sizeof(rsrcfork_header_t));
1756 rsrcforkhdr->fh_DataOffset = SWAP32 (RF_FIRST_RESOURCE);
1757 rsrcforkhdr->fh_MapOffset = SWAP32 (RF_FIRST_RESOURCE);
1758 rsrcforkhdr->fh_MapLength = SWAP32 (RF_NULL_MAP_LENGTH);
1759 rsrcforkhdr->mh_DataOffset = SWAP32 (RF_FIRST_RESOURCE);
1760 rsrcforkhdr->mh_MapOffset = SWAP32 (RF_FIRST_RESOURCE);
1761 rsrcforkhdr->mh_MapLength = SWAP32 (RF_NULL_MAP_LENGTH);
1762 rsrcforkhdr->mh_Types = SWAP16 (RF_NULL_MAP_LENGTH - 2 );
1763 rsrcforkhdr->mh_Names = SWAP16 (RF_NULL_MAP_LENGTH);
1764 rsrcforkhdr->typeCount = SWAP16 (-1);
1765 bcopy(RF_EMPTY_TAG, rsrcforkhdr->systemData, sizeof(RF_EMPTY_TAG));
1766 }
1767
1768 static void
1769 rel_xattrinfo(attr_info_t *ainfop)
1770 {
1771 FREE(ainfop->filehdr, M_TEMP);
1772 bzero(ainfop, sizeof(attr_info_t));
1773 }
1774
1775 static int
1776 write_xattrinfo(attr_info_t *ainfop)
1777 {
1778 uio_t auio;
1779 int error;
1780
1781 auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_WRITE);
1782 uio_addiov(auio, (uintptr_t)ainfop->filehdr, ainfop->iosize);
1783
1784 swap_adhdr(ainfop->filehdr);
1785 if (ainfop->attrhdr != NULL)
1786 swap_attrhdr(ainfop->attrhdr);
1787
1788 error = VNOP_WRITE(ainfop->filevp, auio, 0, ainfop->context);
1789
1790 swap_adhdr(ainfop->filehdr);
1791 if (ainfop->attrhdr != NULL)
1792 swap_attrhdr(ainfop->attrhdr);
1793 return (error);
1794 }
1795
1796 #if BYTE_ORDER == LITTLE_ENDIAN
1797 /*
1798 * Endian swap apple double header
1799 */
1800 static void
1801 swap_adhdr(apple_double_header_t *adh)
1802 {
1803 int count;
1804 int i;
1805
1806 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
1807
1808 adh->magic = SWAP32 (adh->magic);
1809 adh->version = SWAP32 (adh->version);
1810 adh->numEntries = SWAP16 (adh->numEntries);
1811
1812 for (i = 0; i < count; i++) {
1813 adh->entries[i].type = SWAP32 (adh->entries[i].type);
1814 adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
1815 adh->entries[i].length = SWAP32 (adh->entries[i].length);
1816 }
1817 }
1818
1819 /*
1820 * Endian swap extended attributes header
1821 */
1822 static void
1823 swap_attrhdr(attr_header_t *ah)
1824 {
1825 attr_entry_t *ae;
1826 int count;
1827 int i;
1828
1829 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
1830
1831 ah->magic = SWAP32 (ah->magic);
1832 ah->debug_tag = SWAP32 (ah->debug_tag);
1833 ah->total_size = SWAP32 (ah->total_size);
1834 ah->data_start = SWAP32 (ah->data_start);
1835 ah->data_length = SWAP32 (ah->data_length);
1836 ah->flags = SWAP16 (ah->flags);
1837 ah->num_attrs = SWAP16 (ah->num_attrs);
1838
1839 ae = (attr_entry_t *)(&ah[1]);
1840 for (i = 0; i < count; i++, ae = ATTR_NEXT(ae)) {
1841 ae->offset = SWAP32 (ae->offset);
1842 ae->length = SWAP32 (ae->length);
1843 ae->flags = SWAP16 (ae->flags);
1844 }
1845 }
1846 #endif
1847
1848 /*
1849 * Validate attributes header contents
1850 */
1851 static int
1852 validate_attrhdr(attr_header_t *ah, size_t bufsize)
1853 {
1854 attr_entry_t *ae;
1855 u_int8_t *bufend;
1856 int count;
1857 int i;
1858
1859 if (ah == NULL)
1860 return (EINVAL);
1861
1862 bufend = (u_int8_t *)ah + bufsize;
1863 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
1864
1865 ae = (attr_entry_t *)(&ah[1]);
1866 for (i = 0; i < count && (u_int8_t *)ae < bufend; i++, ae = ATTR_NEXT(ae)) {
1867 }
1868 return (i < count ? EINVAL : 0);
1869 }
1870
1871 //
1872 // "start" & "end" are byte offsets in the file.
1873 // "to" is the byte offset we want to move the
1874 // data to. "to" should be > "start".
1875 //
1876 // we do the copy backwards to avoid problems if
1877 // there's an overlap.
1878 //
1879 static int
1880 shift_data_down(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context)
1881 {
1882 int ret, iolen;
1883 size_t chunk, orig_chunk;
1884 char *buff;
1885 off_t pos;
1886 ucred_t ucred = vfs_context_ucred(context);
1887 proc_t p = vfs_context_proc(context);
1888
1889 if (delta == 0 || len == 0) {
1890 return 0;
1891 }
1892
1893 chunk = 4096;
1894 if (len < chunk) {
1895 chunk = len;
1896 }
1897 orig_chunk = chunk;
1898
1899 if (kmem_alloc(kernel_map, (vm_offset_t *)&buff, chunk)) {
1900 return ENOMEM;
1901 }
1902
1903 for(pos=start+len-chunk; pos >= start; pos-=chunk) {
1904 ret = vn_rdwr(UIO_READ, xvp, buff, chunk, pos, UIO_SYSSPACE, IO_NODELOCKED, ucred, &iolen, p);
1905 if (iolen != 0) {
1906 printf("xattr:shift_data: error reading data @ %lld (read %d of %d) (%d)\n",
1907 pos, ret, chunk, ret);
1908 break;
1909 }
1910
1911 ret = vn_rdwr(UIO_WRITE, xvp, buff, chunk, pos + delta, UIO_SYSSPACE, IO_NODELOCKED, ucred, &iolen, p);
1912 if (iolen != 0) {
1913 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %d) (%d)\n",
1914 pos+delta, ret, chunk, ret);
1915 break;
1916 }
1917
1918 if ((pos - chunk) < start) {
1919 chunk = pos - start;
1920
1921 if (chunk == 0) { // we're all done
1922 break;
1923 }
1924 }
1925 }
1926 kmem_free(kernel_map, (vm_offset_t)buff, orig_chunk);
1927
1928 return 0;
1929 }
1930
1931
1932 static int
1933 shift_data_up(vnode_t xvp, off_t start, size_t len, off_t delta, vfs_context_t context)
1934 {
1935 int ret, iolen;
1936 size_t chunk, orig_chunk;
1937 char *buff;
1938 off_t pos;
1939 off_t end;
1940 ucred_t ucred = vfs_context_ucred(context);
1941 proc_t p = vfs_context_proc(context);
1942
1943 if (delta == 0 || len == 0) {
1944 return 0;
1945 }
1946
1947 chunk = 4096;
1948 if (len < chunk) {
1949 chunk = len;
1950 }
1951 orig_chunk = chunk;
1952 end = start + len;
1953
1954 if (kmem_alloc(kernel_map, (vm_offset_t *)&buff, chunk)) {
1955 return ENOMEM;
1956 }
1957
1958 for(pos = start; pos < end; pos += chunk) {
1959 ret = vn_rdwr(UIO_READ, xvp, buff, chunk, pos, UIO_SYSSPACE, IO_NODELOCKED, ucred, &iolen, p);
1960 if (iolen != 0) {
1961 printf("xattr:shift_data: error reading data @ %lld (read %d of %d) (%d)\n",
1962 pos, ret, chunk, ret);
1963 break;
1964 }
1965
1966 ret = vn_rdwr(UIO_WRITE, xvp, buff, chunk, pos - delta, UIO_SYSSPACE, IO_NODELOCKED, ucred, &iolen, p);
1967 if (iolen != 0) {
1968 printf("xattr:shift_data: error writing data @ %lld (wrote %d of %d) (%d)\n",
1969 pos+delta, ret, chunk, ret);
1970 break;
1971 }
1972
1973 if ((pos + chunk) > end) {
1974 chunk = end - pos;
1975
1976 if (chunk == 0) { // we're all done
1977 break;
1978 }
1979 }
1980 }
1981 kmem_free(kernel_map, (vm_offset_t)buff, orig_chunk);
1982
1983 return 0;
1984 }
1985
1986 static int
1987 lock_xattrfile(vnode_t xvp, short locktype, vfs_context_t context)
1988 {
1989 struct flock lf;
1990
1991 lf.l_whence = SEEK_SET;
1992 lf.l_start = 0;
1993 lf.l_len = 0;
1994 lf.l_type = locktype; /* F_WRLCK or F_RDLCK */
1995 /* Note: id is just a kernel address that's not a proc */
1996 return VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_SETLK, &lf, F_FLOCK, context);
1997 }
1998
1999 static int
2000 unlock_xattrfile(vnode_t xvp, vfs_context_t context)
2001 {
2002 struct flock lf;
2003
2004 lf.l_whence = SEEK_SET;
2005 lf.l_start = 0;
2006 lf.l_len = 0;
2007 lf.l_type = F_UNLCK;
2008 /* Note: id is just a kernel address that's not a proc */
2009 return VNOP_ADVLOCK(xvp, (caddr_t)xvp, F_UNLCK, &lf, F_FLOCK, context);
2010 }
2011