]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_attrlist.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_attrlist.c
CommitLineData
9bccf70c 1/*
8ad349bb 2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
9bccf70c 3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
9bccf70c 5 *
8ad349bb
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
9bccf70c
A
29 */
30
31/*
32 * hfs_attrlist.c - HFS attribute list processing
33 *
34 * Copyright (c) 1998-2002, Apple Computer, Inc. All Rights Reserved.
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/attr.h>
42#include <sys/stat.h>
43#include <sys/unistd.h>
91447636
A
44#include <sys/mount_internal.h>
45#include <sys/kauth.h>
46
47#include <kern/locks.h>
9bccf70c
A
48
49#include "hfs.h"
50#include "hfs_cnode.h"
51#include "hfs_mount.h"
52#include "hfs_dbg.h"
53#include "hfs_attrlist.h"
54
55
56
9bccf70c 57/* Routines that are shared by hfs_setattr: */
91447636 58extern int hfs_write_access(struct vnode *vp, kauth_cred_t cred,
9bccf70c
A
59 struct proc *p, Boolean considerFlags);
60
91447636 61extern int hfs_chflags(struct vnode *vp, uint32_t flags, kauth_cred_t cred,
9bccf70c
A
62 struct proc *p);
63
91447636 64extern int hfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred,
9bccf70c
A
65 struct proc *p);
66
91447636 67extern int hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
9bccf70c
A
68 struct proc *p);
69
91447636 70__private_extern__ int hfs_vnop_readdirattr(struct vnop_readdirattr_args *ap);
9bccf70c 71
91447636 72__private_extern__ int hfs_vnop_setattrlist(struct vnop_setattrlist_args *ap);
9bccf70c 73
91447636 74__private_extern__ int hfs_vnop_getattrlist(struct vnop_getattrlist_args *ap);
9bccf70c
A
75
76/* Packing routines: */
77
78
79static void packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp,
55e303ae 80 struct vnode *vp, struct proc *p);
9bccf70c
A
81
82static void packvolattr(struct attrblock *abp, struct hfsmount *hfsmp,
91447636 83 struct vnode *vp);
9bccf70c
A
84
85static void packcommonattr(struct attrblock *abp, struct hfsmount *hfsmp,
86 struct vnode *vp, struct cat_desc * cdp,
55e303ae 87 struct cat_attr * cap, struct proc *p);
9bccf70c
A
88
89static void packfileattr(struct attrblock *abp, struct hfsmount *hfsmp,
90 struct cat_attr *cattrp, struct cat_fork *datafork,
91447636 91 struct cat_fork *rsrcfork);
9bccf70c
A
92
93static void packdirattr(struct attrblock *abp, struct hfsmount *hfsmp,
94 struct vnode *vp, struct cat_desc * descp,
91447636 95 struct cat_attr * cattrp);
9bccf70c 96
91447636
A
97
98#if 0
99static int unpackattrblk(struct attrblock *abp, struct vnode *vp);
9bccf70c
A
100
101static void unpackcommonattr(struct attrblock *abp, struct vnode *vp);
102
91447636
A
103static int unpackvolattr(struct attrblock *abp, struct hfsmount *hfsmp,
104 struct vnode *root_vp);
9bccf70c
A
105
106
107/*
91447636 108 * Get a list of attributes.
9bccf70c
A
109 */
110__private_extern__
111int
91447636
A
112hfs_vnop_getattrlist(ap)
113 struct vnop_getattrlist_args /* {
9bccf70c
A
114 struct vnode *a_vp;
115 struct attrlist *a_alist
116 struct uio *a_uio;
91447636
A
117 int a_options;
118 vfs_context_t a_context;
9bccf70c
A
119 } */ *ap;
120{
121 struct vnode *vp = ap->a_vp;
91447636
A
122 struct cnode *cp;
123 struct hfsmount *hfsmp;
9bccf70c 124 struct attrlist *alist = ap->a_alist;
91447636 125 proc_t p = vfs_context_proc(ap->a_context);
9bccf70c
A
126 int fixedblocksize;
127 int attrblocksize;
128 int attrbufsize;
91447636 129 void *attrbufptr = NULL;
9bccf70c
A
130 void *attrptr;
131 void *varptr;
132 struct attrblock attrblk;
133 struct cat_fork *datafp = NULL;
134 struct cat_fork *rsrcfp = NULL;
91447636
A
135 struct cat_fork rsrcfork;
136 int lockflags;
9bccf70c
A
137 int error = 0;
138
139 if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
140 ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
141 ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) ||
142 ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
143 ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0)) {
144 return (EINVAL);
145 }
146
147 /*
148 * Requesting volume information requires setting the
149 * ATTR_VOL_INFO bit. Also, volume info requests are
150 * mutually exclusive with all other info requests.
151 */
152 if ((alist->volattr != 0) &&
153 (((alist->volattr & ATTR_VOL_INFO) == 0) ||
154 (alist->dirattr != 0) || (alist->fileattr != 0))) {
155 return (EINVAL);
156 }
157
158 /* Reject requests for unsupported options for now: */
159 if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) ||
160 (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) {
161 return (EINVAL);
162 }
163
91447636
A
164 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
165 return (error);
166 cp = VTOC(vp);
167 hfsmp = VTOHFS(vp);
9bccf70c 168
91447636
A
169 /* Requesting volume information requires root vnode */
170 if ((alist->volattr) && cp->c_fileid != kHFSRootFolderID) {
171 error = EINVAL;
172 goto exit;
173 }
9bccf70c 174 /* Asking for data fork attributes from the rsrc fork is not supported */
91447636
A
175 if (VNODE_IS_RSRC(vp) && (alist->fileattr & ATTR_DATAFORK_MASK)) {
176 error = EINVAL;
177 goto exit;
178 }
9bccf70c 179 /* This file no longer exists! */
91447636
A
180 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
181 error = ENOENT;
182 goto exit;
183 }
9bccf70c 184 /* This file doesn't have a name! */
91447636
A
185 if ((cp->c_desc.cd_namelen == 0) && (alist->commonattr & ATTR_CMN_NAME)) {
186 error = ENOENT;
187 goto exit;
188 }
9bccf70c
A
189
190 /* Update cnode times if needed */
91447636 191 hfs_touchtimes(hfsmp, cp);
9bccf70c
A
192
193 /*
194 * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on
195 * an HFS volume we must be sure to create the thread
196 * record before returning it. (yikes)
197 */
91447636 198 if (vnode_isreg(vp) &&
9bccf70c
A
199 (alist->commonattr & ATTR_CMN_OBJPERMANENTID) &&
200 (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord)) {
201
91447636 202 cat_cookie_t cookie;
9bccf70c 203
91447636
A
204 if (hfsmp->hfs_flags & HFS_READ_ONLY) {
205 error = EROFS;
206 goto exit;
207 }
208 if ((error = hfs_write_access(vp, vfs_context_ucred(ap->a_context),
209 p, false)) != 0) {
210 goto exit;
211 }
55e303ae
A
212 /*
213 * Reserve some space in the Catalog file.
214 */
91447636
A
215 bzero(&cookie, sizeof(cookie));
216 error = cat_preflight(hfsmp, CAT_CREATE, &cookie, p);
b4c24cb9 217 if (error) {
91447636
A
218 goto exit;
219 }
220
221 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
9bccf70c
A
222
223 error = cat_insertfilethread(hfsmp, &cp->c_desc);
224
91447636 225 hfs_systemfile_unlock(hfsmp, lockflags);
b4c24cb9 226
91447636 227 cat_postflight(hfsmp, &cookie, p);
b4c24cb9 228
9bccf70c 229 if (error)
91447636 230 goto exit;
9bccf70c 231 }
91447636 232 bzero(&rsrcfork, sizeof(rsrcfork));
9bccf70c
A
233 /* Establish known fork data */
234 if (cp->c_datafork != NULL) {
235 datafp = &cp->c_datafork->ff_data;
236 if ((cp->c_rsrcfork == NULL) &&
237 (cp->c_blocks == datafp->cf_blocks))
238 rsrcfp = &rsrcfork; /* rsrc fork is empty */
239 }
240 if (cp->c_rsrcfork != NULL)
241 rsrcfp = &cp->c_rsrcfork->ff_data;
242
243 /*
244 * When resource fork data is requested and its not available
245 * in the cnode and the fork is not empty then it needs to be
246 * fetched from the catalog.
247 */
248 if ((alist->fileattr & ATTR_RSRCFORK_MASK) && (rsrcfp == NULL)) {
91447636
A
249
250 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
9bccf70c
A
251
252 /* Get resource fork data */
253 error = cat_lookup(hfsmp, &cp->c_desc, 1,
91447636
A
254 (struct cat_desc *)0, (struct cat_attr *)0, &rsrcfork, NULL);
255
256 hfs_systemfile_unlock(hfsmp, lockflags);
9bccf70c 257
9bccf70c 258 if (error)
91447636 259 goto exit;
9bccf70c
A
260
261 rsrcfp = &rsrcfork;
262 }
263
264 fixedblocksize = hfs_attrblksize(alist);
91447636 265 attrblocksize = fixedblocksize + (sizeof(uint32_t)); /* uint32_t for length word */
9bccf70c
A
266 if (alist->commonattr & ATTR_CMN_NAME)
267 attrblocksize += kHFSPlusMaxFileNameBytes + 1;
268 if (alist->volattr & ATTR_VOL_MOUNTPOINT)
269 attrblocksize += PATH_MAX;
270 if (alist->volattr & ATTR_VOL_NAME)
271 attrblocksize += kHFSPlusMaxFileNameBytes + 1;
272#if 0
273 if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST)
274 attrblocksize += 0;
275 if (alist->fileattr & ATTR_FILE_FORKLIST)
276 attrblocksize += 0;
277#endif
91447636 278 attrbufsize = MIN(uio_resid(ap->a_uio), attrblocksize);
9bccf70c
A
279 MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
280 attrptr = attrbufptr;
91447636
A
281 *((uint32_t *)attrptr) = 0; /* Set buffer length in case of errors */
282 ++((uint32_t *)attrptr); /* Reserve space for length field */
9bccf70c
A
283 varptr = ((char *)attrptr) + fixedblocksize;
284
285 attrblk.ab_attrlist = alist;
286 attrblk.ab_attrbufpp = &attrptr;
287 attrblk.ab_varbufpp = &varptr;
288 attrblk.ab_flags = 0;
289 attrblk.ab_blocksize = attrblocksize;
290
291 hfs_packattrblk(&attrblk, hfsmp, vp, &cp->c_desc, &cp->c_attr,
91447636 292 datafp, rsrcfp, p);
9bccf70c
A
293
294 /* Don't copy out more data than was generated */
91447636 295 attrbufsize = MIN((u_int)attrbufsize, (u_int)varptr - (u_int)attrbufptr);
9bccf70c 296 /* Set actual buffer length for return to caller */
91447636 297 *((uint32_t *)attrbufptr) = attrbufsize;
9bccf70c 298 error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio);
91447636
A
299exit:
300 if (attrbufptr)
301 FREE(attrbufptr, M_TEMP);
302 hfs_unlock(cp);
9bccf70c
A
303 return (error);
304}
305
306
307/*
91447636 308 * Set a list of attributes.
9bccf70c
A
309 */
310__private_extern__
311int
91447636
A
312hfs_vnop_setattrlist(ap)
313 struct vnop_setattrlist_args /* {
9bccf70c
A
314 struct vnode *a_vp;
315 struct attrlist *a_alist
316 struct uio *a_uio;
91447636
A
317 int a_options;
318 vfs_context_t a_context;
9bccf70c
A
319 } */ *ap;
320{
321 struct vnode *vp = ap->a_vp;
91447636
A
322 struct cnode *cp;
323 struct hfsmount * hfsmp;
9bccf70c 324 struct attrlist *alist = ap->a_alist;
91447636
A
325 kauth_cred_t cred = vfs_context_ucred(ap->a_context);
326 struct proc *p = vfs_context_proc(ap->a_context);
9bccf70c
A
327 int attrblocksize;
328 void *attrbufptr = NULL;
329 void *attrptr;
330 void *varptr = NULL;
331 struct attrblock attrblk;
332 uid_t saved_uid;
333 gid_t saved_gid;
334 mode_t saved_mode;
91447636 335 uint32_t saved_flags;
9bccf70c
A
336 int error = 0;
337
91447636
A
338 hfsmp = VTOHFS(vp);
339
55e303ae 340 if (hfsmp->hfs_flags & HFS_READ_ONLY)
9bccf70c
A
341 return (EROFS);
342 if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
343 ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) ||
344 ((alist->volattr & ~ATTR_VOL_SETMASK) != 0) ||
345 ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0) ||
346 ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0)) {
347 return (EINVAL);
348 }
91447636
A
349 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK)))
350 return (error);
351 cp = VTOC(vp);
352
9bccf70c
A
353 /*
354 * When setting volume attributes make sure
355 * that ATTR_VOL_INFO is set and that all
356 * the attributes are valid.
357 */
358 if ((alist->volattr != 0) &&
359 (((alist->volattr & ATTR_VOL_INFO) == 0) ||
360 (alist->commonattr & ~ATTR_CMN_VOLSETMASK) ||
91447636 361 (cp->c_fileid != kHFSRootFolderID))) {
9bccf70c
A
362 if ((alist->volattr & ATTR_VOL_INFO) == 0)
363 printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
364 else
365 printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
366 alist->commonattr & ~ATTR_CMN_VOLSETMASK);
91447636
A
367 error = EINVAL;
368 goto ErrorExit;
369 }
370 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
371 error = ENOENT;
372 goto ErrorExit;
9bccf70c 373 }
b4c24cb9
A
374 // XXXdbg - don't allow modifying the journal or journal_info_block
375 if (hfsmp->jnl && cp->c_datafork) {
376 struct HFSPlusExtentDescriptor *extd;
377
55e303ae 378 extd = &cp->c_datafork->ff_extents[0];
b4c24cb9 379 if (extd->startBlock == HFSTOVCB(hfsmp)->vcbJinfoBlock || extd->startBlock == hfsmp->jnl_start) {
91447636
A
380 error = EPERM;
381 goto ErrorExit;
b4c24cb9
A
382 }
383 }
384
9bccf70c
A
385 /*
386 * Ownership of a file is required in one of two classes of calls:
387 *
388 * (a) When setting any ownership-requiring attribute other
389 * than ATTR_CMN_FLAGS, or
390 * (b) When setting ATTR_CMN_FLAGS on a volume that's not
391 * plain HFS (for which no real per-object ownership
392 * information is stored)
393 */
394 if ((alist->commonattr & (ATTR_OWNERSHIP_SETMASK & ~ATTR_CMN_FLAGS)) ||
395 ((alist->commonattr & ATTR_CMN_FLAGS) &&
396 (VTOVCB(vp)->vcbSigWord != kHFSSigWord))) {
397 /*
398 * NOTE: The following isn't ENTIRELY complete: even if
399 * you're the superuser you cannot change the flags as
400 * long as SF_IMMUTABLE or SF_APPEND is set and the
401 * securelevel > 0. This is verified in hfs_chflags
402 * which gets invoked to do the actual flags field
403 * change so this check is sufficient for now.
404 */
405 if ((error = hfs_owner_rights(hfsmp, cp->c_uid, cred, p, true)) != 0)
91447636 406 goto ErrorExit;
9bccf70c
A
407 }
408 /*
409 * For any other attributes, check to see if the user has
91447636 410 * write access to the cnode in question [unlike vn_access,
9bccf70c
A
411 * ignore IMMUTABLE here]:
412 */
413 if (((alist->commonattr & ~ATTR_OWNERSHIP_SETMASK) != 0) ||
414 (alist->volattr != 0) || (alist->dirattr != 0) ||
415 (alist->fileattr != 0)) {
416 if ((error = hfs_write_access(vp, cred, p, false)) != 0)
91447636 417 goto ErrorExit;
9bccf70c
A
418 }
419
420 /*
421 * Allocate the buffer now to minimize the time we might
422 * be blocked holding the catalog lock.
423 */
91447636
A
424 // LP64todo - fix this
425 attrblocksize = uio_resid(ap->a_uio);
426 if (attrblocksize < hfs_attrblksize(alist)) {
427 error = EINVAL;
428 goto ErrorExit;
429 }
9bccf70c
A
430
431 MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK);
432
433 error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio);
434 if (error)
435 goto ErrorExit;
436
437 /* Save original state so changes can be detected. */
438 saved_uid = cp->c_uid;
439 saved_gid = cp->c_gid;
440 saved_mode = cp->c_mode;
441 saved_flags = cp->c_flags;
442
443 attrptr = attrbufptr;
444 attrblk.ab_attrlist = alist;
445 attrblk.ab_attrbufpp = &attrptr;
446 attrblk.ab_varbufpp = &varptr;
447 attrblk.ab_flags = 0;
448 attrblk.ab_blocksize = attrblocksize;
91447636
A
449 error = unpackattrblk(&attrblk, vp);
450 if (error)
451 goto ErrorExit;
9bccf70c
A
452
453 /* If unpacking changed the owner/group then call hfs_chown() */
454 if ((saved_uid != cp->c_uid) || (saved_gid != cp->c_gid)) {
455 uid_t uid;
456 gid_t gid;
457
458 uid = cp->c_uid;
459 cp->c_uid = saved_uid;
460 gid = cp->c_gid;
461 cp->c_gid = saved_gid;
462 if ((error = hfs_chown(vp, uid, gid, cred, p)))
463 goto ErrorExit;
464 }
465 /* If unpacking changed the mode then call hfs_chmod() */
466 if (saved_mode != cp->c_mode) {
467 mode_t mode;
468
469 mode = cp->c_mode;
470 cp->c_mode = saved_mode;
471 if ((error = hfs_chmod(vp, mode, cred, p)))
472 goto ErrorExit;
473 }
474 /* If unpacking changed the flags then call hfs_chflags() */
475 if (saved_flags !=cp->c_flags) {
91447636 476 uint32_t flags;
9bccf70c
A
477
478 flags = cp->c_flags;
479 cp->c_flags = saved_flags;
480 if ((error = hfs_chflags(vp, flags, cred, p)))
481 goto ErrorExit;
482 }
483 /*
484 * If any cnode attributes changed then do an update.
485 */
486 if (alist->volattr == 0) {
9bccf70c 487 cp->c_flag |= C_MODIFIED;
91447636 488 if ((error = hfs_update(vp, TRUE))) {
9bccf70c 489 goto ErrorExit;
91447636 490 }
9bccf70c
A
491 }
492 /* Volume Rename */
493 if (alist->volattr & ATTR_VOL_NAME) {
494 ExtendedVCB *vcb = VTOVCB(vp);
495
496 if (vcb->vcbVN[0] == 0) {
497 /*
498 * Ignore attempts to rename a volume to a zero-length name:
499 * restore the original name from the cnode.
500 */
501 copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
502 } else {
91447636
A
503 struct cat_desc to_desc;
504 struct cat_desc todir_desc;
505 struct cat_desc new_desc;
506 cat_cookie_t cookie;
55e303ae
A
507 int catreserve = 0;
508 int catlocked = 0;
509 int started_tr = 0;
91447636
A
510 int lockflags;
511
512 bzero(&to_desc, sizeof(to_desc));
513 bzero(&todir_desc, sizeof(todir_desc));
514 bzero(&new_desc, sizeof(new_desc));
515 bzero(&cookie, sizeof(cookie));
9bccf70c 516
91447636
A
517 todir_desc.cd_parentcnid = kHFSRootParentID;
518 todir_desc.cd_cnid = kHFSRootFolderID;
9bccf70c
A
519 todir_desc.cd_flags = CD_ISDIR;
520
521 to_desc.cd_nameptr = vcb->vcbVN;
522 to_desc.cd_namelen = strlen(vcb->vcbVN);
91447636 523 to_desc.cd_parentcnid = kHFSRootParentID;
9bccf70c
A
524 to_desc.cd_cnid = cp->c_cnid;
525 to_desc.cd_flags = CD_ISDIR;
526
91447636
A
527 if ((error = hfs_start_transaction(hfsmp) != 0)) {
528 goto rename_out;
b4c24cb9 529 }
91447636 530 started_tr = 1;
b4c24cb9 531
55e303ae
A
532 /*
533 * Reserve some space in the Catalog file.
534 */
535 error = cat_preflight(hfsmp, CAT_RENAME, &cookie, p);
536 if (error) {
537 goto rename_out;
538 }
539 catreserve = 1;
b4c24cb9 540
91447636 541 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK);
55e303ae 542 catlocked = 1;
9bccf70c
A
543
544 error = cat_rename(hfsmp, &cp->c_desc, &todir_desc, &to_desc, &new_desc);
55e303ae
A
545rename_out:
546 if (catlocked) {
91447636 547 hfs_systemfile_unlock(hfsmp, lockflags);
55e303ae
A
548 }
549 if (catreserve) {
550 cat_postflight(hfsmp, &cookie, p);
551 }
91447636 552 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
55e303ae 553 if (started_tr) {
91447636 554 hfs_end_transaction(hfsmp);
b4c24cb9 555 }
b4c24cb9 556
9bccf70c
A
557 if (error) {
558 /* Restore the old name in the VCB */
559 copystr(cp->c_desc.cd_nameptr, vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
560 vcb->vcbFlags |= 0xFF00;
561 goto ErrorExit;
562 }
563 /* Release old allocated name buffer */
564 if (cp->c_desc.cd_flags & CD_HASBUF) {
565 char *name = cp->c_desc.cd_nameptr;
566
567 cp->c_desc.cd_nameptr = 0;
568 cp->c_desc.cd_namelen = 0;
569 cp->c_desc.cd_flags &= ~CD_HASBUF;
91447636 570 vfs_removename(name);
9bccf70c
A
571 }
572 /* Update cnode's catalog descriptor */
573 replace_desc(cp, &new_desc);
574 vcb->volumeNameEncodingHint = new_desc.cd_encoding;
91447636 575 cp->c_touch_chgtime = TRUE;
9bccf70c
A
576 }
577 }
578
579 /*
580 * When the volume name changes or the volume's finder info
581 * changes then force them to disk immediately.
582 */
583 if ((alist->volattr & ATTR_VOL_INFO) &&
584 ((alist->volattr & ATTR_VOL_NAME) ||
585 (alist->commonattr & ATTR_CMN_FNDRINFO))) {
586 (void) hfs_flushvolumeheader(hfsmp, MNT_WAIT, 0);
587 }
588ErrorExit:
589 if (attrbufptr)
590 FREE(attrbufptr, M_TEMP);
591
91447636 592 hfs_unlock(cp);
9bccf70c
A
593 return (error);
594}
91447636 595#endif
9bccf70c
A
596
597/*
598 * readdirattr operation will return attributes for the items in the
599 * directory specified.
600 *
601 * It does not do . and .. entries. The problem is if you are at the root of the
602 * hfs directory and go to .. you could be crossing a mountpoint into a
603 * different (ufs) file system. The attributes that apply for it may not
604 * apply for the file system you are doing the readdirattr on. To make life
605 * simpler, this call will only return entries in its directory, hfs like.
606 * TO DO LATER:
607 * 1. more than one for uiovcnt support.
608 * 2. put knohint (hints) in state for next call in
609 * 3. credentials checking when rest of hfs does it.
610 * 4. Do return permissions concatenation ???
611 */
612
613/*
614#
615#% readdirattr vp L L L
616#
91447636 617vnop_readdirattr {
9bccf70c
A
618 IN struct vnode *vp;
619 IN struct attrlist *alist;
620 INOUT struct uio *uio;
621 IN u_long maxcount:
622 IN u_long options;
623 OUT u_long *newstate;
624 OUT int *eofflag;
625 OUT u_long *actualCount;
626 OUT u_long **cookies;
91447636 627 IN kauth_cred_t cred;
9bccf70c
A
628};
629*/
630__private_extern__
631int
91447636
A
632hfs_vnop_readdirattr(ap)
633 struct vnop_readdirattr_args /* {
9bccf70c
A
634 struct vnode *a_vp;
635 struct attrlist *a_alist;
636 struct uio *a_uio;
637 u_long a_maxcount;
638 u_long a_options;
639 u_long *a_newstate;
640 int *a_eofflag;
641 u_long *a_actualcount;
91447636 642 vfs_context_t a_context;
9bccf70c
A
643 } */ *ap;
644{
645 struct vnode *dvp = ap->a_vp;
91447636
A
646 struct cnode *dcp;
647 struct hfsmount * hfsmp;
9bccf70c 648 struct attrlist *alist = ap->a_alist;
91447636 649 uio_t uio = ap->a_uio;
9bccf70c 650 int maxcount = ap->a_maxcount;
91447636
A
651 struct proc *p = vfs_context_proc(ap->a_context);
652 uint32_t fixedblocksize;
653 uint32_t maxattrblocksize;
654 uint32_t currattrbufsize;
9bccf70c
A
655 void *attrbufptr = NULL;
656 void *attrptr;
657 void *varptr;
658 struct attrblock attrblk;
659 int error = 0;
660 int depleted = 0;
91447636 661 int index;
b4c24cb9 662 int i, dir_entries;
9bccf70c 663 struct cat_desc *lastdescp = NULL;
9bccf70c 664 struct cat_entrylist *ce_list = NULL;
91447636
A
665 directoryhint_t *dirhint = NULL;
666 unsigned int tag;
667 int shared_cnode_lock = 0;
b4c24cb9 668
9bccf70c
A
669 *(ap->a_actualcount) = 0;
670 *(ap->a_eofflag) = 0;
9bccf70c
A
671
672 /* Check for invalid options and buffer space. */
673 if (((ap->a_options & ~(FSOPT_NOINMEMUPDATE | FSOPT_NOFOLLOW)) != 0)
91447636 674 || (uio_resid(uio) <= 0) || (uio_iovcnt(uio) > 1) || (maxcount <= 0))
9bccf70c
A
675 return (EINVAL);
676
677 /* This call doesn't take volume attributes. */
678 if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) ||
679 ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) ||
680 (alist->volattr != 0) ||
681 ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) ||
682 ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0))
683 return (EINVAL);
684
91447636
A
685 if ((error = hfs_lock(VTOC(dvp), HFS_EXCLUSIVE_LOCK)))
686 return (error);
687 dcp = VTOC(dvp);
688 hfsmp = VTOHFS(dvp);
689
9bccf70c
A
690 /* Reject requests for unsupported options. */
691 if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST |
692 ATTR_CMN_OBJPERMANENTID)) ||
693 (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT |
694 ATTR_FILE_FORKLIST | ATTR_FILE_DATAEXTENTS | ATTR_FILE_RSRCEXTENTS))) {
695 printf("readdirattr: unsupported attributes! (%s)\n", dcp->c_desc.cd_nameptr);
91447636
A
696 error = EINVAL;
697 goto exit;
698 }
699
700 dir_entries = dcp->c_entries;
743b1565 701 if (dcp->c_attr.ca_fileid == kHFSRootFolderID && (hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY)))) {
91447636 702 dir_entries -= 3;
9bccf70c
A
703 }
704
705 /* Convert uio_offset into a directory index. */
91447636
A
706 index = uio_offset(uio) & HFS_INDEX_MASK;
707 tag = uio_offset(uio) & ~HFS_INDEX_MASK;
b4c24cb9 708 if ((index + 1) > dir_entries) {
9bccf70c
A
709 *(ap->a_eofflag) = 1;
710 error = 0;
711 goto exit;
712 }
713
714 /* Get a buffer to hold packed attributes. */
91447636 715 fixedblocksize = (sizeof(uint32_t) + hfs_attrblksize(alist)); /* 4 bytes for length */
9bccf70c
A
716 maxattrblocksize = fixedblocksize;
717 if (alist->commonattr & ATTR_CMN_NAME)
718 maxattrblocksize += kHFSPlusMaxFileNameBytes + 1;
719 MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK);
720 attrptr = attrbufptr;
721 varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */
722
723 /* Initialize a catalog entry list. */
724 MALLOC(ce_list, struct cat_entrylist *, sizeof(*ce_list), M_TEMP, M_WAITOK);
725 bzero(ce_list, sizeof(*ce_list));
726 ce_list->maxentries = MAXCATENTRIES;
727
91447636
A
728 /* Get a directory hint (cnode must be locked exclusive) */
729 dirhint = hfs_getdirhint(dcp, ((index - 1) & HFS_INDEX_MASK) | tag);
730
731 /* Hide tag from catalog layer. */
732 dirhint->dh_index &= HFS_INDEX_MASK;
733 if (dirhint->dh_index == HFS_INDEX_MASK) {
734 dirhint->dh_index = -1;
735 }
736
737 /*
738 * An ATTR_CMN_USERACCESS attribute request can result in a
739 * call to kauth_cred_ismember_gid(). So when requesting
740 * this attribute we downgrade our exclusive lock on dcp to
741 * a shared lock in case kauth_cred_ismember_gid generates
742 * an indirect call back into the file system.
743 */
744 if (alist->commonattr & ATTR_CMN_USERACCESS) {
745 lck_rw_lock_exclusive_to_shared(&dcp->c_rwlock);
746 dcp->c_lockowner = HFS_SHARED_OWNER;
747 shared_cnode_lock = 1;
748 }
9bccf70c
A
749 /*
750 * Obtain a list of catalog entries and pack their attributes until
751 * the output buffer is full or maxcount entries have been packed.
752 */
753 while (!depleted) {
754 int maxentries;
91447636 755 int lockflags;
9bccf70c
A
756
757 /* Constrain our list size. */
91447636 758 maxentries = uio_resid(uio) / (fixedblocksize + HFS_AVERAGE_NAME_SIZE);
9bccf70c
A
759 maxentries = min(maxentries, dcp->c_entries - index);
760 maxentries = min(maxentries, maxcount);
761 ce_list->maxentries = min(maxentries, ce_list->maxentries);
762 lastdescp = NULL;
763
91447636 764 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK);
9bccf70c 765
91447636 766 error = cat_getentriesattr(hfsmp, dirhint, ce_list);
9bccf70c
A
767 /* Don't forget to release the descriptors later! */
768
91447636 769 hfs_systemfile_unlock(hfsmp, lockflags);
9bccf70c
A
770
771 if (error == ENOENT) {
772 *(ap->a_eofflag) = TRUE;
773 error = 0;
774 depleted = 1;
775 }
776 if (error)
777 break;
778
779 /* Process the catalog entries. */
91447636 780 for (i = 0; i < (int)ce_list->realentries; ++i) {
9bccf70c
A
781 struct cnode *cp = NULL;
782 struct vnode *vp = NULL;
9bccf70c
A
783 struct cat_desc * cdescp;
784 struct cat_attr * cattrp;
91447636
A
785 struct cat_fork c_datafork;
786 struct cat_fork c_rsrcfork;
9bccf70c 787
91447636
A
788 bzero(&c_datafork, sizeof(c_datafork));
789 bzero(&c_rsrcfork, sizeof(c_rsrcfork));
9bccf70c
A
790 cdescp = &ce_list->entry[i].ce_desc;
791 cattrp = &ce_list->entry[i].ce_attr;
792 c_datafork.cf_size = ce_list->entry[i].ce_datasize;
793 c_datafork.cf_blocks = ce_list->entry[i].ce_datablks;
794 c_rsrcfork.cf_size = ce_list->entry[i].ce_rsrcsize;
795 c_rsrcfork.cf_blocks = ce_list->entry[i].ce_rsrcblks;
796 /*
797 * Get in memory cnode data (if any).
798 */
799 if (!(ap->a_options & FSOPT_NOINMEMUPDATE)) {
91447636
A
800 vp = hfs_chash_getvnode(dcp->c_dev, cattrp->ca_fileid, 0, 0);
801
802 if (vp != NULL) {
803 cp = VTOC(vp);
9bccf70c
A
804 /* Only use cnode's decriptor for non-hardlinks */
805 if (!(cp->c_flag & C_HARDLINK))
806 cdescp = &cp->c_desc;
807 cattrp = &cp->c_attr;
808 if (cp->c_datafork) {
55e303ae
A
809 c_datafork.cf_size = cp->c_datafork->ff_size;
810 c_datafork.cf_blocks = cp->c_datafork->ff_blocks;
9bccf70c
A
811 }
812 if (cp->c_rsrcfork) {
55e303ae
A
813 c_rsrcfork.cf_size = cp->c_rsrcfork->ff_size;
814 c_rsrcfork.cf_blocks = cp->c_rsrcfork->ff_blocks;
9bccf70c
A
815 }
816 }
817 }
91447636 818 *((uint32_t *)attrptr)++ = 0; /* move it past length */
9bccf70c
A
819 attrblk.ab_attrlist = alist;
820 attrblk.ab_attrbufpp = &attrptr;
821 attrblk.ab_varbufpp = &varptr;
822 attrblk.ab_flags = 0;
823 attrblk.ab_blocksize = maxattrblocksize;
824
825 /* Pack catalog entries into attribute buffer. */
826 hfs_packattrblk(&attrblk, hfsmp, vp, cdescp, cattrp,
55e303ae 827 &c_datafork, &c_rsrcfork, p);
9bccf70c
A
828 currattrbufsize = ((char *)varptr - (char *)attrbufptr);
829
830 /* All done with cnode. */
91447636
A
831 if (vp != NULL) {
832 hfs_unlock(VTOC(vp));
833 vnode_put(vp);
9bccf70c 834 vp = NULL;
91447636 835 cp = NULL;
9bccf70c 836 }
9bccf70c
A
837
838 /* Make sure there's enough buffer space remaining. */
91447636
A
839 // LP64todo - fix this!
840 if (uio_resid(uio) < 0 || currattrbufsize > (uint32_t)uio_resid(uio)) {
9bccf70c
A
841 depleted = 1;
842 break;
843 } else {
91447636 844 *((uint32_t *)attrbufptr) = currattrbufsize;
9bccf70c
A
845 error = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio);
846 if (error != E_NONE) {
847 depleted = 1;
848 break;
849 }
850 attrptr = attrbufptr;
851 varptr = (char *)attrbufptr + fixedblocksize; /* Point to variable-length storage */
852 /* Save the last valid catalog entry */
853 lastdescp = &ce_list->entry[i].ce_desc;
854 index++;
855 *ap->a_actualcount += 1;
856
857 /* Termination checks */
858 if ((--maxcount <= 0) ||
91447636
A
859 // LP64todo - fix this!
860 uio_resid(uio) < 0 ||
861 ((uint32_t)uio_resid(uio) < (fixedblocksize + HFS_AVERAGE_NAME_SIZE)) ||
b4c24cb9 862 (index >= dir_entries)) {
9bccf70c
A
863 depleted = 1;
864 break;
865 }
866 }
867 } /* for each catalog entry */
868
869 /* If there are more entries then save the last name. */
b4c24cb9 870 if (index < dir_entries
9bccf70c
A
871 && !(*(ap->a_eofflag))
872 && lastdescp != NULL) {
91447636
A
873
874 /* Remember last entry */
875 if (dirhint->dh_desc.cd_nameptr != NULL) {
876 vfs_removename(dirhint->dh_desc.cd_nameptr);
9bccf70c 877 }
91447636
A
878 dirhint->dh_desc.cd_namelen = lastdescp->cd_namelen;
879 dirhint->dh_desc.cd_nameptr =
880 vfs_addname(lastdescp->cd_nameptr, lastdescp->cd_namelen, 0, 0);
881 dirhint->dh_index = index - 1;
882 dirhint->dh_desc.cd_cnid = lastdescp->cd_cnid;
883 dirhint->dh_desc.cd_hint = lastdescp->cd_hint;
884 dirhint->dh_desc.cd_encoding = lastdescp->cd_encoding;
9bccf70c
A
885 }
886
887 /* All done with the catalog descriptors. */
91447636 888 for (i = 0; i < (int)ce_list->realentries; ++i)
9bccf70c
A
889 cat_releasedesc(&ce_list->entry[i].ce_desc);
890 ce_list->realentries = 0;
891
892 } /* while not depleted */
893
894 *ap->a_newstate = dcp->c_mtime;
9bccf70c 895
91447636
A
896 /* Make sure dcp is locked exclusive before changing c_dirhinttag. */
897 if (shared_cnode_lock) {
743b1565
A
898 /*
899 * If the upgrade fails we loose the lock and
900 * have to take the exclusive lock on our own.
901 */
902 if (lck_rw_lock_shared_to_exclusive(&dcp->c_rwlock) != 0)
903 lck_rw_lock_exclusive(&dcp->c_rwlock);
91447636
A
904 dcp->c_lockowner = current_thread();
905 shared_cnode_lock = 0;
906 }
9bccf70c 907
91447636
A
908 /* Convert directory index back into a uio_offset. */
909 while (tag == 0) tag = (++dcp->c_dirhinttag) << HFS_INDEX_BITS;
910 uio_setoffset(uio, index | tag);
911 dirhint->dh_index |= tag;
9bccf70c 912
91447636
A
913exit:
914 /* Drop directory hint on error or if there are no more entries */
915 if (dirhint && (error || index >= dir_entries)) {
916 if (shared_cnode_lock) {
743b1565
A
917 /*
918 * If the upgrade fails we loose the lock and
919 * have to take the exclusive lock on our own.
920 */
921 if (lck_rw_lock_shared_to_exclusive(&dcp->c_rwlock) != 0)
922 lck_rw_lock_exclusive(&dcp->c_rwlock);
91447636
A
923 dcp->c_lockowner = current_thread();
924 }
925 hfs_reldirhint(dcp, dirhint);
926 }
9bccf70c
A
927 if (attrbufptr)
928 FREE(attrbufptr, M_TEMP);
929 if (ce_list)
930 FREE(ce_list, M_TEMP);
9bccf70c 931
91447636 932 hfs_unlock(dcp);
9bccf70c
A
933 return (error);
934}
935
936
937/*==================== Attribute list support routines ====================*/
938
939/*
940 * Pack cnode attributes into an attribute block.
941 */
942 __private_extern__
943void
944hfs_packattrblk(struct attrblock *abp,
945 struct hfsmount *hfsmp,
946 struct vnode *vp,
947 struct cat_desc *descp,
948 struct cat_attr *attrp,
949 struct cat_fork *datafork,
55e303ae
A
950 struct cat_fork *rsrcfork,
951 struct proc *p)
9bccf70c
A
952{
953 struct attrlist *attrlistp = abp->ab_attrlist;
954
955 if (attrlistp->volattr) {
956 if (attrlistp->commonattr)
55e303ae 957 packvolcommonattr(abp, hfsmp, vp, p);
9bccf70c
A
958
959 if (attrlistp->volattr & ~ATTR_VOL_INFO)
91447636 960 packvolattr(abp, hfsmp, vp);
9bccf70c
A
961 } else {
962 if (attrlistp->commonattr)
55e303ae 963 packcommonattr(abp, hfsmp, vp, descp, attrp, p);
9bccf70c
A
964
965 if (attrlistp->dirattr && S_ISDIR(attrp->ca_mode))
91447636 966 packdirattr(abp, hfsmp, vp, descp,attrp);
9bccf70c
A
967
968 if (attrlistp->fileattr && !S_ISDIR(attrp->ca_mode))
91447636 969 packfileattr(abp, hfsmp, attrp, datafork, rsrcfork);
9bccf70c
A
970 }
971}
972
973
974static char*
975mountpointname(struct mount *mp)
976{
91447636 977 size_t namelength = strlen(mp->mnt_vfsstat.f_mntonname);
9bccf70c
A
978 int foundchars = 0;
979 char *c;
980
981 if (namelength == 0)
982 return (NULL);
983
984 /*
985 * Look backwards through the name string, looking for
986 * the first slash encountered (which must precede the
987 * last part of the pathname).
988 */
91447636 989 for (c = mp->mnt_vfsstat.f_mntonname + namelength - 1;
9bccf70c
A
990 namelength > 0; --c, --namelength) {
991 if (*c != '/') {
992 foundchars = 1;
993 } else if (foundchars) {
994 return (c + 1);
995 }
996 }
997
91447636 998 return (mp->mnt_vfsstat.f_mntonname);
9bccf70c
A
999}
1000
1001
1002static void
1003packnameattr(
1004 struct attrblock *abp,
1005 struct vnode *vp,
1006 char *name,
91447636 1007 int namelen)
9bccf70c
A
1008{
1009 void *varbufptr;
1010 struct attrreference * attr_refptr;
1011 char *mpname;
1012 size_t mpnamelen;
91447636 1013 uint32_t attrlength;
9bccf70c
A
1014 char empty = 0;
1015
1016 /* A cnode's name may be incorrect for the root of a mounted
1017 * filesystem (it can be mounted on a different directory name
1018 * than the name of the volume, such as "blah-1"). So for the
1019 * root directory, it's best to return the last element of the
1020 location where the volume's mounted:
1021 */
91447636
A
1022 if ((vp != NULL) && vnode_isvroot(vp) &&
1023 (mpname = mountpointname(vnode_mount(vp)))) {
9bccf70c
A
1024 mpnamelen = strlen(mpname);
1025
1026 /* Trim off any trailing slashes: */
1027 while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/'))
1028 --mpnamelen;
1029
1030 /* If there's anything left, use it instead of the volume's name */
1031 if (mpnamelen > 0) {
1032 name = mpname;
1033 namelen = mpnamelen;
1034 }
1035 }
1036 if (name == NULL) {
1037 name = &empty;
1038 namelen = 0;
1039 }
1040
1041 varbufptr = *abp->ab_varbufpp;
1042 attr_refptr = (struct attrreference *)(*abp->ab_attrbufpp);
1043
1044 attrlength = namelen + 1;
1045 attr_refptr->attr_dataoffset = (char *)varbufptr - (char *)attr_refptr;
1046 attr_refptr->attr_length = attrlength;
1047 (void) strncpy((unsigned char *)varbufptr, name, attrlength);
1048 /*
1049 * Advance beyond the space just allocated and
1050 * round up to the next 4-byte boundary:
1051 */
1052 (char *)(varbufptr) += attrlength + ((4 - (attrlength & 3)) & 3);
1053 ++attr_refptr;
1054
1055 *abp->ab_attrbufpp = attr_refptr;
1056 *abp->ab_varbufpp = varbufptr;
1057}
1058
1059/*
1060 * Pack common volume attributes.
1061 */
1062static void
55e303ae 1063packvolcommonattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp, struct proc *p)
9bccf70c
A
1064{
1065 attrgroup_t attr;
1066 void *attrbufptr = *abp->ab_attrbufpp;
1067 void *varbufptr = *abp->ab_varbufpp;
1068 struct cnode *cp = VTOC(vp);
1069 struct mount *mp = VTOVFS(vp);
1070 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
91447636
A
1071 u_int32_t attrlength;
1072 boolean_t is_64_bit = proc_is64bit(p);
9bccf70c
A
1073
1074 attr = abp->ab_attrlist->commonattr;
1075
1076 if (ATTR_CMN_NAME & attr) {
91447636 1077 packnameattr(abp, vp, cp->c_desc.cd_nameptr, cp->c_desc.cd_namelen);
9bccf70c
A
1078 attrbufptr = *abp->ab_attrbufpp;
1079 varbufptr = *abp->ab_varbufpp;
1080 }
1081 if (ATTR_CMN_DEVID & attr) {
1082 *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1083 }
1084 if (ATTR_CMN_FSID & attr) {
91447636
A
1085 fsid_t fsid;
1086
1087 fsid.val[0] = (long)hfsmp->hfs_raw_dev;
1088 fsid.val[1] = (long)vfs_typenum(mp);
1089 *((fsid_t *)attrbufptr) = fsid;
9bccf70c
A
1090 ++((fsid_t *)attrbufptr);
1091 }
1092 if (ATTR_CMN_OBJTYPE & attr) {
1093 *((fsobj_type_t *)attrbufptr)++ = 0;
1094 }
1095 if (ATTR_CMN_OBJTAG & attr) {
1096 *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1097 }
1098 if (ATTR_CMN_OBJID & attr) {
1099 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1100 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1101 ++((fsobj_id_t *)attrbufptr);
1102 }
1103 if (ATTR_CMN_OBJPERMANENTID & attr) {
1104 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1105 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1106 ++((fsobj_id_t *)attrbufptr);
1107 }
1108 if (ATTR_CMN_PAROBJID & attr) {
1109 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1110 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1111 ++((fsobj_id_t *)attrbufptr);
1112 }
1113 if (ATTR_CMN_SCRIPT & attr) {
91447636 1114 uint32_t encoding;
9bccf70c
A
1115
1116 if (vcb->vcbSigWord == kHFSPlusSigWord)
1117 encoding = vcb->volumeNameEncodingHint;
1118 else
1119 encoding = hfsmp->hfs_encoding;
1120 *((text_encoding_t *)attrbufptr)++ = encoding;
1121 }
1122 if (ATTR_CMN_CRTIME & attr) {
91447636
A
1123 if (is_64_bit) {
1124 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbCrDate;
1125 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1126 ++((struct user_timespec *)attrbufptr);
1127 }
1128 else {
1129 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbCrDate;
1130 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1131 ++((struct timespec *)attrbufptr);
1132 }
9bccf70c
A
1133 }
1134 if (ATTR_CMN_MODTIME & attr) {
91447636
A
1135 if (is_64_bit) {
1136 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1137 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1138 ++((struct user_timespec *)attrbufptr);
1139 }
1140 else {
1141 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1142 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1143 ++((struct timespec *)attrbufptr);
1144 }
9bccf70c
A
1145 }
1146 if (ATTR_CMN_CHGTIME & attr) {
91447636
A
1147 if (is_64_bit) {
1148 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1149 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1150 ++((struct user_timespec *)attrbufptr);
1151 }
1152 else {
1153 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1154 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1155 ++((struct timespec *)attrbufptr);
1156 }
9bccf70c
A
1157 }
1158 if (ATTR_CMN_ACCTIME & attr) {
91447636
A
1159 if (is_64_bit) {
1160 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1161 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1162 ++((struct user_timespec *)attrbufptr);
1163 }
1164 else {
1165 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbLsMod;
1166 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1167 ++((struct timespec *)attrbufptr);
1168 }
9bccf70c
A
1169 }
1170 if (ATTR_CMN_BKUPTIME & attr) {
91447636
A
1171 if (is_64_bit) {
1172 ((struct user_timespec *)attrbufptr)->tv_sec = vcb->vcbVolBkUp;
1173 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1174 ++((struct user_timespec *)attrbufptr);
1175 }
1176 else {
1177 ((struct timespec *)attrbufptr)->tv_sec = vcb->vcbVolBkUp;
1178 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1179 ++((struct timespec *)attrbufptr);
1180 }
9bccf70c
A
1181 }
1182 if (ATTR_CMN_FNDRINFO & attr) {
1183 bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo));
1184 (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
1185 }
1186 if (ATTR_CMN_OWNERID & attr) {
1187 if (cp->c_uid == UNKNOWNUID)
91447636 1188 *((uid_t *)attrbufptr)++ = kauth_cred_getuid(proc_ucred(p));
9bccf70c
A
1189 else
1190 *((uid_t *)attrbufptr)++ = cp->c_uid;
1191 }
1192 if (ATTR_CMN_GRPID & attr) {
1193 *((gid_t *)attrbufptr)++ = cp->c_gid;
1194 }
91447636 1195
9bccf70c
A
1196 if (ATTR_CMN_ACCESSMASK & attr) {
1197 /*
1198 * [2856576] Since we are dynamically changing the owner, also
1199 * effectively turn off the set-user-id and set-group-id bits,
1200 * just like chmod(2) would when changing ownership. This prevents
1201 * a security hole where set-user-id programs run as whoever is
1202 * logged on (or root if nobody is logged in yet!)
1203 */
91447636 1204 *((uint32_t *)attrbufptr)++ =
9bccf70c
A
1205 (cp->c_uid == UNKNOWNUID) ? cp->c_mode & ~(S_ISUID | S_ISGID) : cp->c_mode;
1206 }
1207 if (ATTR_CMN_NAMEDATTRCOUNT & attr) {
91447636 1208 *((uint32_t *)attrbufptr)++ = 0; /* XXX PPD TBC */
9bccf70c
A
1209 }
1210 if (ATTR_CMN_NAMEDATTRLIST & attr) {
1211 attrlength = 0;
1212 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1213 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1214 /*
1215 * Advance beyond the space just allocated and
1216 * round up to the next 4-byte boundary:
1217 */
1218 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1219 ++((struct attrreference *)attrbufptr);
1220 }
1221 if (ATTR_CMN_FLAGS & attr) {
91447636 1222 *((uint32_t *)attrbufptr)++ = cp->c_flags;
9bccf70c
A
1223 }
1224 if (ATTR_CMN_USERACCESS & attr) {
91447636 1225 *((uint32_t *)attrbufptr)++ =
9bccf70c 1226 DerivePermissionSummary(cp->c_uid, cp->c_gid, cp->c_mode,
91447636 1227 VTOVFS(vp), kauth_cred_get(), proc_self());
9bccf70c
A
1228 }
1229
1230 *abp->ab_attrbufpp = attrbufptr;
1231 *abp->ab_varbufpp = varbufptr;
1232}
1233
1234
1235static void
91447636 1236packvolattr(struct attrblock *abp, struct hfsmount *hfsmp, struct vnode *vp)
9bccf70c
A
1237{
1238 attrgroup_t attr;
1239 void *attrbufptr = *abp->ab_attrbufpp;
1240 void *varbufptr = *abp->ab_varbufpp;
1241 struct cnode *cp = VTOC(vp);
1242 struct mount *mp = VTOVFS(vp);
1243 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
91447636 1244 uint32_t attrlength;
9bccf70c
A
1245
1246 attr = abp->ab_attrlist->volattr;
1247
1248 if (ATTR_VOL_FSTYPE & attr) {
91447636 1249 *((uint32_t *)attrbufptr)++ = (uint32_t)vfs_typenum(mp);
9bccf70c
A
1250 }
1251 if (ATTR_VOL_SIGNATURE & attr) {
91447636 1252 *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbSigWord;
9bccf70c
A
1253 }
1254 if (ATTR_VOL_SIZE & attr) {
1255 *((off_t *)attrbufptr)++ =
1256 (off_t)vcb->totalBlocks * (off_t)vcb->blockSize;
1257 }
1258 if (ATTR_VOL_SPACEFREE & attr) {
1259 *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 0) *
1260 (off_t)vcb->blockSize;
9bccf70c
A
1261 }
1262 if (ATTR_VOL_SPACEAVAIL & attr) {
1263 *((off_t *)attrbufptr)++ = (off_t)hfs_freeblks(hfsmp, 1) *
1264 (off_t)vcb->blockSize;
1265 }
1266 if (ATTR_VOL_MINALLOCATION & attr) {
1267 *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize;
1268 }
1269 if (ATTR_VOL_ALLOCATIONCLUMP & attr) {
1270 *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz);
1271 }
1272 if (ATTR_VOL_IOBLOCKSIZE & attr) {
91447636 1273 *((uint32_t *)attrbufptr)++ = hfsmp->hfs_logBlockSize;
9bccf70c
A
1274 }
1275 if (ATTR_VOL_OBJCOUNT & attr) {
91447636
A
1276 *((uint32_t *)attrbufptr)++ =
1277 (uint32_t)vcb->vcbFilCnt + (uint32_t)vcb->vcbDirCnt;
9bccf70c
A
1278 }
1279 if (ATTR_VOL_FILECOUNT & attr) {
91447636 1280 *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbFilCnt;
9bccf70c
A
1281 }
1282 if (ATTR_VOL_DIRCOUNT & attr) {
91447636 1283 *((uint32_t *)attrbufptr)++ = (uint32_t)vcb->vcbDirCnt;
9bccf70c
A
1284 }
1285 if (ATTR_VOL_MAXOBJCOUNT & attr) {
91447636 1286 *((uint32_t *)attrbufptr)++ = 0xFFFFFFFF;
9bccf70c
A
1287 }
1288 if (ATTR_VOL_MOUNTPOINT & attr) {
1289 ((struct attrreference *)attrbufptr)->attr_dataoffset =
1290 (char *)varbufptr - (char *)attrbufptr;
1291 ((struct attrreference *)attrbufptr)->attr_length =
91447636 1292 strlen(mp->mnt_vfsstat.f_mntonname) + 1;
9bccf70c
A
1293 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1294 /* round up to the next 4-byte boundary: */
1295 attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
91447636 1296 (void) bcopy(mp->mnt_vfsstat.f_mntonname, varbufptr, attrlength);
9bccf70c
A
1297
1298 /* Advance beyond the space just allocated: */
1299 (char *)varbufptr += attrlength;
1300 ++((struct attrreference *)attrbufptr);
1301 }
1302 if (ATTR_VOL_NAME & attr) {
1303 ((struct attrreference *)attrbufptr)->attr_dataoffset =
1304 (char *)varbufptr - (char *)attrbufptr;
1305 ((struct attrreference *)attrbufptr)->attr_length =
1306 cp->c_desc.cd_namelen + 1;
1307 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1308 /* round up to the next 4-byte boundary: */
1309 attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
1310 /* XXX this could read off the end of cd_nameptr! */
1311 bcopy(cp->c_desc.cd_nameptr, varbufptr, attrlength);
1312
1313 /* Advance beyond the space just allocated: */
1314 (char *)varbufptr += attrlength;
1315 ++((struct attrreference *)attrbufptr);
1316 }
91447636
A
1317 if (ATTR_VOL_MOUNTFLAGS & attr) {
1318 *((uint32_t *)attrbufptr)++ = (uint32_t)vfs_flags(mp);
1319 }
9bccf70c
A
1320 if (ATTR_VOL_MOUNTEDDEVICE & attr) {
1321 ((struct attrreference *)attrbufptr)->attr_dataoffset =
1322 (char *)varbufptr - (char *)attrbufptr;
1323 ((struct attrreference *)attrbufptr)->attr_length =
91447636 1324 strlen(mp->mnt_vfsstat.f_mntfromname) + 1;
9bccf70c
A
1325 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1326 /* round up to the next 4-byte boundary: */
1327 attrlength = attrlength + ((4 - (attrlength & 3)) & 3);
91447636 1328 (void) bcopy(mp->mnt_vfsstat.f_mntfromname, varbufptr, attrlength);
9bccf70c
A
1329
1330 /* Advance beyond the space just allocated: */
1331 (char *)varbufptr += attrlength;
1332 ++((struct attrreference *)attrbufptr);
1333 }
1334 if (ATTR_VOL_ENCODINGSUSED & attr) {
1335 *((unsigned long long *)attrbufptr)++ =
1336 (unsigned long long)vcb->encodingsBitmap;
1337 }
1338 if (ATTR_VOL_CAPABILITIES & attr) {
1339 vol_capabilities_attr_t *vcapattrptr;
1340
1341 vcapattrptr = (vol_capabilities_attr_t *)attrbufptr;
1342
1343 if (vcb->vcbSigWord == kHFSPlusSigWord) {
91447636 1344 u_int32_t journal_active_cap;
55e303ae
A
1345 u_int32_t case_sensitive;
1346
1347 if (hfsmp->jnl)
91447636 1348 journal_active_cap = VOL_CAP_FMT_JOURNAL_ACTIVE;
55e303ae 1349 else
91447636 1350 journal_active_cap = 0;
55e303ae
A
1351
1352 if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE)
1353 case_sensitive = VOL_CAP_FMT_CASE_SENSITIVE;
1354 else
1355 case_sensitive = 0;
1356
9bccf70c
A
1357 vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
1358 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1359 VOL_CAP_FMT_SYMBOLICLINKS |
55e303ae
A
1360 VOL_CAP_FMT_HARDLINKS |
1361 VOL_CAP_FMT_JOURNAL |
91447636 1362 journal_active_cap |
55e303ae
A
1363 case_sensitive |
1364 VOL_CAP_FMT_CASE_PRESERVING |
91447636
A
1365 VOL_CAP_FMT_FAST_STATFS |
1366 VOL_CAP_FMT_2TB_FILESIZE;
9bccf70c
A
1367 } else { /* Plain HFS */
1368 vcapattrptr->capabilities[VOL_CAPABILITIES_FORMAT] =
55e303ae
A
1369 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1370 VOL_CAP_FMT_CASE_PRESERVING |
1371 VOL_CAP_FMT_FAST_STATFS ;
9bccf70c
A
1372 }
1373 vcapattrptr->capabilities[VOL_CAPABILITIES_INTERFACES] =
1374 VOL_CAP_INT_SEARCHFS |
1375 VOL_CAP_INT_ATTRLIST |
1376 VOL_CAP_INT_NFSEXPORT |
55e303ae
A
1377 VOL_CAP_INT_READDIRATTR |
1378 VOL_CAP_INT_EXCHANGEDATA |
1379 VOL_CAP_INT_ALLOCATE |
1380 VOL_CAP_INT_VOL_RENAME |
1381 VOL_CAP_INT_ADVLOCK |
1382 VOL_CAP_INT_FLOCK ;
9bccf70c
A
1383 vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
1384 vcapattrptr->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
1385
1386 vcapattrptr->valid[VOL_CAPABILITIES_FORMAT] =
1387 VOL_CAP_FMT_PERSISTENTOBJECTIDS |
1388 VOL_CAP_FMT_SYMBOLICLINKS |
55e303ae
A
1389 VOL_CAP_FMT_HARDLINKS |
1390 VOL_CAP_FMT_JOURNAL |
1391 VOL_CAP_FMT_JOURNAL_ACTIVE |
1392 VOL_CAP_FMT_NO_ROOT_TIMES |
1393 VOL_CAP_FMT_SPARSE_FILES |
1394 VOL_CAP_FMT_ZERO_RUNS |
1395 VOL_CAP_FMT_CASE_SENSITIVE |
1396 VOL_CAP_FMT_CASE_PRESERVING |
91447636
A
1397 VOL_CAP_FMT_FAST_STATFS |
1398 VOL_CAP_FMT_2TB_FILESIZE;
9bccf70c
A
1399 vcapattrptr->valid[VOL_CAPABILITIES_INTERFACES] =
1400 VOL_CAP_INT_SEARCHFS |
1401 VOL_CAP_INT_ATTRLIST |
1402 VOL_CAP_INT_NFSEXPORT |
55e303ae
A
1403 VOL_CAP_INT_READDIRATTR |
1404 VOL_CAP_INT_EXCHANGEDATA |
1405 VOL_CAP_INT_COPYFILE |
1406 VOL_CAP_INT_ALLOCATE |
1407 VOL_CAP_INT_VOL_RENAME |
1408 VOL_CAP_INT_ADVLOCK |
1409 VOL_CAP_INT_FLOCK ;
9bccf70c
A
1410 vcapattrptr->valid[VOL_CAPABILITIES_RESERVED1] = 0;
1411 vcapattrptr->valid[VOL_CAPABILITIES_RESERVED2] = 0;
1412
1413 ++((vol_capabilities_attr_t *)attrbufptr);
1414 }
1415 if (ATTR_VOL_ATTRIBUTES & attr) {
1416 vol_attributes_attr_t *volattrattrp;
1417
1418 volattrattrp = (vol_attributes_attr_t *)attrbufptr;
1419 volattrattrp->validattr.commonattr = ATTR_CMN_VALIDMASK;
1420 volattrattrp->validattr.volattr = ATTR_VOL_VALIDMASK;
1421 volattrattrp->validattr.dirattr = ATTR_DIR_VALIDMASK;
1422 volattrattrp->validattr.fileattr = ATTR_FILE_VALIDMASK;
1423 volattrattrp->validattr.forkattr = ATTR_FORK_VALIDMASK;
1424
1425 volattrattrp->nativeattr.commonattr = ATTR_CMN_VALIDMASK;
1426 volattrattrp->nativeattr.volattr = ATTR_VOL_VALIDMASK;
1427 volattrattrp->nativeattr.dirattr = ATTR_DIR_VALIDMASK;
1428 volattrattrp->nativeattr.fileattr = ATTR_FILE_VALIDMASK;
1429 volattrattrp->nativeattr.forkattr = ATTR_FORK_VALIDMASK;
1430 ++((vol_attributes_attr_t *)attrbufptr);
1431 }
1432
1433 *abp->ab_attrbufpp = attrbufptr;
1434 *abp->ab_varbufpp = varbufptr;
1435}
1436
1437
1438static void
1439packcommonattr(
1440 struct attrblock *abp,
1441 struct hfsmount *hfsmp,
1442 struct vnode *vp,
1443 struct cat_desc * cdp,
55e303ae
A
1444 struct cat_attr * cap,
1445 struct proc *p)
9bccf70c
A
1446{
1447 attrgroup_t attr = abp->ab_attrlist->commonattr;
1448 struct mount *mp = HFSTOVFS(hfsmp);
1449 void *attrbufptr = *abp->ab_attrbufpp;
1450 void *varbufptr = *abp->ab_varbufpp;
91447636
A
1451 uint32_t attrlength = 0;
1452 boolean_t is_64_bit = proc_is64bit(p);
9bccf70c
A
1453
1454 if (ATTR_CMN_NAME & attr) {
91447636 1455 packnameattr(abp, vp, cdp->cd_nameptr, cdp->cd_namelen);
9bccf70c
A
1456 attrbufptr = *abp->ab_attrbufpp;
1457 varbufptr = *abp->ab_varbufpp;
1458 }
1459 if (ATTR_CMN_DEVID & attr) {
1460 *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1461 }
1462 if (ATTR_CMN_FSID & attr) {
91447636
A
1463 fsid_t fsid;
1464
1465 fsid.val[0] = (long)hfsmp->hfs_raw_dev;
1466 fsid.val[1] = (long)vfs_typenum(mp);
1467 *((fsid_t *)attrbufptr) = fsid;
9bccf70c
A
1468 ++((fsid_t *)attrbufptr);
1469 }
1470 if (ATTR_CMN_OBJTYPE & attr) {
1471 *((fsobj_type_t *)attrbufptr)++ = IFTOVT(cap->ca_mode);
1472 }
1473 if (ATTR_CMN_OBJTAG & attr) {
1474 *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1475 }
1476 /*
1477 * Exporting file IDs from HFS Plus:
1478 *
1479 * For "normal" files the c_fileid is the same value as the
1480 * c_cnid. But for hard link files, they are different - the
1481 * c_cnid belongs to the active directory entry (ie the link)
1482 * and the c_fileid is for the actual inode (ie the data file).
1483 *
1484 * The stat call (getattr) will always return the c_fileid
1485 * and Carbon APIs, which are hardlink-ignorant, will always
1486 * receive the c_cnid (from getattrlist).
1487 */
91447636 1488 if (ATTR_CMN_OBJID & attr) {
9bccf70c
A
1489 ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid;
1490 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1491 ++((fsobj_id_t *)attrbufptr);
1492 }
1493 if (ATTR_CMN_OBJPERMANENTID & attr) {
1494 ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_cnid;
1495 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1496 ++((fsobj_id_t *)attrbufptr);
1497 }
1498 if (ATTR_CMN_PAROBJID & attr) {
1499 ((fsobj_id_t *)attrbufptr)->fid_objno = cdp->cd_parentcnid;
1500 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1501 ++((fsobj_id_t *)attrbufptr);
1502 }
1503 if (ATTR_CMN_SCRIPT & attr) {
1504 *((text_encoding_t *)attrbufptr)++ = cdp->cd_encoding;
1505 }
1506 if (ATTR_CMN_CRTIME & attr) {
91447636
A
1507 if (is_64_bit) {
1508 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_itime;
1509 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1510 ++((struct user_timespec *)attrbufptr);
1511 }
1512 else {
1513 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_itime;
1514 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1515 ++((struct timespec *)attrbufptr);
1516 }
9bccf70c
A
1517 }
1518 if (ATTR_CMN_MODTIME & attr) {
91447636
A
1519 if (is_64_bit) {
1520 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_mtime;
1521 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1522 ++((struct user_timespec *)attrbufptr);
1523 }
1524 else {
1525 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_mtime;
1526 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1527 ++((struct timespec *)attrbufptr);
1528 }
9bccf70c
A
1529 }
1530 if (ATTR_CMN_CHGTIME & attr) {
91447636
A
1531 if (is_64_bit) {
1532 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_ctime;
1533 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1534 ++((struct user_timespec *)attrbufptr);
1535 }
1536 else {
1537 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_ctime;
1538 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1539 ++((struct timespec *)attrbufptr);
1540 }
9bccf70c
A
1541 }
1542 if (ATTR_CMN_ACCTIME & attr) {
91447636
A
1543 if (is_64_bit) {
1544 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_atime;
1545 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1546 ++((struct user_timespec *)attrbufptr);
1547 }
1548 else {
1549 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_atime;
1550 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1551 ++((struct timespec *)attrbufptr);
1552 }
9bccf70c
A
1553 }
1554 if (ATTR_CMN_BKUPTIME & attr) {
91447636
A
1555 if (is_64_bit) {
1556 ((struct user_timespec *)attrbufptr)->tv_sec = cap->ca_btime;
1557 ((struct user_timespec *)attrbufptr)->tv_nsec = 0;
1558 ++((struct user_timespec *)attrbufptr);
1559 }
1560 else {
1561 ((struct timespec *)attrbufptr)->tv_sec = cap->ca_btime;
1562 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1563 ++((struct timespec *)attrbufptr);
1564 }
9bccf70c
A
1565 }
1566 if (ATTR_CMN_FNDRINFO & attr) {
1567 bcopy(&cap->ca_finderinfo, attrbufptr, sizeof(u_int8_t) * 32);
1568 (char *)attrbufptr += sizeof(u_int8_t) * 32;
1569 }
1570 if (ATTR_CMN_OWNERID & attr) {
1571 *((uid_t *)attrbufptr)++ =
91447636 1572 (cap->ca_uid == UNKNOWNUID) ? kauth_cred_getuid(proc_ucred(p)) : cap->ca_uid;
9bccf70c
A
1573 }
1574 if (ATTR_CMN_GRPID & attr) {
1575 *((gid_t *)attrbufptr)++ = cap->ca_gid;
1576 }
1577 if (ATTR_CMN_ACCESSMASK & attr) {
1578 /*
1579 * [2856576] Since we are dynamically changing the owner, also
1580 * effectively turn off the set-user-id and set-group-id bits,
1581 * just like chmod(2) would when changing ownership. This prevents
1582 * a security hole where set-user-id programs run as whoever is
1583 * logged on (or root if nobody is logged in yet!)
1584 */
91447636 1585 *((uint32_t *)attrbufptr)++ =
9bccf70c
A
1586 (cap->ca_uid == UNKNOWNUID) ? cap->ca_mode & ~(S_ISUID | S_ISGID) : cap->ca_mode;
1587 }
1588 if (ATTR_CMN_NAMEDATTRCOUNT & attr) {
91447636 1589 *((uint32_t *)attrbufptr)++ = 0;
9bccf70c
A
1590 }
1591 if (ATTR_CMN_NAMEDATTRLIST & attr) {
1592 attrlength = 0;
1593 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1594 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1595 /*
1596 * Advance beyond the space just allocated and
1597 * round up to the next 4-byte boundary:
1598 */
1599 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1600 ++((struct attrreference *)attrbufptr);
1601 }
1602 if (ATTR_CMN_FLAGS & attr) {
91447636 1603 *((uint32_t *)attrbufptr)++ = cap->ca_flags;
9bccf70c
A
1604 }
1605 if (ATTR_CMN_USERACCESS & attr) {
91447636 1606 *((uint32_t *)attrbufptr)++ =
9bccf70c 1607 DerivePermissionSummary(cap->ca_uid, cap->ca_gid,
91447636 1608 cap->ca_mode, mp, proc_ucred(current_proc()),
9bccf70c
A
1609 current_proc());
1610 }
1611
1612 *abp->ab_attrbufpp = attrbufptr;
1613 *abp->ab_varbufpp = varbufptr;
1614}
1615
1616static void
1617packdirattr(
1618 struct attrblock *abp,
1619 struct hfsmount *hfsmp,
1620 struct vnode *vp,
1621 struct cat_desc * descp,
91447636 1622 struct cat_attr * cattrp)
9bccf70c
A
1623{
1624 attrgroup_t attr = abp->ab_attrlist->dirattr;
1625 void *attrbufptr = *abp->ab_attrbufpp;
1626
1627 if (ATTR_DIR_LINKCOUNT & attr)
91447636 1628 *((uint32_t *)attrbufptr)++ = cattrp->ca_nlink;
9bccf70c 1629 if (ATTR_DIR_ENTRYCOUNT & attr) {
91447636 1630 uint32_t entries = cattrp->ca_entries;
9bccf70c 1631
91447636 1632 if (descp->cd_parentcnid == kHFSRootParentID) {
55e303ae 1633 if (hfsmp->hfs_privdir_desc.cd_cnid != 0)
b4c24cb9 1634 --entries; /* hide private dir */
743b1565 1635 if (hfsmp->jnl || ((HFSTOVCB(hfsmp)->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY)))
b4c24cb9
A
1636 entries -= 2; /* hide the journal files */
1637 }
9bccf70c 1638
91447636 1639 *((uint32_t *)attrbufptr)++ = entries;
9bccf70c
A
1640 }
1641 if (ATTR_DIR_MOUNTSTATUS & attr) {
91447636
A
1642 if (vp != NULL && vnode_mountedhere(vp) != NULL)
1643 *((uint32_t *)attrbufptr)++ = DIR_MNTSTATUS_MNTPOINT;
9bccf70c 1644 else
91447636 1645 *((uint32_t *)attrbufptr)++ = 0;
9bccf70c
A
1646 }
1647 *abp->ab_attrbufpp = attrbufptr;
1648}
1649
1650static void
1651packfileattr(
1652 struct attrblock *abp,
1653 struct hfsmount *hfsmp,
1654 struct cat_attr *cattrp,
1655 struct cat_fork *datafork,
91447636 1656 struct cat_fork *rsrcfork)
9bccf70c
A
1657{
1658 attrgroup_t attr = abp->ab_attrlist->fileattr;
1659 void *attrbufptr = *abp->ab_attrbufpp;
1660 void *varbufptr = *abp->ab_varbufpp;
91447636
A
1661 uint32_t attrlength;
1662 uint32_t allocblksize;
9bccf70c
A
1663
1664 allocblksize = HFSTOVCB(hfsmp)->blockSize;
1665
1666 if (ATTR_FILE_LINKCOUNT & attr) {
91447636 1667 *((uint32_t *)attrbufptr)++ = cattrp->ca_nlink;
9bccf70c
A
1668 }
1669 if (ATTR_FILE_TOTALSIZE & attr) {
1670 *((off_t *)attrbufptr)++ = datafork->cf_size + rsrcfork->cf_size;
1671 }
1672 if (ATTR_FILE_ALLOCSIZE & attr) {
1673 *((off_t *)attrbufptr)++ =
1674 (off_t)cattrp->ca_blocks * (off_t)allocblksize;
1675 }
1676 if (ATTR_FILE_IOBLOCKSIZE & attr) {
91447636 1677 *((uint32_t *)attrbufptr)++ = hfsmp->hfs_logBlockSize;
9bccf70c
A
1678 }
1679 if (ATTR_FILE_CLUMPSIZE & attr) {
91447636 1680 *((uint32_t *)attrbufptr)++ = HFSTOVCB(hfsmp)->vcbClpSiz;
9bccf70c
A
1681 }
1682 if (ATTR_FILE_DEVTYPE & attr) {
1683 if (S_ISBLK(cattrp->ca_mode) || S_ISCHR(cattrp->ca_mode))
91447636 1684 *((uint32_t *)attrbufptr)++ = (uint32_t)cattrp->ca_rdev;
9bccf70c 1685 else
91447636 1686 *((uint32_t *)attrbufptr)++ = 0;
9bccf70c
A
1687 }
1688 if (ATTR_FILE_FILETYPE & attr) {
91447636 1689 *((uint32_t *)attrbufptr)++ = 0;
9bccf70c
A
1690 }
1691 if (ATTR_FILE_FORKCOUNT & attr) {
91447636 1692 *((uint32_t *)attrbufptr)++ = 2;
9bccf70c
A
1693 }
1694 if (ATTR_FILE_FORKLIST & attr) {
1695 attrlength = 0;
1696 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1697 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1698 /*
1699 * Advance beyond the space just allocated and
1700 * round up to the next 4-byte boundary:
1701 */
1702 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1703 ++((struct attrreference *)attrbufptr);
1704 }
1705 if (ATTR_FILE_DATALENGTH & attr) {
1706 *((off_t *)attrbufptr)++ = datafork->cf_size;
1707 }
1708 if (ATTR_FILE_DATAALLOCSIZE & attr) {
1709 *((off_t *)attrbufptr)++ =
1710 (off_t)datafork->cf_blocks * (off_t)allocblksize;
1711 }
1712 if (ATTR_FILE_DATAEXTENTS & attr) {
1713 bcopy(&datafork->cf_extents, attrbufptr, sizeof(extentrecord));
1714 (char *)attrbufptr += sizeof(extentrecord);
1715 }
1716 if (ATTR_FILE_RSRCLENGTH & attr) {
1717 *((off_t *)attrbufptr)++ = rsrcfork->cf_size;
1718 }
1719 if (ATTR_FILE_RSRCALLOCSIZE & attr) {
1720 *((off_t *)attrbufptr)++ =
1721 (off_t)rsrcfork->cf_blocks * (off_t)allocblksize;
1722 }
1723 if (ATTR_FILE_RSRCEXTENTS & attr) {
1724 bcopy(&rsrcfork->cf_extents, attrbufptr, sizeof(extentrecord));
1725 (char *)attrbufptr += sizeof(extentrecord);
1726 }
1727 *abp->ab_attrbufpp = attrbufptr;
1728 *abp->ab_varbufpp = varbufptr;
1729}
1730
91447636
A
1731#if 0
1732static int
9bccf70c
A
1733unpackattrblk(struct attrblock *abp, struct vnode *vp)
1734{
1735 struct attrlist *attrlistp = abp->ab_attrlist;
91447636 1736 int error;
9bccf70c 1737
91447636
A
1738 if (attrlistp->volattr) {
1739 error = unpackvolattr(abp, VTOHFS(vp), vp);
1740 if (error)
1741 return (error);
1742 } else if (attrlistp->commonattr) {
9bccf70c 1743 unpackcommonattr(abp, vp);
91447636
A
1744 }
1745 return (0);
9bccf70c
A
1746}
1747
1748
1749static void
1750unpackcommonattr(
1751 struct attrblock *abp,
1752 struct vnode *vp)
1753{
1754 attrgroup_t attr = abp->ab_attrlist->commonattr;
1755 void *attrbufptr = *abp->ab_attrbufpp;
1756 struct cnode *cp = VTOC(vp);
91447636 1757 boolean_t is_64_bit = proc_is64bit(current_proc());
9bccf70c
A
1758
1759 if (ATTR_CMN_SCRIPT & attr) {
1760 cp->c_encoding = (u_int32_t)*((text_encoding_t *)attrbufptr)++;
1761 hfs_setencodingbits(VTOHFS(vp), cp->c_encoding);
1762 }
1763 if (ATTR_CMN_CRTIME & attr) {
91447636
A
1764 if (is_64_bit) {
1765 cp->c_itime = ((struct user_timespec *)attrbufptr)->tv_sec;
1766 ++((struct user_timespec *)attrbufptr);
1767 }
1768 else {
1769 cp->c_itime = ((struct timespec *)attrbufptr)->tv_sec;
1770 ++((struct timespec *)attrbufptr);
1771 }
9bccf70c
A
1772 }
1773 if (ATTR_CMN_MODTIME & attr) {
1774 cp->c_mtime = ((struct timespec *)attrbufptr)->tv_sec;
9bccf70c 1775 ++((struct timespec *)attrbufptr);
91447636 1776 cp->c_touch_modtime = FALSE;
9bccf70c
A
1777 }
1778 if (ATTR_CMN_CHGTIME & attr) {
1779 cp->c_ctime = ((struct timespec *)attrbufptr)->tv_sec;
1780 ++((struct timespec *)attrbufptr);
91447636 1781 cp->c_touch_chgtime = FALSE;
9bccf70c
A
1782 }
1783 if (ATTR_CMN_ACCTIME & attr) {
1784 cp->c_atime = ((struct timespec *)attrbufptr)->tv_sec;
1785 ++((struct timespec *)attrbufptr);
91447636 1786 cp->c_touch_acctime = FALSE;
9bccf70c
A
1787 }
1788 if (ATTR_CMN_BKUPTIME & attr) {
1789 cp->c_btime = ((struct timespec *)attrbufptr)->tv_sec;
1790 ++((struct timespec *)attrbufptr);
1791 }
1792 if (ATTR_CMN_FNDRINFO & attr) {
1793 bcopy(attrbufptr, &cp->c_attr.ca_finderinfo,
1794 sizeof(cp->c_attr.ca_finderinfo));
1795 (char *)attrbufptr += sizeof(cp->c_attr.ca_finderinfo);
1796 }
1797 if (ATTR_CMN_OWNERID & attr) {
1798 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1799 u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++;
1800 if (uid != (uid_t)VNOVAL)
1801 cp->c_uid = uid;
1802 } else {
1803 ((uid_t *)attrbufptr)++;
1804 }
1805 }
1806 if (ATTR_CMN_GRPID & attr) {
1807 u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++;
1808 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1809 if (gid != (gid_t)VNOVAL)
1810 cp->c_gid = gid;
1811 }
1812 }
1813 if (ATTR_CMN_ACCESSMASK & attr) {
91447636 1814 u_int16_t mode = (u_int16_t)*((uint32_t *)attrbufptr)++;
9bccf70c
A
1815 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
1816 if (mode != (mode_t)VNOVAL) {
1817 cp->c_mode &= ~ALLPERMS;
1818 cp->c_mode |= (mode & ALLPERMS);
1819 }
1820 }
1821 }
1822 if (ATTR_CMN_FLAGS & attr) {
91447636 1823 uint32_t flags = *((uint32_t *)attrbufptr)++;
9bccf70c
A
1824 /*
1825 * Flags are settable only on HFS+ volumes. A special
1826 * exception is made for the IMMUTABLE flags
1827 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1828 * HFS volumes as well:
1829 */
1830 if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) ||
1831 ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) &&
1832 ((flags & ~IMMUTABLE) == 0))) {
91447636 1833 if (flags != (uint32_t)VNOVAL) {
9bccf70c
A
1834 cp->c_flags = flags;
1835 }
1836 }
1837 }
1838 *abp->ab_attrbufpp = attrbufptr;
1839}
1840
1841
91447636 1842static int
9bccf70c
A
1843unpackvolattr(
1844 struct attrblock *abp,
1845 struct hfsmount *hfsmp,
91447636 1846 struct vnode *root_vp)
9bccf70c
A
1847{
1848 void *attrbufptr = *abp->ab_attrbufpp;
9bccf70c 1849 attrgroup_t attr;
91447636
A
1850 int error = 0;
1851 boolean_t is_64_bit = proc_is64bit(current_proc());
1852
1853 HFS_MOUNT_LOCK(hfsmp, TRUE);
9bccf70c
A
1854
1855 attr = abp->ab_attrlist->commonattr;
1856 if (attr == 0)
1857 goto volattr;
1858
1859 if (ATTR_CMN_SCRIPT & attr) {
91447636 1860 hfsmp->volumeNameEncodingHint =
9bccf70c
A
1861 (u_int32_t)*(((text_encoding_t *)attrbufptr)++);
1862 }
1863 if (ATTR_CMN_CRTIME & attr) {
91447636
A
1864 if (is_64_bit) {
1865 hfsmp->vcbCrDate = ((struct user_timespec *)attrbufptr)->tv_sec;
1866 ++((struct user_timespec *)attrbufptr);
1867 }
1868 else {
1869 hfsmp->vcbCrDate = ((struct timespec *)attrbufptr)->tv_sec;
1870 ++((struct timespec *)attrbufptr);
1871 }
9bccf70c
A
1872
1873 /* The volume's create date comes from the root directory */
91447636
A
1874 VTOC(root_vp)->c_itime = hfsmp->vcbCrDate;
1875 VTOC(root_vp)->c_flag |= C_MODIFIED;
9bccf70c
A
1876 /*
1877 * XXX Should we also do a relative change to the
1878 * the volume header's create date in local time?
1879 */
1880 }
1881 if (ATTR_CMN_MODTIME & attr) {
91447636 1882 hfsmp->vcbLsMod = ((struct timespec *)attrbufptr)->tv_sec;
9bccf70c
A
1883 ++((struct timespec *)attrbufptr);
1884 }
1885 if (ATTR_CMN_BKUPTIME & attr) {
91447636 1886 hfsmp->vcbVolBkUp = ((struct timespec *)attrbufptr)->tv_sec;
9bccf70c
A
1887 ++((struct timespec *)attrbufptr);
1888 }
1889 if (ATTR_CMN_FNDRINFO & attr) {
91447636
A
1890 bcopy(attrbufptr, &hfsmp->vcbFndrInfo, sizeof(hfsmp->vcbFndrInfo));
1891 (char *)attrbufptr += sizeof(hfsmp->vcbFndrInfo);
9bccf70c
A
1892 }
1893
1894volattr:
1895 attr = abp->ab_attrlist->volattr & ~ATTR_VOL_INFO;
1896 /*
1897 * XXX - no validation is done on the name!
1898 * It could be empty or garbage (bad UTF-8).
1899 */
1900 if (ATTR_VOL_NAME & attr) {
91447636
A
1901 attrreference_t * attr_refp = (attrreference_t *) attrbufptr;
1902
1903 error = copystr(((char *)attrbufptr) + attr_refp->attr_dataoffset,
1904 hfsmp->vcbVN, MIN(attr_refp->attr_length, sizeof(hfsmp->vcbVN)),
1905 NULL);
1906 if (error == 0)
1907 (char *)attrbufptr += sizeof(struct attrreference);
9bccf70c
A
1908 }
1909 *abp->ab_attrbufpp = attrbufptr;
1910
91447636
A
1911 hfsmp->vcbFlags |= 0xFF00;
1912 HFS_MOUNT_UNLOCK(hfsmp, TRUE);
1913
1914 return (error);
9bccf70c 1915}
91447636 1916#endif
9bccf70c
A
1917
1918/*
1919 * Calculate the total size of an attribute block.
1920 */
1921 __private_extern__
1922int
1923hfs_attrblksize(struct attrlist *attrlist)
1924{
1925 int size;
1926 attrgroup_t a;
91447636
A
1927 int sizeof_timespec;
1928 boolean_t is_64_bit = proc_is64bit(current_proc());
9bccf70c 1929
91447636
A
1930 if (is_64_bit)
1931 sizeof_timespec = sizeof(struct user_timespec);
1932 else
1933 sizeof_timespec = sizeof(struct timespec);
1934
9bccf70c
A
1935#if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1936 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \
1937 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \
1938 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \
1939 ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1940 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \
1941 ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \
1942 != ATTR_CMN_VALIDMASK)
1943#error hfs_attrblksize: Missing bits in common mask computation!
1944#endif
1945 DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0);
1946
1947#if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \
1948 ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
1949 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1950 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \
1951 ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \
1952 ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \
1953 ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1954 != ATTR_VOL_VALIDMASK)
1955#error hfs_attrblksize: Missing bits in volume mask computation!
1956#endif
1957 DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0);
1958
1959#if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \
1960 != ATTR_DIR_VALIDMASK)
1961#error hfs_attrblksize: Missing bits in directory mask computation!
1962#endif
1963 DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0);
1964
1965#if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
1966 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \
1967 ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \
1968 ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1969 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \
1970 != ATTR_FILE_VALIDMASK)
1971#error hfs_attrblksize: Missing bits in file mask computation!
1972#endif
1973 DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0);
1974
1975#if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1976#error hfs_attrblksize: Missing bits in fork mask computation!
1977#endif
1978 DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0);
1979
1980 size = 0;
1981
1982 if ((a = attrlist->commonattr) != 0) {
1983 if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference);
1984 if (a & ATTR_CMN_DEVID) size += sizeof(dev_t);
1985 if (a & ATTR_CMN_FSID) size += sizeof(fsid_t);
1986 if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t);
1987 if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t);
1988 if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t);
1989 if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t);
1990 if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t);
1991 if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t);
91447636
A
1992 if (a & ATTR_CMN_CRTIME) size += sizeof_timespec;
1993 if (a & ATTR_CMN_MODTIME) size += sizeof_timespec;
1994 if (a & ATTR_CMN_CHGTIME) size += sizeof_timespec;
1995 if (a & ATTR_CMN_ACCTIME) size += sizeof_timespec;
1996 if (a & ATTR_CMN_BKUPTIME) size += sizeof_timespec;
9bccf70c
A
1997 if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(u_int8_t);
1998 if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t);
1999 if (a & ATTR_CMN_GRPID) size += sizeof(gid_t);
91447636
A
2000 if (a & ATTR_CMN_ACCESSMASK) size += sizeof(uint32_t);
2001 if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(uint32_t);
9bccf70c 2002 if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference);
91447636
A
2003 if (a & ATTR_CMN_FLAGS) size += sizeof(uint32_t);
2004 if (a & ATTR_CMN_USERACCESS) size += sizeof(uint32_t);
9bccf70c
A
2005 };
2006 if ((a = attrlist->volattr) != 0) {
91447636
A
2007 if (a & ATTR_VOL_FSTYPE) size += sizeof(uint32_t);
2008 if (a & ATTR_VOL_SIGNATURE) size += sizeof(uint32_t);
9bccf70c
A
2009 if (a & ATTR_VOL_SIZE) size += sizeof(off_t);
2010 if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t);
2011 if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t);
2012 if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t);
2013 if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t);
91447636
A
2014 if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(uint32_t);
2015 if (a & ATTR_VOL_OBJCOUNT) size += sizeof(uint32_t);
2016 if (a & ATTR_VOL_FILECOUNT) size += sizeof(uint32_t);
2017 if (a & ATTR_VOL_DIRCOUNT) size += sizeof(uint32_t);
2018 if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(uint32_t);
9bccf70c
A
2019 if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference);
2020 if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference);
91447636 2021 if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(uint32_t);
9bccf70c
A
2022 if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference);
2023 if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long);
2024 if (a & ATTR_VOL_CAPABILITIES) size += sizeof(vol_capabilities_attr_t);
2025 if (a & ATTR_VOL_ATTRIBUTES) size += sizeof(vol_attributes_attr_t);
2026 };
2027 if ((a = attrlist->dirattr) != 0) {
91447636
A
2028 if (a & ATTR_DIR_LINKCOUNT) size += sizeof(uint32_t);
2029 if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(uint32_t);
2030 if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(uint32_t);
9bccf70c
A
2031 };
2032 if ((a = attrlist->fileattr) != 0) {
91447636 2033 if (a & ATTR_FILE_LINKCOUNT) size += sizeof(uint32_t);
9bccf70c
A
2034 if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t);
2035 if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t);
91447636
A
2036 if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(uint32_t);
2037 if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(uint32_t);
2038 if (a & ATTR_FILE_DEVTYPE) size += sizeof(uint32_t);
2039 if (a & ATTR_FILE_FILETYPE) size += sizeof(uint32_t);
2040 if (a & ATTR_FILE_FORKCOUNT) size += sizeof(uint32_t);
9bccf70c
A
2041 if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference);
2042 if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t);
2043 if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t);
2044 if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord);
2045 if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t);
2046 if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t);
2047 if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord);
2048 };
2049 if ((a = attrlist->forkattr) != 0) {
2050 if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t);
2051 if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t);
2052 };
2053
2054 return size;
2055}
2056
2057
2058__private_extern__
2059unsigned long
2060DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode,
91447636 2061 struct mount *mp, kauth_cred_t cred, struct proc *p)
9bccf70c 2062{
9bccf70c 2063 unsigned long permissions;
9bccf70c
A
2064
2065 if (obj_uid == UNKNOWNUID)
91447636 2066 obj_uid = kauth_cred_getuid(proc_ucred(p));
9bccf70c
A
2067
2068 /* User id 0 (root) always gets access. */
91447636 2069 if (!suser(cred, NULL)) {
9bccf70c
A
2070 permissions = R_OK | W_OK | X_OK;
2071 goto Exit;
2072 };
2073
2074 /* Otherwise, check the owner. */
2075 if (hfs_owner_rights(VFSTOHFS(mp), obj_uid, cred, p, false) == 0) {
2076 permissions = ((unsigned long)obj_mode & S_IRWXU) >> 6;
2077 goto Exit;
2078 }
2079
2080 /* Otherwise, check the groups. */
91447636
A
2081 if (! (((unsigned int)vfs_flags(mp)) & MNT_UNKNOWNPERMISSIONS)) {
2082 int is_member;
2083
2084 if (kauth_cred_ismember_gid(cred, obj_gid, &is_member) == 0 && is_member) {
2085 permissions = ((unsigned long)obj_mode & S_IRWXG) >> 3;
2086 goto Exit;
9bccf70c
A
2087 }
2088 }
2089
2090 /* Otherwise, settle for 'others' access. */
2091 permissions = (unsigned long)obj_mode & S_IRWXO;
2092
2093Exit:
2094 return (permissions);
2095}
2096