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