]>
Commit | Line | Data |
---|---|---|
91447636 A |
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 <architecture/byte_order.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 |