]>
Commit | Line | Data |
---|---|---|
9bccf70c | 1 | /* |
22ba694c | 2 | * Copyright (c) 2000-2014 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
9bccf70c | 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@ |
9bccf70c A |
27 | */ |
28 | ||
29 | /* | |
30 | * hfs_attrlist.c - HFS attribute list processing | |
31 | * | |
32 | * Copyright (c) 1998-2002, Apple Computer, Inc. All Rights Reserved. | |
33 | */ | |
34 | ||
35 | #include <sys/param.h> | |
36 | #include <sys/systm.h> | |
37 | #include <sys/kernel.h> | |
38 | #include <sys/malloc.h> | |
39 | #include <sys/attr.h> | |
40 | #include <sys/stat.h> | |
41 | #include <sys/unistd.h> | |
91447636 A |
42 | #include <sys/mount_internal.h> |
43 | #include <sys/kauth.h> | |
6d2010ae | 44 | #include <sys/fsctl.h> |
91447636 A |
45 | |
46 | #include <kern/locks.h> | |
9bccf70c A |
47 | |
48 | #include "hfs.h" | |
49 | #include "hfs_cnode.h" | |
50 | #include "hfs_mount.h" | |
51 | #include "hfs_dbg.h" | |
52 | #include "hfs_attrlist.h" | |
2d21ac55 | 53 | #include "hfs_btreeio.h" |
9bccf70c A |
54 | |
55 | /* Packing routines: */ | |
56 | ||
2d21ac55 A |
57 | static void packnameattr(struct attrblock *abp, struct vnode *vp, |
58 | const u_int8_t *name, int namelen); | |
9bccf70c A |
59 | |
60 | static void packcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, | |
61 | struct vnode *vp, struct cat_desc * cdp, | |
b0d623f7 | 62 | struct cat_attr * cap, struct vfs_context *ctx); |
9bccf70c A |
63 | |
64 | static void packfileattr(struct attrblock *abp, struct hfsmount *hfsmp, | |
65 | struct cat_attr *cattrp, struct cat_fork *datafork, | |
b0d623f7 | 66 | struct cat_fork *rsrcfork, struct vnode *vp); |
9bccf70c A |
67 | |
68 | static void packdirattr(struct attrblock *abp, struct hfsmount *hfsmp, | |
69 | struct vnode *vp, struct cat_desc * descp, | |
91447636 | 70 | struct cat_attr * cattrp); |
9bccf70c | 71 | |
2d21ac55 | 72 | static u_int32_t hfs_real_user_access(vnode_t vp, vfs_context_t ctx); |
9bccf70c A |
73 | |
74 | /* | |
75 | * readdirattr operation will return attributes for the items in the | |
76 | * directory specified. | |
77 | * | |
78 | * It does not do . and .. entries. The problem is if you are at the root of the | |
79 | * hfs directory and go to .. you could be crossing a mountpoint into a | |
80 | * different (ufs) file system. The attributes that apply for it may not | |
81 | * apply for the file system you are doing the readdirattr on. To make life | |
82 | * simpler, this call will only return entries in its directory, hfs like. | |
9bccf70c | 83 | */ |
9bccf70c | 84 | int |
91447636 A |
85 | hfs_vnop_readdirattr(ap) |
86 | struct vnop_readdirattr_args /* { | |
9bccf70c A |
87 | struct vnode *a_vp; |
88 | struct attrlist *a_alist; | |
89 | struct uio *a_uio; | |
90 | u_long a_maxcount; | |
91 | u_long a_options; | |
92 | u_long *a_newstate; | |
93 | int *a_eofflag; | |
94 | u_long *a_actualcount; | |
91447636 | 95 | vfs_context_t a_context; |
9bccf70c A |
96 | } */ *ap; |
97 | { | |
98 | struct vnode *dvp = ap->a_vp; | |
91447636 A |
99 | struct cnode *dcp; |
100 | struct hfsmount * hfsmp; | |
9bccf70c | 101 | struct attrlist *alist = ap->a_alist; |
91447636 | 102 | uio_t uio = ap->a_uio; |
9bccf70c | 103 | int maxcount = ap->a_maxcount; |
2d21ac55 A |
104 | u_int32_t fixedblocksize; |
105 | u_int32_t maxattrblocksize; | |
106 | u_int32_t currattrbufsize; | |
9bccf70c A |
107 | void *attrbufptr = NULL; |
108 | void *attrptr; | |
109 | void *varptr; | |
110 | struct attrblock attrblk; | |
111 | int error = 0; | |
2d21ac55 A |
112 | int index = 0; |
113 | int i, dir_entries = 0; | |
9bccf70c | 114 | struct cat_desc *lastdescp = NULL; |
9bccf70c | 115 | struct cat_entrylist *ce_list = NULL; |
91447636 A |
116 | directoryhint_t *dirhint = NULL; |
117 | unsigned int tag; | |
2d21ac55 A |
118 | int maxentries; |
119 | int lockflags; | |
b0d623f7 | 120 | u_int32_t dirchg = 0; |
b4c24cb9 | 121 | |
9bccf70c A |
122 | *(ap->a_actualcount) = 0; |
123 | *(ap->a_eofflag) = 0; | |
9bccf70c A |
124 | |
125 | /* Check for invalid options and buffer space. */ | |
2d21ac55 A |
126 | if (((ap->a_options & ~(FSOPT_NOINMEMUPDATE | FSOPT_NOFOLLOW)) != 0) || |
127 | (uio_resid(uio) <= 0) || (uio_iovcnt(uio) > 1) || (maxcount <= 0)) { | |
9bccf70c | 128 | return (EINVAL); |
2d21ac55 A |
129 | } |
130 | /* | |
131 | * Reject requests for unsupported attributes. | |
132 | */ | |
9bccf70c | 133 | if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || |
2d21ac55 | 134 | (alist->commonattr & ~HFS_ATTR_CMN_VALID) || |
9bccf70c | 135 | (alist->volattr != 0) || |
2d21ac55 A |
136 | (alist->dirattr & ~HFS_ATTR_DIR_VALID) || |
137 | (alist->fileattr & ~HFS_ATTR_FILE_VALID) || | |
138 | (alist->forkattr != 0)) { | |
9bccf70c | 139 | return (EINVAL); |
2d21ac55 | 140 | } |
6d2010ae | 141 | |
316670eb | 142 | if (VTOC(dvp)->c_bsdflags & UF_COMPRESSED) { |
6d2010ae A |
143 | int compressed = hfs_file_is_compressed(VTOC(dvp), 0); /* 0 == take the cnode lock */ |
144 | ||
145 | if (!compressed) { | |
146 | error = check_for_dataless_file(dvp, NAMESPACE_HANDLER_READ_OP); | |
147 | if (error) { | |
148 | return error; | |
149 | } | |
150 | } | |
151 | } | |
152 | ||
153 | ||
2d21ac55 A |
154 | /* |
155 | * Take an exclusive directory lock since we manipulate the directory hints | |
156 | */ | |
39236c6e | 157 | if ((error = hfs_lock(VTOC(dvp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_DEFAULT))) { |
91447636 | 158 | return (error); |
2d21ac55 | 159 | } |
91447636 A |
160 | dcp = VTOC(dvp); |
161 | hfsmp = VTOHFS(dvp); | |
162 | ||
91447636 | 163 | dir_entries = dcp->c_entries; |
b0d623f7 | 164 | dirchg = dcp->c_dirchangecnt; |
9bccf70c | 165 | |
2d21ac55 | 166 | /* Extract directory index and tag (sequence number) from uio_offset */ |
91447636 A |
167 | index = uio_offset(uio) & HFS_INDEX_MASK; |
168 | tag = uio_offset(uio) & ~HFS_INDEX_MASK; | |
b4c24cb9 | 169 | if ((index + 1) > dir_entries) { |
9bccf70c A |
170 | *(ap->a_eofflag) = 1; |
171 | error = 0; | |
2d21ac55 | 172 | goto exit2; |
9bccf70c A |
173 | } |
174 | ||
175 | /* Get a buffer to hold packed attributes. */ | |
2d21ac55 | 176 | fixedblocksize = (sizeof(u_int32_t) + hfs_attrblksize(alist)); /* 4 bytes for length */ |
9bccf70c A |
177 | maxattrblocksize = fixedblocksize; |
178 | if (alist->commonattr & ATTR_CMN_NAME) | |
179 | maxattrblocksize += kHFSPlusMaxFileNameBytes + 1; | |
180 | MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK); | |
b0d623f7 A |
181 | if (attrbufptr == NULL) { |
182 | error = ENOMEM; | |
183 | goto exit2; | |
184 | } | |
9bccf70c A |
185 | attrptr = attrbufptr; |
186 | varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */ | |
187 | ||
2d21ac55 A |
188 | /* Get a detached directory hint (cnode must be locked exclusive) */ |
189 | dirhint = hfs_getdirhint(dcp, ((index - 1) & HFS_INDEX_MASK) | tag, TRUE); | |
91447636 A |
190 | |
191 | /* Hide tag from catalog layer. */ | |
192 | dirhint->dh_index &= HFS_INDEX_MASK; | |
193 | if (dirhint->dh_index == HFS_INDEX_MASK) { | |
194 | dirhint->dh_index = -1; | |
195 | } | |
196 | ||
197 | /* | |
2d21ac55 A |
198 | * Obtain a list of catalog entries and pack their attributes until |
199 | * the output buffer is full or maxcount entries have been packed. | |
200 | */ | |
201 | ||
202 | /* | |
203 | * Constrain our list size. | |
91447636 | 204 | */ |
2d21ac55 | 205 | maxentries = uio_resid(uio) / (fixedblocksize + HFS_AVERAGE_NAME_SIZE); |
2d21ac55 A |
206 | maxentries = min(maxentries, maxcount); |
207 | maxentries = min(maxentries, MAXCATENTRIES); | |
208 | if (maxentries < 1) { | |
209 | error = EINVAL; | |
210 | goto exit2; | |
91447636 | 211 | } |
2d21ac55 A |
212 | |
213 | /* Initialize a catalog entry list. */ | |
214 | MALLOC(ce_list, struct cat_entrylist *, CE_LIST_SIZE(maxentries), M_TEMP, M_WAITOK); | |
b0d623f7 A |
215 | if (ce_list == NULL) { |
216 | error = ENOMEM; | |
217 | goto exit2; | |
218 | } | |
2d21ac55 A |
219 | bzero(ce_list, CE_LIST_SIZE(maxentries)); |
220 | ce_list->maxentries = maxentries; | |
221 | ||
9bccf70c | 222 | /* |
2d21ac55 | 223 | * Populate the ce_list from the catalog file. |
9bccf70c | 224 | */ |
2d21ac55 A |
225 | lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); |
226 | ||
227 | error = cat_getentriesattr(hfsmp, dirhint, ce_list); | |
228 | /* Don't forget to release the descriptors later! */ | |
229 | ||
230 | hfs_systemfile_unlock(hfsmp, lockflags); | |
231 | ||
232 | if (error == ENOENT) { | |
233 | *(ap->a_eofflag) = TRUE; | |
234 | error = 0; | |
235 | } | |
236 | if (error) { | |
237 | goto exit1; | |
238 | } | |
239 | ||
240 | /* | |
241 | * Drop the directory lock so we don't deadlock when we: | |
242 | * - acquire a child cnode lock | |
243 | * - make calls to vnode_authorize() | |
244 | * - make calls to kauth_cred_ismember_gid() | |
245 | */ | |
246 | hfs_unlock(dcp); | |
247 | dcp = NULL; | |
248 | ||
249 | /* Process the catalog entries. */ | |
250 | for (i = 0; i < (int)ce_list->realentries; ++i) { | |
251 | struct cnode *cp = NULL; | |
252 | struct vnode *vp = NULL; | |
253 | struct cat_desc * cdescp; | |
254 | struct cat_attr * cattrp; | |
255 | struct cat_fork c_datafork; | |
256 | struct cat_fork c_rsrcfork; | |
257 | ||
258 | bzero(&c_datafork, sizeof(c_datafork)); | |
259 | bzero(&c_rsrcfork, sizeof(c_rsrcfork)); | |
260 | cdescp = &ce_list->entry[i].ce_desc; | |
261 | cattrp = &ce_list->entry[i].ce_attr; | |
262 | c_datafork.cf_size = ce_list->entry[i].ce_datasize; | |
263 | c_datafork.cf_blocks = ce_list->entry[i].ce_datablks; | |
264 | c_rsrcfork.cf_size = ce_list->entry[i].ce_rsrcsize; | |
265 | c_rsrcfork.cf_blocks = ce_list->entry[i].ce_rsrcblks; | |
266 | ||
267 | if ((alist->commonattr & ATTR_CMN_USERACCESS) && | |
268 | (cattrp->ca_recflags & kHFSHasSecurityMask)) { | |
9bccf70c | 269 | /* |
2d21ac55 | 270 | * Obtain vnode for our vnode_authorize() calls. |
9bccf70c | 271 | */ |
6d2010ae | 272 | if (hfs_vget(hfsmp, cattrp->ca_fileid, &vp, 0, 0) != 0) { |
9bccf70c | 273 | vp = NULL; |
9bccf70c | 274 | } |
2d21ac55 A |
275 | } else if (!(ap->a_options & FSOPT_NOINMEMUPDATE)) { |
276 | /* Get in-memory cnode data (if any). */ | |
6d2010ae | 277 | vp = hfs_chash_getvnode(hfsmp, cattrp->ca_fileid, 0, 0, 0); |
2d21ac55 A |
278 | } |
279 | if (vp != NULL) { | |
280 | cp = VTOC(vp); | |
281 | /* Only use cnode's decriptor for non-hardlinks */ | |
282 | if (!(cp->c_flag & C_HARDLINK)) | |
283 | cdescp = &cp->c_desc; | |
284 | cattrp = &cp->c_attr; | |
285 | if (cp->c_datafork) { | |
286 | c_datafork.cf_size = cp->c_datafork->ff_size; | |
287 | c_datafork.cf_blocks = cp->c_datafork->ff_blocks; | |
288 | } | |
289 | if (cp->c_rsrcfork) { | |
290 | c_rsrcfork.cf_size = cp->c_rsrcfork->ff_size; | |
291 | c_rsrcfork.cf_blocks = cp->c_rsrcfork->ff_blocks; | |
9bccf70c | 292 | } |
2d21ac55 A |
293 | /* All done with cnode. */ |
294 | hfs_unlock(cp); | |
295 | cp = NULL; | |
296 | } | |
9bccf70c | 297 | |
2d21ac55 A |
298 | *((u_int32_t *)attrptr) = 0; |
299 | attrptr = ((u_int32_t *)attrptr) + 1; | |
300 | attrblk.ab_attrlist = alist; | |
301 | attrblk.ab_attrbufpp = &attrptr; | |
302 | attrblk.ab_varbufpp = &varptr; | |
303 | attrblk.ab_flags = 0; | |
304 | attrblk.ab_blocksize = maxattrblocksize; | |
305 | attrblk.ab_context = ap->a_context; | |
306 | ||
307 | /* Pack catalog entries into attribute buffer. */ | |
b0d623f7 | 308 | hfs_packattrblk(&attrblk, hfsmp, vp, cdescp, cattrp, &c_datafork, &c_rsrcfork, ap->a_context); |
2d21ac55 A |
309 | currattrbufsize = ((char *)varptr - (char *)attrbufptr); |
310 | ||
311 | /* All done with vnode. */ | |
312 | if (vp != NULL) { | |
313 | vnode_put(vp); | |
314 | vp = NULL; | |
315 | } | |
91447636 | 316 | |
2d21ac55 A |
317 | /* Make sure there's enough buffer space remaining. */ |
318 | // LP64todo - fix this! | |
319 | if (uio_resid(uio) < 0 || currattrbufsize > (u_int32_t)uio_resid(uio)) { | |
320 | break; | |
321 | } else { | |
322 | *((u_int32_t *)attrbufptr) = currattrbufsize; | |
323 | error = uiomove((caddr_t)attrbufptr, currattrbufsize, uio); | |
324 | if (error != E_NONE) { | |
325 | break; | |
326 | } | |
327 | attrptr = attrbufptr; | |
328 | /* Point to variable-length storage */ | |
329 | varptr = (char *)attrbufptr + fixedblocksize; | |
330 | /* Save the last valid catalog entry */ | |
331 | lastdescp = &ce_list->entry[i].ce_desc; | |
332 | index++; | |
333 | *ap->a_actualcount += 1; | |
334 | ||
335 | /* Termination checks */ | |
336 | if ((--maxcount <= 0) || | |
337 | // LP64todo - fix this! | |
338 | uio_resid(uio) < 0 || | |
b0d623f7 | 339 | ((u_int32_t)uio_resid(uio) < (fixedblocksize + HFS_AVERAGE_NAME_SIZE))){ |
2d21ac55 | 340 | break; |
9bccf70c A |
341 | } |
342 | } | |
2d21ac55 | 343 | } /* for each catalog entry */ |
9bccf70c | 344 | |
2d21ac55 A |
345 | /* For small directories, check if we're all done. */ |
346 | if (*ap->a_actualcount == (u_long)dir_entries) { | |
347 | *(ap->a_eofflag) = TRUE; | |
348 | } | |
9bccf70c | 349 | |
2d21ac55 A |
350 | /* If we skipped catalog entries for reserved files that should |
351 | * not be listed in namespace, update the index accordingly. | |
352 | */ | |
353 | if (ce_list->skipentries) { | |
354 | index += ce_list->skipentries; | |
355 | ce_list->skipentries = 0; | |
356 | } | |
9bccf70c | 357 | |
2d21ac55 A |
358 | /* If there are more entries then save the last name. */ |
359 | if (index < dir_entries | |
360 | && !(*(ap->a_eofflag)) | |
361 | && lastdescp != NULL) { | |
362 | ||
363 | /* Remember last entry */ | |
364 | if ((dirhint->dh_desc.cd_flags & CD_HASBUF) && | |
365 | (dirhint->dh_desc.cd_nameptr != NULL)) { | |
366 | dirhint->dh_desc.cd_flags &= ~CD_HASBUF; | |
367 | vfs_removename((const char *)dirhint->dh_desc.cd_nameptr); | |
368 | } | |
369 | dirhint->dh_desc.cd_namelen = lastdescp->cd_namelen; | |
370 | dirhint->dh_desc.cd_nameptr = (const u_int8_t *) | |
371 | vfs_addname((const char *)lastdescp->cd_nameptr, lastdescp->cd_namelen, 0, 0); | |
372 | dirhint->dh_desc.cd_flags |= CD_HASBUF; | |
373 | dirhint->dh_index = index - 1; | |
374 | dirhint->dh_desc.cd_cnid = lastdescp->cd_cnid; | |
375 | dirhint->dh_desc.cd_hint = lastdescp->cd_hint; | |
376 | dirhint->dh_desc.cd_encoding = lastdescp->cd_encoding; | |
377 | } else { | |
378 | /* No more entries. */ | |
379 | *(ap->a_eofflag) = TRUE; | |
91447636 | 380 | } |
2d21ac55 A |
381 | |
382 | /* All done with the catalog descriptors. */ | |
383 | for (i = 0; i < (int)ce_list->realentries; ++i) | |
384 | cat_releasedesc(&ce_list->entry[i].ce_desc); | |
385 | ce_list->realentries = 0; | |
386 | ||
39236c6e | 387 | (void) hfs_lock(VTOC(dvp), HFS_EXCLUSIVE_LOCK, HFS_LOCK_ALLOW_NOEXISTS); |
2d21ac55 | 388 | dcp = VTOC(dvp); |
9bccf70c | 389 | |
2d21ac55 A |
390 | exit1: |
391 | /* Pack directory index and tag into uio_offset. */ | |
91447636 A |
392 | while (tag == 0) tag = (++dcp->c_dirhinttag) << HFS_INDEX_BITS; |
393 | uio_setoffset(uio, index | tag); | |
394 | dirhint->dh_index |= tag; | |
9bccf70c | 395 | |
2d21ac55 | 396 | exit2: |
b0d623f7 | 397 | *ap->a_newstate = dirchg; |
2d21ac55 | 398 | |
91447636 | 399 | /* Drop directory hint on error or if there are no more entries */ |
2d21ac55 A |
400 | if (dirhint) { |
401 | if ((error != 0) || (index >= dir_entries) || *(ap->a_eofflag)) | |
402 | hfs_reldirhint(dcp, dirhint); | |
403 | else | |
404 | hfs_insertdirhint(dcp, dirhint); | |
91447636 | 405 | } |
9bccf70c A |
406 | if (attrbufptr) |
407 | FREE(attrbufptr, M_TEMP); | |
408 | if (ce_list) | |
409 | FREE(ce_list, M_TEMP); | |
2d21ac55 | 410 | |
91447636 | 411 | hfs_unlock(dcp); |
9bccf70c A |
412 | return (error); |
413 | } | |
414 | ||
415 | ||
416 | /*==================== Attribute list support routines ====================*/ | |
417 | ||
418 | /* | |
419 | * Pack cnode attributes into an attribute block. | |
420 | */ | |
6d2010ae | 421 | __private_extern__ |
9bccf70c A |
422 | void |
423 | hfs_packattrblk(struct attrblock *abp, | |
424 | struct hfsmount *hfsmp, | |
425 | struct vnode *vp, | |
426 | struct cat_desc *descp, | |
427 | struct cat_attr *attrp, | |
428 | struct cat_fork *datafork, | |
55e303ae | 429 | struct cat_fork *rsrcfork, |
b0d623f7 | 430 | struct vfs_context *ctx) |
2d21ac55 A |
431 | { |
432 | struct attrlist *attrlistp = abp->ab_attrlist; | |
91447636 | 433 | |
2d21ac55 | 434 | if (attrlistp->commonattr) |
b0d623f7 | 435 | packcommonattr(abp, hfsmp, vp, descp, attrp, ctx); |
9bccf70c | 436 | |
2d21ac55 A |
437 | if (attrlistp->dirattr && S_ISDIR(attrp->ca_mode)) |
438 | packdirattr(abp, hfsmp, vp, descp,attrp); | |
439 | ||
440 | if (attrlistp->fileattr && !S_ISDIR(attrp->ca_mode)) | |
b0d623f7 | 441 | packfileattr(abp, hfsmp, attrp, datafork, rsrcfork, vp); |
9bccf70c A |
442 | } |
443 | ||
444 | ||
2d21ac55 A |
445 | static char* |
446 | mountpointname(struct mount *mp) | |
9bccf70c | 447 | { |
2d21ac55 A |
448 | size_t namelength = strlen(mp->mnt_vfsstat.f_mntonname); |
449 | int foundchars = 0; | |
450 | char *c; | |
451 | ||
452 | if (namelength == 0) | |
453 | return (NULL); | |
454 | ||
455 | /* | |
456 | * Look backwards through the name string, looking for | |
457 | * the first slash encountered (which must precede the | |
458 | * last part of the pathname). | |
459 | */ | |
460 | for (c = mp->mnt_vfsstat.f_mntonname + namelength - 1; | |
461 | namelength > 0; --c, --namelength) { | |
462 | if (*c != '/') { | |
463 | foundchars = 1; | |
464 | } else if (foundchars) { | |
465 | return (c + 1); | |
466 | } | |
467 | } | |
468 | ||
469 | return (mp->mnt_vfsstat.f_mntonname); | |
470 | } | |
9bccf70c | 471 | |
9bccf70c | 472 | |
2d21ac55 A |
473 | static void |
474 | packnameattr( | |
475 | struct attrblock *abp, | |
476 | struct vnode *vp, | |
477 | const u_int8_t *name, | |
478 | int namelen) | |
479 | { | |
480 | void *varbufptr; | |
481 | struct attrreference * attr_refptr; | |
482 | char *mpname; | |
483 | size_t mpnamelen; | |
484 | u_int32_t attrlength; | |
485 | u_int8_t empty = 0; | |
9bccf70c | 486 | |
2d21ac55 A |
487 | /* A cnode's name may be incorrect for the root of a mounted |
488 | * filesystem (it can be mounted on a different directory name | |
489 | * than the name of the volume, such as "blah-1"). So for the | |
490 | * root directory, it's best to return the last element of the | |
491 | location where the volume's mounted: | |
492 | */ | |
493 | if ((vp != NULL) && vnode_isvroot(vp) && | |
494 | (mpname = mountpointname(vnode_mount(vp)))) { | |
495 | mpnamelen = strlen(mpname); | |
496 | ||
497 | /* Trim off any trailing slashes: */ | |
498 | while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/')) | |
499 | --mpnamelen; | |
500 | ||
501 | /* If there's anything left, use it instead of the volume's name */ | |
502 | if (mpnamelen > 0) { | |
503 | name = (u_int8_t *)mpname; | |
504 | namelen = mpnamelen; | |
9bccf70c | 505 | } |
9bccf70c | 506 | } |
2d21ac55 A |
507 | if (name == NULL) { |
508 | name = ∅ | |
509 | namelen = 0; | |
9bccf70c | 510 | } |
2d21ac55 A |
511 | |
512 | varbufptr = *abp->ab_varbufpp; | |
513 | attr_refptr = (struct attrreference *)(*abp->ab_attrbufpp); | |
514 | ||
515 | attrlength = namelen + 1; | |
516 | attr_refptr->attr_dataoffset = (char *)varbufptr - (char *)attr_refptr; | |
517 | attr_refptr->attr_length = attrlength; | |
518 | (void) strncpy((char *)varbufptr, (const char *) name, attrlength); | |
519 | /* | |
520 | * Advance beyond the space just allocated and | |
521 | * round up to the next 4-byte boundary: | |
522 | */ | |
523 | varbufptr = ((char *)varbufptr) + attrlength + ((4 - (attrlength & 3)) & 3); | |
524 | ++attr_refptr; | |
525 | ||
526 | *abp->ab_attrbufpp = attr_refptr; | |
9bccf70c A |
527 | *abp->ab_varbufpp = varbufptr; |
528 | } | |
529 | ||
530 | ||
531 | static void | |
532 | packcommonattr( | |
533 | struct attrblock *abp, | |
534 | struct hfsmount *hfsmp, | |
535 | struct vnode *vp, | |
536 | struct cat_desc * cdp, | |
55e303ae | 537 | struct cat_attr * cap, |
b0d623f7 | 538 | struct vfs_context * ctx) |
9bccf70c A |
539 | { |
540 | attrgroup_t attr = abp->ab_attrlist->commonattr; | |
541 | struct mount *mp = HFSTOVFS(hfsmp); | |
542 | void *attrbufptr = *abp->ab_attrbufpp; | |
543 | void *varbufptr = *abp->ab_varbufpp; | |
b0d623f7 | 544 | boolean_t is_64_bit = proc_is64bit(vfs_context_proc(ctx)); |
2d21ac55 A |
545 | uid_t cuid = 1; |
546 | int isroot = 0; | |
547 | ||
548 | if (attr & (ATTR_CMN_OWNERID | ATTR_CMN_GRPID)) { | |
b0d623f7 | 549 | cuid = kauth_cred_getuid(vfs_context_ucred(ctx)); |
2d21ac55 A |
550 | isroot = cuid == 0; |
551 | } | |
9bccf70c A |
552 | |
553 | if (ATTR_CMN_NAME & attr) { | |
91447636 | 554 | packnameattr(abp, vp, cdp->cd_nameptr, cdp->cd_namelen); |
9bccf70c A |
555 | attrbufptr = *abp->ab_attrbufpp; |
556 | varbufptr = *abp->ab_varbufpp; | |
557 | } | |
558 | if (ATTR_CMN_DEVID & attr) { | |
2d21ac55 A |
559 | *((dev_t *)attrbufptr) = hfsmp->hfs_raw_dev; |
560 | attrbufptr = ((dev_t *)attrbufptr) + 1; | |
9bccf70c A |
561 | } |
562 | if (ATTR_CMN_FSID & attr) { | |
91447636 A |
563 | fsid_t fsid; |
564 | ||
39236c6e A |
565 | fsid.val[0] = hfsmp->hfs_raw_dev; |
566 | fsid.val[1] = vfs_typenum(mp); | |
91447636 | 567 | *((fsid_t *)attrbufptr) = fsid; |
2d21ac55 | 568 | attrbufptr = ((fsid_t *)attrbufptr) + 1; |
9bccf70c A |
569 | } |
570 | if (ATTR_CMN_OBJTYPE & attr) { | |
2d21ac55 A |
571 | *((fsobj_type_t *)attrbufptr) = IFTOVT(cap->ca_mode); |
572 | attrbufptr = ((fsobj_type_t *)attrbufptr) + 1; | |
9bccf70c A |
573 | } |
574 | if (ATTR_CMN_OBJTAG & attr) { | |
2d21ac55 A |
575 | *((fsobj_tag_t *)attrbufptr) = VT_HFS; |
576 | attrbufptr = ((fsobj_tag_t *)attrbufptr) + 1; | |
9bccf70c A |
577 | } |
578 | /* | |
579 | * Exporting file IDs from HFS Plus: | |
580 | * | |
581 | * For "normal" files the c_fileid is the same value as the | |
582 | * c_cnid. But for hard link files, they are different - the | |
583 | * c_cnid belongs to the active directory entry (ie the link) | |
584 | * and the c_fileid is for the actual inode (ie the data file). | |
585 | * | |
586 | * The stat call (getattr) will always return the c_fileid | |
587 | * and Carbon APIs, which are hardlink-ignorant, will always | |
588 | * receive the c_cnid (from getattrlist). | |
589 | */ | |
2d21ac55 | 590 | if (ATTR_CMN_OBJID & attr) { |
9bccf70c A |
591 | ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid; |
592 | ((fsobj_id_t *)attrbufptr)->fid_generation = 0; | |
2d21ac55 | 593 | attrbufptr = ((fsobj_id_t *)attrbufptr) + 1; |
9bccf70c A |
594 | } |
595 | if (ATTR_CMN_OBJPERMANENTID & attr) { | |
596 | ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid; | |
597 | ((fsobj_id_t *)attrbufptr)->fid_generation = 0; | |
2d21ac55 | 598 | attrbufptr = ((fsobj_id_t *)attrbufptr) + 1; |
9bccf70c A |
599 | } |
600 | if (ATTR_CMN_PAROBJID & attr) { | |
601 | ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_parentcnid; | |
602 | ((fsobj_id_t *)attrbufptr)->fid_generation = 0; | |
2d21ac55 | 603 | attrbufptr = ((fsobj_id_t *)attrbufptr) + 1; |
9bccf70c A |
604 | } |
605 | if (ATTR_CMN_SCRIPT & attr) { | |
2d21ac55 A |
606 | *((text_encoding_t *)attrbufptr) = cdp->cd_encoding; |
607 | attrbufptr = ((text_encoding_t *)attrbufptr) + 1; | |
9bccf70c A |
608 | } |
609 | if (ATTR_CMN_CRTIME & attr) { | |
91447636 | 610 | if (is_64_bit) { |
b0d623f7 A |
611 | ((struct user64_timespec *)attrbufptr)->tv_sec = cap->ca_itime; |
612 | ((struct user64_timespec *)attrbufptr)->tv_nsec = 0; | |
613 | attrbufptr = ((struct user64_timespec *)attrbufptr) + 1; | |
91447636 A |
614 | } |
615 | else { | |
b0d623f7 A |
616 | ((struct user32_timespec *)attrbufptr)->tv_sec = cap->ca_itime; |
617 | ((struct user32_timespec *)attrbufptr)->tv_nsec = 0; | |
618 | attrbufptr = ((struct user32_timespec *)attrbufptr) + 1; | |
91447636 | 619 | } |
9bccf70c A |
620 | } |
621 | if (ATTR_CMN_MODTIME & attr) { | |
91447636 | 622 | if (is_64_bit) { |
b0d623f7 A |
623 | ((struct user64_timespec *)attrbufptr)->tv_sec = cap->ca_mtime; |
624 | ((struct user64_timespec *)attrbufptr)->tv_nsec = 0; | |
625 | attrbufptr = ((struct user64_timespec *)attrbufptr) + 1; | |
91447636 A |
626 | } |
627 | else { | |
b0d623f7 A |
628 | ((struct user32_timespec *)attrbufptr)->tv_sec = cap->ca_mtime; |
629 | ((struct user32_timespec *)attrbufptr)->tv_nsec = 0; | |
630 | attrbufptr = ((struct user32_timespec *)attrbufptr) + 1; | |
91447636 | 631 | } |
9bccf70c A |
632 | } |
633 | if (ATTR_CMN_CHGTIME & attr) { | |
91447636 | 634 | if (is_64_bit) { |
b0d623f7 A |
635 | ((struct user64_timespec *)attrbufptr)->tv_sec = cap->ca_ctime; |
636 | ((struct user64_timespec *)attrbufptr)->tv_nsec = 0; | |
637 | attrbufptr = ((struct user64_timespec *)attrbufptr) + 1; | |
91447636 A |
638 | } |
639 | else { | |
b0d623f7 A |
640 | ((struct user32_timespec *)attrbufptr)->tv_sec = cap->ca_ctime; |
641 | ((struct user32_timespec *)attrbufptr)->tv_nsec = 0; | |
642 | attrbufptr = ((struct user32_timespec *)attrbufptr) + 1; | |
91447636 | 643 | } |
9bccf70c A |
644 | } |
645 | if (ATTR_CMN_ACCTIME & attr) { | |
91447636 | 646 | if (is_64_bit) { |
b0d623f7 A |
647 | ((struct user64_timespec *)attrbufptr)->tv_sec = cap->ca_atime; |
648 | ((struct user64_timespec *)attrbufptr)->tv_nsec = 0; | |
649 | attrbufptr = ((struct user64_timespec *)attrbufptr) + 1; | |
91447636 A |
650 | } |
651 | else { | |
b0d623f7 A |
652 | ((struct user32_timespec *)attrbufptr)->tv_sec = cap->ca_atime; |
653 | ((struct user32_timespec *)attrbufptr)->tv_nsec = 0; | |
654 | attrbufptr = ((struct user32_timespec *)attrbufptr) + 1; | |
91447636 | 655 | } |
9bccf70c A |
656 | } |
657 | if (ATTR_CMN_BKUPTIME & attr) { | |
91447636 | 658 | if (is_64_bit) { |
b0d623f7 A |
659 | ((struct user64_timespec *)attrbufptr)->tv_sec = cap->ca_btime; |
660 | ((struct user64_timespec *)attrbufptr)->tv_nsec = 0; | |
661 | attrbufptr = ((struct user64_timespec *)attrbufptr) + 1; | |
91447636 A |
662 | } |
663 | else { | |
b0d623f7 A |
664 | ((struct user32_timespec *)attrbufptr)->tv_sec = cap->ca_btime; |
665 | ((struct user32_timespec *)attrbufptr)->tv_nsec = 0; | |
666 | attrbufptr = ((struct user32_timespec *)attrbufptr) + 1; | |
91447636 | 667 | } |
9bccf70c A |
668 | } |
669 | if (ATTR_CMN_FNDRINFO & attr) { | |
6d2010ae | 670 | u_int8_t *finfo = NULL; |
9bccf70c | 671 | bcopy(&cap->ca_finderinfo, attrbufptr, sizeof(u_int8_t) * 32); |
6d2010ae A |
672 | finfo = (u_int8_t*)attrbufptr; |
673 | ||
2d21ac55 A |
674 | /* Don't expose a symlink's private type/creator. */ |
675 | if (S_ISLNK(cap->ca_mode)) { | |
676 | struct FndrFileInfo *fip; | |
677 | ||
678 | fip = (struct FndrFileInfo *)attrbufptr; | |
679 | fip->fdType = 0; | |
680 | fip->fdCreator = 0; | |
681 | } | |
6d2010ae A |
682 | |
683 | /* advance 16 bytes into the attrbuf */ | |
684 | finfo = finfo + 16; | |
39236c6e A |
685 | |
686 | /* also don't expose the date_added or write_gen_counter fields */ | |
687 | if (S_ISREG(cap->ca_mode) || S_ISLNK(cap->ca_mode)) { | |
6d2010ae | 688 | struct FndrExtendedFileInfo *extinfo = (struct FndrExtendedFileInfo *)finfo; |
22ba694c | 689 | extinfo->document_id = 0; |
6d2010ae | 690 | extinfo->date_added = 0; |
39236c6e | 691 | extinfo->write_gen_counter = 0; |
6d2010ae A |
692 | } |
693 | else if (S_ISDIR(cap->ca_mode)) { | |
694 | struct FndrExtendedDirInfo *extinfo = (struct FndrExtendedDirInfo *)finfo; | |
22ba694c | 695 | extinfo->document_id = 0; |
6d2010ae | 696 | extinfo->date_added = 0; |
22ba694c | 697 | extinfo->write_gen_counter = 0; |
6d2010ae A |
698 | } |
699 | ||
2d21ac55 | 700 | attrbufptr = (char *)attrbufptr + sizeof(u_int8_t) * 32; |
9bccf70c A |
701 | } |
702 | if (ATTR_CMN_OWNERID & attr) { | |
2d21ac55 A |
703 | uid_t nuid = cap->ca_uid; |
704 | ||
705 | if (!isroot) { | |
706 | if (((unsigned int)vfs_flags(HFSTOVFS(hfsmp))) & MNT_UNKNOWNPERMISSIONS) | |
707 | nuid = cuid; | |
708 | else if (nuid == UNKNOWNUID) | |
709 | nuid = cuid; | |
710 | } | |
711 | ||
712 | *((uid_t *)attrbufptr) = nuid; | |
713 | attrbufptr = ((uid_t *)attrbufptr) + 1; | |
9bccf70c A |
714 | } |
715 | if (ATTR_CMN_GRPID & attr) { | |
2d21ac55 A |
716 | gid_t ngid = cap->ca_gid; |
717 | ||
718 | if (!isroot) { | |
b0d623f7 | 719 | gid_t cgid = kauth_cred_getgid(vfs_context_ucred(ctx)); |
2d21ac55 A |
720 | if (((unsigned int)vfs_flags(HFSTOVFS(hfsmp))) & MNT_UNKNOWNPERMISSIONS) |
721 | ngid = cgid; | |
722 | else if (ngid == UNKNOWNUID) | |
723 | ngid = cgid; | |
724 | } | |
725 | ||
726 | *((gid_t *)attrbufptr) = ngid; | |
727 | attrbufptr = ((gid_t *)attrbufptr) + 1; | |
9bccf70c A |
728 | } |
729 | if (ATTR_CMN_ACCESSMASK & attr) { | |
730 | /* | |
731 | * [2856576] Since we are dynamically changing the owner, also | |
732 | * effectively turn off the set-user-id and set-group-id bits, | |
733 | * just like chmod(2) would when changing ownership. This prevents | |
734 | * a security hole where set-user-id programs run as whoever is | |
735 | * logged on (or root if nobody is logged in yet!) | |
736 | */ | |
2d21ac55 A |
737 | *((u_int32_t *)attrbufptr) = (cap->ca_uid == UNKNOWNUID) ? |
738 | cap->ca_mode & ~(S_ISUID | S_ISGID) : cap->ca_mode; | |
739 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c A |
740 | } |
741 | if (ATTR_CMN_FLAGS & attr) { | |
2d21ac55 A |
742 | *((u_int32_t *)attrbufptr) = cap->ca_flags; |
743 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c | 744 | } |
22ba694c | 745 | |
9bccf70c | 746 | if (ATTR_CMN_USERACCESS & attr) { |
2d21ac55 A |
747 | u_int32_t user_access; |
748 | ||
749 | /* Take the long path when we have an ACL */ | |
750 | if ((vp != NULLVP) && (cap->ca_recflags & kHFSHasSecurityMask)) { | |
751 | user_access = hfs_real_user_access(vp, abp->ab_context); | |
752 | } else { | |
753 | user_access = DerivePermissionSummary(cap->ca_uid, cap->ca_gid, | |
39236c6e | 754 | cap->ca_mode, mp, vfs_context_ucred(ctx), 0); |
2d21ac55 A |
755 | } |
756 | /* Also consider READ-ONLY file system. */ | |
757 | if (vfs_flags(mp) & MNT_RDONLY) { | |
758 | user_access &= ~W_OK; | |
759 | } | |
760 | /* Locked objects are not writable either */ | |
761 | if ((cap->ca_flags & UF_IMMUTABLE) && (vfs_context_suser(abp->ab_context) != 0)) | |
762 | user_access &= ~W_OK; | |
763 | if ((cap->ca_flags & SF_IMMUTABLE) && (vfs_context_suser(abp->ab_context) == 0)) | |
764 | user_access &= ~W_OK; | |
765 | ||
766 | *((u_int32_t *)attrbufptr) = user_access; | |
767 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
768 | } | |
769 | if (ATTR_CMN_FILEID & attr) { | |
770 | *((u_int64_t *)attrbufptr) = cap->ca_fileid; | |
771 | attrbufptr = ((u_int64_t *)attrbufptr) + 1; | |
772 | } | |
773 | if (ATTR_CMN_PARENTID & attr) { | |
774 | *((u_int64_t *)attrbufptr) = cdp->cd_parentcnid; | |
775 | attrbufptr = ((u_int64_t *)attrbufptr) + 1; | |
9bccf70c A |
776 | } |
777 | ||
778 | *abp->ab_attrbufpp = attrbufptr; | |
779 | *abp->ab_varbufpp = varbufptr; | |
780 | } | |
781 | ||
782 | static void | |
783 | packdirattr( | |
784 | struct attrblock *abp, | |
785 | struct hfsmount *hfsmp, | |
786 | struct vnode *vp, | |
787 | struct cat_desc * descp, | |
91447636 | 788 | struct cat_attr * cattrp) |
9bccf70c A |
789 | { |
790 | attrgroup_t attr = abp->ab_attrlist->dirattr; | |
791 | void *attrbufptr = *abp->ab_attrbufpp; | |
2d21ac55 A |
792 | u_int32_t entries; |
793 | ||
794 | /* | |
795 | * The DIR_LINKCOUNT is the count of real directory hard links. | |
796 | * (i.e. its not the sum of the implied "." and ".." references | |
797 | * typically used in stat's st_nlink field) | |
798 | */ | |
799 | if (ATTR_DIR_LINKCOUNT & attr) { | |
800 | *((u_int32_t *)attrbufptr) = cattrp->ca_linkcount; | |
801 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
802 | } | |
9bccf70c | 803 | if (ATTR_DIR_ENTRYCOUNT & attr) { |
2d21ac55 | 804 | entries = cattrp->ca_entries; |
9bccf70c | 805 | |
91447636 | 806 | if (descp->cd_parentcnid == kHFSRootParentID) { |
2d21ac55 A |
807 | if (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid != 0) |
808 | --entries; /* hide private dir */ | |
809 | if (hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid != 0) | |
b4c24cb9 | 810 | --entries; /* hide private dir */ |
2d21ac55 A |
811 | if (hfsmp->jnl || |
812 | ((hfsmp->vcbAtrb & kHFSVolumeJournaledMask) && | |
813 | (hfsmp->hfs_flags & HFS_READ_ONLY))) | |
b4c24cb9 A |
814 | entries -= 2; /* hide the journal files */ |
815 | } | |
9bccf70c | 816 | |
2d21ac55 A |
817 | *((u_int32_t *)attrbufptr) = entries; |
818 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c A |
819 | } |
820 | if (ATTR_DIR_MOUNTSTATUS & attr) { | |
91447636 | 821 | if (vp != NULL && vnode_mountedhere(vp) != NULL) |
2d21ac55 | 822 | *((u_int32_t *)attrbufptr) = DIR_MNTSTATUS_MNTPOINT; |
9bccf70c | 823 | else |
2d21ac55 A |
824 | *((u_int32_t *)attrbufptr) = 0; |
825 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c A |
826 | } |
827 | *abp->ab_attrbufpp = attrbufptr; | |
828 | } | |
829 | ||
830 | static void | |
831 | packfileattr( | |
832 | struct attrblock *abp, | |
833 | struct hfsmount *hfsmp, | |
834 | struct cat_attr *cattrp, | |
835 | struct cat_fork *datafork, | |
b0d623f7 A |
836 | struct cat_fork *rsrcfork, |
837 | struct vnode *vp) | |
9bccf70c | 838 | { |
b0d623f7 A |
839 | #if !HFS_COMPRESSION |
840 | #pragma unused(vp) | |
841 | #endif | |
9bccf70c A |
842 | attrgroup_t attr = abp->ab_attrlist->fileattr; |
843 | void *attrbufptr = *abp->ab_attrbufpp; | |
844 | void *varbufptr = *abp->ab_varbufpp; | |
2d21ac55 | 845 | u_int32_t allocblksize; |
9bccf70c A |
846 | |
847 | allocblksize = HFSTOVCB(hfsmp)->blockSize; | |
848 | ||
b0d623f7 A |
849 | off_t datasize = datafork->cf_size; |
850 | off_t totalsize = datasize + rsrcfork->cf_size; | |
851 | #if HFS_COMPRESSION | |
6d2010ae A |
852 | int handle_compressed; |
853 | handle_compressed = (cattrp->ca_flags & UF_COMPRESSED);// && hfs_file_is_compressed(VTOC(vp), 1); | |
854 | ||
855 | if (handle_compressed) { | |
b0d623f7 A |
856 | if (attr & (ATTR_FILE_DATALENGTH|ATTR_FILE_TOTALSIZE)) { |
857 | if ( 0 == hfs_uncompressed_size_of_compressed_file(hfsmp, vp, cattrp->ca_fileid, &datasize, 1) ) { /* 1 == don't take the cnode lock */ | |
858 | /* total size of a compressed file is just the data size */ | |
859 | totalsize = datasize; | |
860 | } | |
861 | } | |
862 | } | |
863 | #endif | |
864 | ||
9bccf70c | 865 | if (ATTR_FILE_LINKCOUNT & attr) { |
2d21ac55 A |
866 | *((u_int32_t *)attrbufptr) = cattrp->ca_linkcount; |
867 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c A |
868 | } |
869 | if (ATTR_FILE_TOTALSIZE & attr) { | |
b0d623f7 | 870 | *((off_t *)attrbufptr) = totalsize; |
2d21ac55 | 871 | attrbufptr = ((off_t *)attrbufptr) + 1; |
9bccf70c A |
872 | } |
873 | if (ATTR_FILE_ALLOCSIZE & attr) { | |
2d21ac55 | 874 | *((off_t *)attrbufptr) = |
9bccf70c | 875 | (off_t)cattrp->ca_blocks * (off_t)allocblksize; |
2d21ac55 | 876 | attrbufptr = ((off_t *)attrbufptr) + 1; |
9bccf70c A |
877 | } |
878 | if (ATTR_FILE_IOBLOCKSIZE & attr) { | |
2d21ac55 A |
879 | *((u_int32_t *)attrbufptr) = hfsmp->hfs_logBlockSize; |
880 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c A |
881 | } |
882 | if (ATTR_FILE_CLUMPSIZE & attr) { | |
2d21ac55 A |
883 | *((u_int32_t *)attrbufptr) = hfsmp->vcbClpSiz; |
884 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c A |
885 | } |
886 | if (ATTR_FILE_DEVTYPE & attr) { | |
887 | if (S_ISBLK(cattrp->ca_mode) || S_ISCHR(cattrp->ca_mode)) | |
2d21ac55 | 888 | *((u_int32_t *)attrbufptr) = (u_int32_t)cattrp->ca_rdev; |
9bccf70c | 889 | else |
2d21ac55 A |
890 | *((u_int32_t *)attrbufptr) = 0; |
891 | attrbufptr = ((u_int32_t *)attrbufptr) + 1; | |
9bccf70c | 892 | } |
b0d623f7 | 893 | |
9bccf70c | 894 | if (ATTR_FILE_DATALENGTH & attr) { |
b0d623f7 | 895 | *((off_t *)attrbufptr) = datasize; |
2d21ac55 | 896 | attrbufptr = ((off_t *)attrbufptr) + 1; |
9bccf70c | 897 | } |
b0d623f7 A |
898 | |
899 | #if HFS_COMPRESSION | |
900 | /* fake the data fork size on a decmpfs compressed file to reflect the | |
901 | * uncompressed size. This ensures proper reading and copying of these files. | |
902 | * NOTE: we may need to get the vnode here because the vnode parameter | |
903 | * passed by hfs_vnop_readdirattr() may be null. | |
904 | */ | |
905 | ||
6d2010ae | 906 | if ( handle_compressed ) { |
b0d623f7 A |
907 | if (attr & ATTR_FILE_DATAALLOCSIZE) { |
908 | *((off_t *)attrbufptr) = (off_t)rsrcfork->cf_blocks * (off_t)allocblksize; | |
909 | attrbufptr = ((off_t *)attrbufptr) + 1; | |
910 | } | |
911 | if (attr & ATTR_FILE_RSRCLENGTH) { | |
912 | *((off_t *)attrbufptr) = 0; | |
913 | attrbufptr = ((off_t *)attrbufptr) + 1; | |
914 | } | |
915 | if (attr & ATTR_FILE_RSRCALLOCSIZE) { | |
916 | *((off_t *)attrbufptr) = 0; | |
917 | attrbufptr = ((off_t *)attrbufptr) + 1; | |
918 | } | |
9bccf70c | 919 | } |
b0d623f7 A |
920 | else |
921 | #endif | |
922 | { | |
923 | if (ATTR_FILE_DATAALLOCSIZE & attr) { | |
924 | *((off_t *)attrbufptr) = (off_t)datafork->cf_blocks * (off_t)allocblksize; | |
925 | attrbufptr = ((off_t *)attrbufptr) + 1; | |
926 | } | |
927 | if (ATTR_FILE_RSRCLENGTH & attr) { | |
928 | *((off_t *)attrbufptr) = rsrcfork->cf_size; | |
929 | attrbufptr = ((off_t *)attrbufptr) + 1; | |
930 | } | |
931 | if (ATTR_FILE_RSRCALLOCSIZE & attr) { | |
932 | *((off_t *)attrbufptr) = (off_t)rsrcfork->cf_blocks * (off_t)allocblksize; | |
933 | attrbufptr = ((off_t *)attrbufptr) + 1; | |
934 | } | |
9bccf70c A |
935 | } |
936 | *abp->ab_attrbufpp = attrbufptr; | |
937 | *abp->ab_varbufpp = varbufptr; | |
938 | } | |
939 | ||
9bccf70c A |
940 | /* |
941 | * Calculate the total size of an attribute block. | |
942 | */ | |
6d2010ae | 943 | __private_extern__ |
9bccf70c A |
944 | int |
945 | hfs_attrblksize(struct attrlist *attrlist) | |
946 | { | |
947 | int size; | |
948 | attrgroup_t a; | |
91447636 A |
949 | int sizeof_timespec; |
950 | boolean_t is_64_bit = proc_is64bit(current_proc()); | |
9bccf70c | 951 | |
91447636 | 952 | if (is_64_bit) |
b0d623f7 | 953 | sizeof_timespec = sizeof(struct user64_timespec); |
91447636 | 954 | else |
b0d623f7 | 955 | sizeof_timespec = sizeof(struct user32_timespec); |
91447636 | 956 | |
9bccf70c A |
957 | DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0); |
958 | ||
9bccf70c A |
959 | DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0); |
960 | ||
9bccf70c A |
961 | DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0); |
962 | ||
9bccf70c A |
963 | DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0); |
964 | ||
9bccf70c A |
965 | DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0); |
966 | ||
967 | size = 0; | |
968 | ||
969 | if ((a = attrlist->commonattr) != 0) { | |
2d21ac55 | 970 | if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference); |
9bccf70c A |
971 | if (a & ATTR_CMN_DEVID) size += sizeof(dev_t); |
972 | if (a & ATTR_CMN_FSID) size += sizeof(fsid_t); | |
973 | if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t); | |
974 | if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t); | |
975 | if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t); | |
976 | if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t); | |
977 | if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t); | |
978 | if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t); | |
2d21ac55 A |
979 | if (a & ATTR_CMN_CRTIME) size += sizeof_timespec; |
980 | if (a & ATTR_CMN_MODTIME) size += sizeof_timespec; | |
981 | if (a & ATTR_CMN_CHGTIME) size += sizeof_timespec; | |
982 | if (a & ATTR_CMN_ACCTIME) size += sizeof_timespec; | |
983 | if (a & ATTR_CMN_BKUPTIME) size += sizeof_timespec; | |
9bccf70c A |
984 | if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(u_int8_t); |
985 | if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t); | |
986 | if (a & ATTR_CMN_GRPID) size += sizeof(gid_t); | |
2d21ac55 A |
987 | if (a & ATTR_CMN_ACCESSMASK) size += sizeof(u_int32_t); |
988 | if (a & ATTR_CMN_FLAGS) size += sizeof(u_int32_t); | |
989 | if (a & ATTR_CMN_USERACCESS) size += sizeof(u_int32_t); | |
990 | if (a & ATTR_CMN_FILEID) size += sizeof(u_int64_t); | |
991 | if (a & ATTR_CMN_PARENTID) size += sizeof(u_int64_t); | |
992 | } | |
9bccf70c | 993 | if ((a = attrlist->dirattr) != 0) { |
2d21ac55 A |
994 | if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_int32_t); |
995 | if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(u_int32_t); | |
996 | if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(u_int32_t); | |
997 | } | |
9bccf70c | 998 | if ((a = attrlist->fileattr) != 0) { |
2d21ac55 | 999 | if (a & ATTR_FILE_LINKCOUNT) size += sizeof(u_int32_t); |
9bccf70c A |
1000 | if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t); |
1001 | if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t); | |
2d21ac55 A |
1002 | if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(u_int32_t); |
1003 | if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(u_int32_t); | |
1004 | if (a & ATTR_FILE_DEVTYPE) size += sizeof(u_int32_t); | |
9bccf70c A |
1005 | if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t); |
1006 | if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t); | |
9bccf70c A |
1007 | if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t); |
1008 | if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t); | |
2d21ac55 | 1009 | } |
9bccf70c | 1010 | |
2d21ac55 | 1011 | return (size); |
9bccf70c A |
1012 | } |
1013 | ||
2d21ac55 A |
1014 | #define KAUTH_DIR_WRITE_RIGHTS (KAUTH_VNODE_ACCESS | KAUTH_VNODE_ADD_FILE | \ |
1015 | KAUTH_VNODE_ADD_SUBDIRECTORY | \ | |
1016 | KAUTH_VNODE_DELETE_CHILD) | |
1017 | ||
1018 | #define KAUTH_DIR_READ_RIGHTS (KAUTH_VNODE_ACCESS | KAUTH_VNODE_LIST_DIRECTORY) | |
1019 | ||
1020 | #define KAUTH_DIR_EXECUTE_RIGHTS (KAUTH_VNODE_ACCESS | KAUTH_VNODE_SEARCH) | |
1021 | ||
1022 | #define KAUTH_FILE_WRITE_RIGHTS (KAUTH_VNODE_ACCESS | KAUTH_VNODE_WRITE_DATA) | |
1023 | ||
1024 | #define KAUTH_FILE_READRIGHTS (KAUTH_VNODE_ACCESS | KAUTH_VNODE_READ_DATA) | |
1025 | ||
1026 | #define KAUTH_FILE_EXECUTE_RIGHTS (KAUTH_VNODE_ACCESS | KAUTH_VNODE_EXECUTE) | |
1027 | ||
1028 | ||
1029 | /* | |
1030 | * Compute the same [expensive] user_access value as getattrlist does | |
1031 | */ | |
1032 | static u_int32_t | |
1033 | hfs_real_user_access(vnode_t vp, vfs_context_t ctx) | |
1034 | { | |
1035 | u_int32_t user_access = 0; | |
1036 | ||
1037 | if (vnode_isdir(vp)) { | |
1038 | if (vnode_authorize(vp, NULLVP, KAUTH_DIR_WRITE_RIGHTS, ctx) == 0) | |
1039 | user_access |= W_OK; | |
1040 | if (vnode_authorize(vp, NULLVP, KAUTH_DIR_READ_RIGHTS, ctx) == 0) | |
1041 | user_access |= R_OK; | |
1042 | if (vnode_authorize(vp, NULLVP, KAUTH_DIR_EXECUTE_RIGHTS, ctx) == 0) | |
1043 | user_access |= X_OK; | |
1044 | } else { | |
1045 | if (vnode_authorize(vp, NULLVP, KAUTH_FILE_WRITE_RIGHTS, ctx) == 0) | |
1046 | user_access |= W_OK; | |
1047 | if (vnode_authorize(vp, NULLVP, KAUTH_FILE_READRIGHTS, ctx) == 0) | |
1048 | user_access |= R_OK; | |
1049 | if (vnode_authorize(vp, NULLVP, KAUTH_FILE_EXECUTE_RIGHTS, ctx) == 0) | |
1050 | user_access |= X_OK; | |
1051 | } | |
1052 | return (user_access); | |
1053 | } | |
1054 | ||
9bccf70c | 1055 | |
b0d623f7 | 1056 | u_int32_t |
9bccf70c | 1057 | DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode, |
2d21ac55 | 1058 | struct mount *mp, kauth_cred_t cred, __unused struct proc *p) |
9bccf70c | 1059 | { |
b0d623f7 | 1060 | u_int32_t permissions; |
9bccf70c A |
1061 | |
1062 | if (obj_uid == UNKNOWNUID) | |
2d21ac55 | 1063 | obj_uid = kauth_cred_getuid(cred); |
9bccf70c A |
1064 | |
1065 | /* User id 0 (root) always gets access. */ | |
91447636 | 1066 | if (!suser(cred, NULL)) { |
9bccf70c A |
1067 | permissions = R_OK | W_OK | X_OK; |
1068 | goto Exit; | |
1069 | }; | |
1070 | ||
1071 | /* Otherwise, check the owner. */ | |
2d21ac55 | 1072 | if (hfs_owner_rights(VFSTOHFS(mp), obj_uid, cred, NULL, false) == 0) { |
b0d623f7 | 1073 | permissions = ((u_int32_t)obj_mode & S_IRWXU) >> 6; |
9bccf70c A |
1074 | goto Exit; |
1075 | } | |
1076 | ||
1077 | /* Otherwise, check the groups. */ | |
91447636 A |
1078 | if (! (((unsigned int)vfs_flags(mp)) & MNT_UNKNOWNPERMISSIONS)) { |
1079 | int is_member; | |
1080 | ||
1081 | if (kauth_cred_ismember_gid(cred, obj_gid, &is_member) == 0 && is_member) { | |
b0d623f7 | 1082 | permissions = ((u_int32_t)obj_mode & S_IRWXG) >> 3; |
91447636 | 1083 | goto Exit; |
9bccf70c A |
1084 | } |
1085 | } | |
1086 | ||
1087 | /* Otherwise, settle for 'others' access. */ | |
b0d623f7 | 1088 | permissions = (u_int32_t)obj_mode & S_IRWXO; |
9bccf70c A |
1089 | |
1090 | Exit: | |
1091 | return (permissions); | |
1092 | } | |
1093 |