2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * hfs_attrlist.c - HFS attribute list processing
32 * Copyright (c) 1998-2002, Apple Computer, Inc. All Rights Reserved.
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
41 #include <sys/unistd.h>
42 #include <sys/mount_internal.h>
43 #include <sys/kauth.h>
45 #include <kern/locks.h>
48 #include "hfs_cnode.h"
49 #include "hfs_mount.h"
51 #include "hfs_attrlist.h"
55 /* Routines that are shared by hfs_setattr: */
56 extern int hfs_write_access(struct vnode
*vp
, kauth_cred_t cred
,
57 struct proc
*p
, Boolean considerFlags
);
59 extern int hfs_chflags(struct vnode
*vp
, uint32_t flags
, kauth_cred_t cred
,
62 extern int hfs_chmod(struct vnode
*vp
, int mode
, kauth_cred_t cred
,
65 extern int hfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, kauth_cred_t cred
,
68 __private_extern__
int hfs_vnop_readdirattr(struct vnop_readdirattr_args
*ap
);
70 __private_extern__
int hfs_vnop_setattrlist(struct vnop_setattrlist_args
*ap
);
72 __private_extern__
int hfs_vnop_getattrlist(struct vnop_getattrlist_args
*ap
);
74 /* Packing routines: */
77 static void packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
78 struct vnode
*vp
, struct proc
*p
);
80 static void packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
83 static void packcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
84 struct vnode
*vp
, struct cat_desc
* cdp
,
85 struct cat_attr
* cap
, struct proc
*p
);
87 static void packfileattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
88 struct cat_attr
*cattrp
, struct cat_fork
*datafork
,
89 struct cat_fork
*rsrcfork
);
91 static void packdirattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
92 struct vnode
*vp
, struct cat_desc
* descp
,
93 struct cat_attr
* cattrp
);
97 static int unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
);
99 static void unpackcommonattr(struct attrblock
*abp
, struct vnode
*vp
);
101 static int unpackvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
102 struct vnode
*root_vp
);
106 * Get a list of attributes.
110 hfs_vnop_getattrlist(ap
)
111 struct vnop_getattrlist_args
/* {
113 struct attrlist *a_alist
116 vfs_context_t a_context;
119 struct vnode
*vp
= ap
->a_vp
;
121 struct hfsmount
*hfsmp
;
122 struct attrlist
*alist
= ap
->a_alist
;
123 proc_t p
= vfs_context_proc(ap
->a_context
);
127 void *attrbufptr
= NULL
;
130 struct attrblock attrblk
;
131 struct cat_fork
*datafp
= NULL
;
132 struct cat_fork
*rsrcfp
= NULL
;
133 struct cat_fork rsrcfork
;
137 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
138 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
139 ((alist
->volattr
& ~ATTR_VOL_VALIDMASK
) != 0) ||
140 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
141 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0)) {
146 * Requesting volume information requires setting the
147 * ATTR_VOL_INFO bit. Also, volume info requests are
148 * mutually exclusive with all other info requests.
150 if ((alist
->volattr
!= 0) &&
151 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
152 (alist
->dirattr
!= 0) || (alist
->fileattr
!= 0))) {
156 /* Reject requests for unsupported options for now: */
157 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
)) ||
158 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
| ATTR_FILE_FORKLIST
))) {
162 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
)))
167 /* Requesting volume information requires root vnode */
168 if ((alist
->volattr
) && cp
->c_fileid
!= kHFSRootFolderID
) {
172 /* Asking for data fork attributes from the rsrc fork is not supported */
173 if (VNODE_IS_RSRC(vp
) && (alist
->fileattr
& ATTR_DATAFORK_MASK
)) {
177 /* This file no longer exists! */
178 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
182 /* This file doesn't have a name! */
183 if ((cp
->c_desc
.cd_namelen
== 0) && (alist
->commonattr
& ATTR_CMN_NAME
)) {
188 /* Update cnode times if needed */
189 hfs_touchtimes(hfsmp
, cp
);
192 * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on
193 * an HFS volume we must be sure to create the thread
194 * record before returning it. (yikes)
196 if (vnode_isreg(vp
) &&
197 (alist
->commonattr
& ATTR_CMN_OBJPERMANENTID
) &&
198 (VTOVCB(vp
)->vcbSigWord
!= kHFSPlusSigWord
)) {
202 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
) {
206 if ((error
= hfs_write_access(vp
, vfs_context_ucred(ap
->a_context
),
211 * Reserve some space in the Catalog file.
213 bzero(&cookie
, sizeof(cookie
));
214 error
= cat_preflight(hfsmp
, CAT_CREATE
, &cookie
, p
);
219 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
221 error
= cat_insertfilethread(hfsmp
, &cp
->c_desc
);
223 hfs_systemfile_unlock(hfsmp
, lockflags
);
225 cat_postflight(hfsmp
, &cookie
, p
);
230 bzero(&rsrcfork
, sizeof(rsrcfork
));
231 /* Establish known fork data */
232 if (cp
->c_datafork
!= NULL
) {
233 datafp
= &cp
->c_datafork
->ff_data
;
234 if ((cp
->c_rsrcfork
== NULL
) &&
235 (cp
->c_blocks
== datafp
->cf_blocks
))
236 rsrcfp
= &rsrcfork
; /* rsrc fork is empty */
238 if (cp
->c_rsrcfork
!= NULL
)
239 rsrcfp
= &cp
->c_rsrcfork
->ff_data
;
242 * When resource fork data is requested and its not available
243 * in the cnode and the fork is not empty then it needs to be
244 * fetched from the catalog.
246 if ((alist
->fileattr
& ATTR_RSRCFORK_MASK
) && (rsrcfp
== NULL
)) {
248 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
250 /* Get resource fork data */
251 error
= cat_lookup(hfsmp
, &cp
->c_desc
, 1,
252 (struct cat_desc
*)0, (struct cat_attr
*)0, &rsrcfork
, NULL
);
254 hfs_systemfile_unlock(hfsmp
, lockflags
);
262 fixedblocksize
= hfs_attrblksize(alist
);
263 attrblocksize
= fixedblocksize
+ (sizeof(uint32_t)); /* uint32_t for length word */
264 if (alist
->commonattr
& ATTR_CMN_NAME
)
265 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
266 if (alist
->volattr
& ATTR_VOL_MOUNTPOINT
)
267 attrblocksize
+= PATH_MAX
;
268 if (alist
->volattr
& ATTR_VOL_NAME
)
269 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
271 if (alist
->commonattr
& ATTR_CMN_NAMEDATTRLIST
)
273 if (alist
->fileattr
& ATTR_FILE_FORKLIST
)
276 attrbufsize
= MIN(uio_resid(ap
->a_uio
), attrblocksize
);
277 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
278 attrptr
= attrbufptr
;
279 *((uint32_t *)attrptr
) = 0; /* Set buffer length in case of errors */
280 ++((uint32_t *)attrptr
); /* Reserve space for length field */
281 varptr
= ((char *)attrptr
) + fixedblocksize
;
283 attrblk
.ab_attrlist
= alist
;
284 attrblk
.ab_attrbufpp
= &attrptr
;
285 attrblk
.ab_varbufpp
= &varptr
;
286 attrblk
.ab_flags
= 0;
287 attrblk
.ab_blocksize
= attrblocksize
;
289 hfs_packattrblk(&attrblk
, hfsmp
, vp
, &cp
->c_desc
, &cp
->c_attr
,
292 /* Don't copy out more data than was generated */
293 attrbufsize
= MIN((u_int
)attrbufsize
, (u_int
)varptr
- (u_int
)attrbufptr
);
294 /* Set actual buffer length for return to caller */
295 *((uint32_t *)attrbufptr
) = attrbufsize
;
296 error
= uiomove((caddr_t
)attrbufptr
, attrbufsize
, ap
->a_uio
);
299 FREE(attrbufptr
, M_TEMP
);
306 * Set a list of attributes.
310 hfs_vnop_setattrlist(ap
)
311 struct vnop_setattrlist_args
/* {
313 struct attrlist *a_alist
316 vfs_context_t a_context;
319 struct vnode
*vp
= ap
->a_vp
;
321 struct hfsmount
* hfsmp
;
322 struct attrlist
*alist
= ap
->a_alist
;
323 kauth_cred_t cred
= vfs_context_ucred(ap
->a_context
);
324 struct proc
*p
= vfs_context_proc(ap
->a_context
);
326 void *attrbufptr
= NULL
;
329 struct attrblock attrblk
;
333 uint32_t saved_flags
;
338 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
)
340 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
341 ((alist
->commonattr
& ~ATTR_CMN_SETMASK
) != 0) ||
342 ((alist
->volattr
& ~ATTR_VOL_SETMASK
) != 0) ||
343 ((alist
->dirattr
& ~ATTR_DIR_SETMASK
) != 0) ||
344 ((alist
->fileattr
& ~ATTR_FILE_SETMASK
) != 0)) {
347 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
)))
352 * When setting volume attributes make sure
353 * that ATTR_VOL_INFO is set and that all
354 * the attributes are valid.
356 if ((alist
->volattr
!= 0) &&
357 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
358 (alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
359 (cp
->c_fileid
!= kHFSRootFolderID
))) {
360 if ((alist
->volattr
& ATTR_VOL_INFO
) == 0)
361 printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
363 printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
364 alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
);
368 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
372 // XXXdbg - don't allow modifying the journal or journal_info_block
373 if (hfsmp
->jnl
&& cp
->c_datafork
) {
374 struct HFSPlusExtentDescriptor
*extd
;
376 extd
= &cp
->c_datafork
->ff_extents
[0];
377 if (extd
->startBlock
== HFSTOVCB(hfsmp
)->vcbJinfoBlock
|| extd
->startBlock
== hfsmp
->jnl_start
) {
384 * Ownership of a file is required in one of two classes of calls:
386 * (a) When setting any ownership-requiring attribute other
387 * than ATTR_CMN_FLAGS, or
388 * (b) When setting ATTR_CMN_FLAGS on a volume that's not
389 * plain HFS (for which no real per-object ownership
390 * information is stored)
392 if ((alist
->commonattr
& (ATTR_OWNERSHIP_SETMASK
& ~ATTR_CMN_FLAGS
)) ||
393 ((alist
->commonattr
& ATTR_CMN_FLAGS
) &&
394 (VTOVCB(vp
)->vcbSigWord
!= kHFSSigWord
))) {
396 * NOTE: The following isn't ENTIRELY complete: even if
397 * you're the superuser you cannot change the flags as
398 * long as SF_IMMUTABLE or SF_APPEND is set and the
399 * securelevel > 0. This is verified in hfs_chflags
400 * which gets invoked to do the actual flags field
401 * change so this check is sufficient for now.
403 if ((error
= hfs_owner_rights(hfsmp
, cp
->c_uid
, cred
, p
, true)) != 0)
407 * For any other attributes, check to see if the user has
408 * write access to the cnode in question [unlike vn_access,
409 * ignore IMMUTABLE here]:
411 if (((alist
->commonattr
& ~ATTR_OWNERSHIP_SETMASK
) != 0) ||
412 (alist
->volattr
!= 0) || (alist
->dirattr
!= 0) ||
413 (alist
->fileattr
!= 0)) {
414 if ((error
= hfs_write_access(vp
, cred
, p
, false)) != 0)
419 * Allocate the buffer now to minimize the time we might
420 * be blocked holding the catalog lock.
422 // LP64todo - fix this
423 attrblocksize
= uio_resid(ap
->a_uio
);
424 if (attrblocksize
< hfs_attrblksize(alist
)) {
429 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
431 error
= uiomove((caddr_t
)attrbufptr
, attrblocksize
, ap
->a_uio
);
435 /* Save original state so changes can be detected. */
436 saved_uid
= cp
->c_uid
;
437 saved_gid
= cp
->c_gid
;
438 saved_mode
= cp
->c_mode
;
439 saved_flags
= cp
->c_flags
;
441 attrptr
= attrbufptr
;
442 attrblk
.ab_attrlist
= alist
;
443 attrblk
.ab_attrbufpp
= &attrptr
;
444 attrblk
.ab_varbufpp
= &varptr
;
445 attrblk
.ab_flags
= 0;
446 attrblk
.ab_blocksize
= attrblocksize
;
447 error
= unpackattrblk(&attrblk
, vp
);
451 /* If unpacking changed the owner/group then call hfs_chown() */
452 if ((saved_uid
!= cp
->c_uid
) || (saved_gid
!= cp
->c_gid
)) {
457 cp
->c_uid
= saved_uid
;
459 cp
->c_gid
= saved_gid
;
460 if ((error
= hfs_chown(vp
, uid
, gid
, cred
, p
)))
463 /* If unpacking changed the mode then call hfs_chmod() */
464 if (saved_mode
!= cp
->c_mode
) {
468 cp
->c_mode
= saved_mode
;
469 if ((error
= hfs_chmod(vp
, mode
, cred
, p
)))
472 /* If unpacking changed the flags then call hfs_chflags() */
473 if (saved_flags
!=cp
->c_flags
) {
477 cp
->c_flags
= saved_flags
;
478 if ((error
= hfs_chflags(vp
, flags
, cred
, p
)))
482 * If any cnode attributes changed then do an update.
484 if (alist
->volattr
== 0) {
485 cp
->c_flag
|= C_MODIFIED
;
486 if ((error
= hfs_update(vp
, TRUE
))) {
491 if (alist
->volattr
& ATTR_VOL_NAME
) {
492 ExtendedVCB
*vcb
= VTOVCB(vp
);
494 if (vcb
->vcbVN
[0] == 0) {
496 * Ignore attempts to rename a volume to a zero-length name:
497 * restore the original name from the cnode.
499 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
501 struct cat_desc to_desc
;
502 struct cat_desc todir_desc
;
503 struct cat_desc new_desc
;
510 bzero(&to_desc
, sizeof(to_desc
));
511 bzero(&todir_desc
, sizeof(todir_desc
));
512 bzero(&new_desc
, sizeof(new_desc
));
513 bzero(&cookie
, sizeof(cookie
));
515 todir_desc
.cd_parentcnid
= kHFSRootParentID
;
516 todir_desc
.cd_cnid
= kHFSRootFolderID
;
517 todir_desc
.cd_flags
= CD_ISDIR
;
519 to_desc
.cd_nameptr
= vcb
->vcbVN
;
520 to_desc
.cd_namelen
= strlen(vcb
->vcbVN
);
521 to_desc
.cd_parentcnid
= kHFSRootParentID
;
522 to_desc
.cd_cnid
= cp
->c_cnid
;
523 to_desc
.cd_flags
= CD_ISDIR
;
525 if ((error
= hfs_start_transaction(hfsmp
) != 0)) {
531 * Reserve some space in the Catalog file.
533 error
= cat_preflight(hfsmp
, CAT_RENAME
, &cookie
, p
);
539 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
542 error
= cat_rename(hfsmp
, &cp
->c_desc
, &todir_desc
, &to_desc
, &new_desc
);
545 hfs_systemfile_unlock(hfsmp
, lockflags
);
548 cat_postflight(hfsmp
, &cookie
, p
);
550 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
552 hfs_end_transaction(hfsmp
);
556 /* Restore the old name in the VCB */
557 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
558 vcb
->vcbFlags
|= 0xFF00;
561 /* Release old allocated name buffer */
562 if (cp
->c_desc
.cd_flags
& CD_HASBUF
) {
563 char *name
= cp
->c_desc
.cd_nameptr
;
565 cp
->c_desc
.cd_nameptr
= 0;
566 cp
->c_desc
.cd_namelen
= 0;
567 cp
->c_desc
.cd_flags
&= ~CD_HASBUF
;
568 vfs_removename(name
);
570 /* Update cnode's catalog descriptor */
571 replace_desc(cp
, &new_desc
);
572 vcb
->volumeNameEncodingHint
= new_desc
.cd_encoding
;
573 cp
->c_touch_chgtime
= TRUE
;
578 * When the volume name changes or the volume's finder info
579 * changes then force them to disk immediately.
581 if ((alist
->volattr
& ATTR_VOL_INFO
) &&
582 ((alist
->volattr
& ATTR_VOL_NAME
) ||
583 (alist
->commonattr
& ATTR_CMN_FNDRINFO
))) {
584 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
588 FREE(attrbufptr
, M_TEMP
);
596 * readdirattr operation will return attributes for the items in the
597 * directory specified.
599 * It does not do . and .. entries. The problem is if you are at the root of the
600 * hfs directory and go to .. you could be crossing a mountpoint into a
601 * different (ufs) file system. The attributes that apply for it may not
602 * apply for the file system you are doing the readdirattr on. To make life
603 * simpler, this call will only return entries in its directory, hfs like.
605 * 1. more than one for uiovcnt support.
606 * 2. put knohint (hints) in state for next call in
607 * 3. credentials checking when rest of hfs does it.
608 * 4. Do return permissions concatenation ???
613 #% readdirattr vp L L L
617 IN struct attrlist *alist;
618 INOUT struct uio *uio;
621 OUT u_long *newstate;
623 OUT u_long *actualCount;
624 OUT u_long **cookies;
625 IN kauth_cred_t cred;
630 hfs_vnop_readdirattr(ap
)
631 struct vnop_readdirattr_args
/* {
633 struct attrlist *a_alist;
639 u_long *a_actualcount;
640 vfs_context_t a_context;
643 struct vnode
*dvp
= ap
->a_vp
;
645 struct hfsmount
* hfsmp
;
646 struct attrlist
*alist
= ap
->a_alist
;
647 uio_t uio
= ap
->a_uio
;
648 int maxcount
= ap
->a_maxcount
;
649 struct proc
*p
= vfs_context_proc(ap
->a_context
);
650 uint32_t fixedblocksize
;
651 uint32_t maxattrblocksize
;
652 uint32_t currattrbufsize
;
653 void *attrbufptr
= NULL
;
656 struct attrblock attrblk
;
661 struct cat_desc
*lastdescp
= NULL
;
662 struct cat_entrylist
*ce_list
= NULL
;
663 directoryhint_t
*dirhint
= NULL
;
665 int shared_cnode_lock
= 0;
667 *(ap
->a_actualcount
) = 0;
668 *(ap
->a_eofflag
) = 0;
670 /* Check for invalid options and buffer space. */
671 if (((ap
->a_options
& ~(FSOPT_NOINMEMUPDATE
| FSOPT_NOFOLLOW
)) != 0)
672 || (uio_resid(uio
) <= 0) || (uio_iovcnt(uio
) > 1) || (maxcount
<= 0))
675 /* This call doesn't take volume attributes. */
676 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
677 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
678 (alist
->volattr
!= 0) ||
679 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
680 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0))
683 if ((error
= hfs_lock(VTOC(dvp
), HFS_EXCLUSIVE_LOCK
)))
688 /* Reject requests for unsupported options. */
689 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
|
690 ATTR_CMN_OBJPERMANENTID
)) ||
691 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
|
692 ATTR_FILE_FORKLIST
| ATTR_FILE_DATAEXTENTS
| ATTR_FILE_RSRCEXTENTS
))) {
693 printf("readdirattr: unsupported attributes! (%s)\n", dcp
->c_desc
.cd_nameptr
);
698 dir_entries
= dcp
->c_entries
;
699 if (dcp
->c_attr
.ca_fileid
== kHFSRootFolderID
&& (hfsmp
->jnl
|| ((HFSTOVCB(hfsmp
)->vcbAtrb
& kHFSVolumeJournaledMask
) && (hfsmp
->hfs_flags
& HFS_READ_ONLY
)))) {
703 /* Convert uio_offset into a directory index. */
704 index
= uio_offset(uio
) & HFS_INDEX_MASK
;
705 tag
= uio_offset(uio
) & ~HFS_INDEX_MASK
;
706 if ((index
+ 1) > dir_entries
) {
707 *(ap
->a_eofflag
) = 1;
712 /* Get a buffer to hold packed attributes. */
713 fixedblocksize
= (sizeof(uint32_t) + hfs_attrblksize(alist
)); /* 4 bytes for length */
714 maxattrblocksize
= fixedblocksize
;
715 if (alist
->commonattr
& ATTR_CMN_NAME
)
716 maxattrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
717 MALLOC(attrbufptr
, void *, maxattrblocksize
, M_TEMP
, M_WAITOK
);
718 attrptr
= attrbufptr
;
719 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
721 /* Initialize a catalog entry list. */
722 MALLOC(ce_list
, struct cat_entrylist
*, sizeof(*ce_list
), M_TEMP
, M_WAITOK
);
723 bzero(ce_list
, sizeof(*ce_list
));
724 ce_list
->maxentries
= MAXCATENTRIES
;
726 /* Get a directory hint (cnode must be locked exclusive) */
727 dirhint
= hfs_getdirhint(dcp
, ((index
- 1) & HFS_INDEX_MASK
) | tag
);
729 /* Hide tag from catalog layer. */
730 dirhint
->dh_index
&= HFS_INDEX_MASK
;
731 if (dirhint
->dh_index
== HFS_INDEX_MASK
) {
732 dirhint
->dh_index
= -1;
736 * An ATTR_CMN_USERACCESS attribute request can result in a
737 * call to kauth_cred_ismember_gid(). So when requesting
738 * this attribute we downgrade our exclusive lock on dcp to
739 * a shared lock in case kauth_cred_ismember_gid generates
740 * an indirect call back into the file system.
742 if (alist
->commonattr
& ATTR_CMN_USERACCESS
) {
743 lck_rw_lock_exclusive_to_shared(&dcp
->c_rwlock
);
744 dcp
->c_lockowner
= HFS_SHARED_OWNER
;
745 shared_cnode_lock
= 1;
748 * Obtain a list of catalog entries and pack their attributes until
749 * the output buffer is full or maxcount entries have been packed.
755 /* Constrain our list size. */
756 maxentries
= uio_resid(uio
) / (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
);
757 maxentries
= min(maxentries
, dcp
->c_entries
- index
);
758 maxentries
= min(maxentries
, maxcount
);
759 ce_list
->maxentries
= min(maxentries
, ce_list
->maxentries
);
762 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
764 error
= cat_getentriesattr(hfsmp
, dirhint
, ce_list
);
765 /* Don't forget to release the descriptors later! */
767 hfs_systemfile_unlock(hfsmp
, lockflags
);
769 if (error
== ENOENT
) {
770 *(ap
->a_eofflag
) = TRUE
;
777 /* Process the catalog entries. */
778 for (i
= 0; i
< (int)ce_list
->realentries
; ++i
) {
779 struct cnode
*cp
= NULL
;
780 struct vnode
*vp
= NULL
;
781 struct cat_desc
* cdescp
;
782 struct cat_attr
* cattrp
;
783 struct cat_fork c_datafork
;
784 struct cat_fork c_rsrcfork
;
786 bzero(&c_datafork
, sizeof(c_datafork
));
787 bzero(&c_rsrcfork
, sizeof(c_rsrcfork
));
788 cdescp
= &ce_list
->entry
[i
].ce_desc
;
789 cattrp
= &ce_list
->entry
[i
].ce_attr
;
790 c_datafork
.cf_size
= ce_list
->entry
[i
].ce_datasize
;
791 c_datafork
.cf_blocks
= ce_list
->entry
[i
].ce_datablks
;
792 c_rsrcfork
.cf_size
= ce_list
->entry
[i
].ce_rsrcsize
;
793 c_rsrcfork
.cf_blocks
= ce_list
->entry
[i
].ce_rsrcblks
;
795 * Get in memory cnode data (if any).
797 if (!(ap
->a_options
& FSOPT_NOINMEMUPDATE
)) {
798 vp
= hfs_chash_getvnode(dcp
->c_dev
, cattrp
->ca_fileid
, 0, 0);
802 /* Only use cnode's decriptor for non-hardlinks */
803 if (!(cp
->c_flag
& C_HARDLINK
))
804 cdescp
= &cp
->c_desc
;
805 cattrp
= &cp
->c_attr
;
806 if (cp
->c_datafork
) {
807 c_datafork
.cf_size
= cp
->c_datafork
->ff_size
;
808 c_datafork
.cf_blocks
= cp
->c_datafork
->ff_blocks
;
810 if (cp
->c_rsrcfork
) {
811 c_rsrcfork
.cf_size
= cp
->c_rsrcfork
->ff_size
;
812 c_rsrcfork
.cf_blocks
= cp
->c_rsrcfork
->ff_blocks
;
816 *((uint32_t *)attrptr
)++ = 0; /* move it past length */
817 attrblk
.ab_attrlist
= alist
;
818 attrblk
.ab_attrbufpp
= &attrptr
;
819 attrblk
.ab_varbufpp
= &varptr
;
820 attrblk
.ab_flags
= 0;
821 attrblk
.ab_blocksize
= maxattrblocksize
;
823 /* Pack catalog entries into attribute buffer. */
824 hfs_packattrblk(&attrblk
, hfsmp
, vp
, cdescp
, cattrp
,
825 &c_datafork
, &c_rsrcfork
, p
);
826 currattrbufsize
= ((char *)varptr
- (char *)attrbufptr
);
828 /* All done with cnode. */
830 hfs_unlock(VTOC(vp
));
836 /* Make sure there's enough buffer space remaining. */
837 // LP64todo - fix this!
838 if (uio_resid(uio
) < 0 || currattrbufsize
> (uint32_t)uio_resid(uio
)) {
842 *((uint32_t *)attrbufptr
) = currattrbufsize
;
843 error
= uiomove((caddr_t
)attrbufptr
, currattrbufsize
, ap
->a_uio
);
844 if (error
!= E_NONE
) {
848 attrptr
= attrbufptr
;
849 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
850 /* Save the last valid catalog entry */
851 lastdescp
= &ce_list
->entry
[i
].ce_desc
;
853 *ap
->a_actualcount
+= 1;
855 /* Termination checks */
856 if ((--maxcount
<= 0) ||
857 // LP64todo - fix this!
858 uio_resid(uio
) < 0 ||
859 ((uint32_t)uio_resid(uio
) < (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
)) ||
860 (index
>= dir_entries
)) {
865 } /* for each catalog entry */
867 /* If there are more entries then save the last name. */
868 if (index
< dir_entries
869 && !(*(ap
->a_eofflag
))
870 && lastdescp
!= NULL
) {
872 /* Remember last entry */
873 if (dirhint
->dh_desc
.cd_nameptr
!= NULL
) {
874 vfs_removename(dirhint
->dh_desc
.cd_nameptr
);
876 dirhint
->dh_desc
.cd_namelen
= lastdescp
->cd_namelen
;
877 dirhint
->dh_desc
.cd_nameptr
=
878 vfs_addname(lastdescp
->cd_nameptr
, lastdescp
->cd_namelen
, 0, 0);
879 dirhint
->dh_index
= index
- 1;
880 dirhint
->dh_desc
.cd_cnid
= lastdescp
->cd_cnid
;
881 dirhint
->dh_desc
.cd_hint
= lastdescp
->cd_hint
;
882 dirhint
->dh_desc
.cd_encoding
= lastdescp
->cd_encoding
;
885 /* All done with the catalog descriptors. */
886 for (i
= 0; i
< (int)ce_list
->realentries
; ++i
)
887 cat_releasedesc(&ce_list
->entry
[i
].ce_desc
);
888 ce_list
->realentries
= 0;
890 } /* while not depleted */
892 *ap
->a_newstate
= dcp
->c_mtime
;
894 /* Make sure dcp is locked exclusive before changing c_dirhinttag. */
895 if (shared_cnode_lock
) {
897 * If the upgrade fails we loose the lock and
898 * have to take the exclusive lock on our own.
900 if (lck_rw_lock_shared_to_exclusive(&dcp
->c_rwlock
) != 0)
901 lck_rw_lock_exclusive(&dcp
->c_rwlock
);
902 dcp
->c_lockowner
= current_thread();
903 shared_cnode_lock
= 0;
906 /* Convert directory index back into a uio_offset. */
907 while (tag
== 0) tag
= (++dcp
->c_dirhinttag
) << HFS_INDEX_BITS
;
908 uio_setoffset(uio
, index
| tag
);
909 dirhint
->dh_index
|= tag
;
912 /* Drop directory hint on error or if there are no more entries */
913 if (dirhint
&& (error
|| index
>= dir_entries
)) {
914 if (shared_cnode_lock
) {
916 * If the upgrade fails we loose the lock and
917 * have to take the exclusive lock on our own.
919 if (lck_rw_lock_shared_to_exclusive(&dcp
->c_rwlock
) != 0)
920 lck_rw_lock_exclusive(&dcp
->c_rwlock
);
921 dcp
->c_lockowner
= current_thread();
923 hfs_reldirhint(dcp
, dirhint
);
926 FREE(attrbufptr
, M_TEMP
);
928 FREE(ce_list
, M_TEMP
);
935 /*==================== Attribute list support routines ====================*/
938 * Pack cnode attributes into an attribute block.
942 hfs_packattrblk(struct attrblock
*abp
,
943 struct hfsmount
*hfsmp
,
945 struct cat_desc
*descp
,
946 struct cat_attr
*attrp
,
947 struct cat_fork
*datafork
,
948 struct cat_fork
*rsrcfork
,
951 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
953 if (attrlistp
->volattr
) {
954 if (attrlistp
->commonattr
)
955 packvolcommonattr(abp
, hfsmp
, vp
, p
);
957 if (attrlistp
->volattr
& ~ATTR_VOL_INFO
)
958 packvolattr(abp
, hfsmp
, vp
);
960 if (attrlistp
->commonattr
)
961 packcommonattr(abp
, hfsmp
, vp
, descp
, attrp
, p
);
963 if (attrlistp
->dirattr
&& S_ISDIR(attrp
->ca_mode
))
964 packdirattr(abp
, hfsmp
, vp
, descp
,attrp
);
966 if (attrlistp
->fileattr
&& !S_ISDIR(attrp
->ca_mode
))
967 packfileattr(abp
, hfsmp
, attrp
, datafork
, rsrcfork
);
973 mountpointname(struct mount
*mp
)
975 size_t namelength
= strlen(mp
->mnt_vfsstat
.f_mntonname
);
983 * Look backwards through the name string, looking for
984 * the first slash encountered (which must precede the
985 * last part of the pathname).
987 for (c
= mp
->mnt_vfsstat
.f_mntonname
+ namelength
- 1;
988 namelength
> 0; --c
, --namelength
) {
991 } else if (foundchars
) {
996 return (mp
->mnt_vfsstat
.f_mntonname
);
1002 struct attrblock
*abp
,
1008 struct attrreference
* attr_refptr
;
1011 uint32_t attrlength
;
1014 /* A cnode's name may be incorrect for the root of a mounted
1015 * filesystem (it can be mounted on a different directory name
1016 * than the name of the volume, such as "blah-1"). So for the
1017 * root directory, it's best to return the last element of the
1018 location where the volume's mounted:
1020 if ((vp
!= NULL
) && vnode_isvroot(vp
) &&
1021 (mpname
= mountpointname(vnode_mount(vp
)))) {
1022 mpnamelen
= strlen(mpname
);
1024 /* Trim off any trailing slashes: */
1025 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/'))
1028 /* If there's anything left, use it instead of the volume's name */
1029 if (mpnamelen
> 0) {
1031 namelen
= mpnamelen
;
1039 varbufptr
= *abp
->ab_varbufpp
;
1040 attr_refptr
= (struct attrreference
*)(*abp
->ab_attrbufpp
);
1042 attrlength
= namelen
+ 1;
1043 attr_refptr
->attr_dataoffset
= (char *)varbufptr
- (char *)attr_refptr
;
1044 attr_refptr
->attr_length
= attrlength
;
1045 (void) strncpy((unsigned char *)varbufptr
, name
, attrlength
);
1047 * Advance beyond the space just allocated and
1048 * round up to the next 4-byte boundary:
1050 (char *)(varbufptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1053 *abp
->ab_attrbufpp
= attr_refptr
;
1054 *abp
->ab_varbufpp
= varbufptr
;
1058 * Pack common volume attributes.
1061 packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
, struct proc
*p
)
1064 void *attrbufptr
= *abp
->ab_attrbufpp
;
1065 void *varbufptr
= *abp
->ab_varbufpp
;
1066 struct cnode
*cp
= VTOC(vp
);
1067 struct mount
*mp
= VTOVFS(vp
);
1068 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1069 u_int32_t attrlength
;
1070 boolean_t is_64_bit
= proc_is64bit(p
);
1072 attr
= abp
->ab_attrlist
->commonattr
;
1074 if (ATTR_CMN_NAME
& attr
) {
1075 packnameattr(abp
, vp
, cp
->c_desc
.cd_nameptr
, cp
->c_desc
.cd_namelen
);
1076 attrbufptr
= *abp
->ab_attrbufpp
;
1077 varbufptr
= *abp
->ab_varbufpp
;
1079 if (ATTR_CMN_DEVID
& attr
) {
1080 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1082 if (ATTR_CMN_FSID
& attr
) {
1085 fsid
.val
[0] = (long)hfsmp
->hfs_raw_dev
;
1086 fsid
.val
[1] = (long)vfs_typenum(mp
);
1087 *((fsid_t
*)attrbufptr
) = fsid
;
1088 ++((fsid_t
*)attrbufptr
);
1090 if (ATTR_CMN_OBJTYPE
& attr
) {
1091 *((fsobj_type_t
*)attrbufptr
)++ = 0;
1093 if (ATTR_CMN_OBJTAG
& attr
) {
1094 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1096 if (ATTR_CMN_OBJID
& attr
) {
1097 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1098 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1099 ++((fsobj_id_t
*)attrbufptr
);
1101 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1102 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1103 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1104 ++((fsobj_id_t
*)attrbufptr
);
1106 if (ATTR_CMN_PAROBJID
& attr
) {
1107 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1108 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1109 ++((fsobj_id_t
*)attrbufptr
);
1111 if (ATTR_CMN_SCRIPT
& attr
) {
1114 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1115 encoding
= vcb
->volumeNameEncodingHint
;
1117 encoding
= hfsmp
->hfs_encoding
;
1118 *((text_encoding_t
*)attrbufptr
)++ = encoding
;
1120 if (ATTR_CMN_CRTIME
& attr
) {
1122 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbCrDate
;
1123 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1124 ++((struct user_timespec
*)attrbufptr
);
1127 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbCrDate
;
1128 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1129 ++((struct timespec
*)attrbufptr
);
1132 if (ATTR_CMN_MODTIME
& attr
) {
1134 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1135 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1136 ++((struct user_timespec
*)attrbufptr
);
1139 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1140 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1141 ++((struct timespec
*)attrbufptr
);
1144 if (ATTR_CMN_CHGTIME
& attr
) {
1146 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1147 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1148 ++((struct user_timespec
*)attrbufptr
);
1151 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1152 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1153 ++((struct timespec
*)attrbufptr
);
1156 if (ATTR_CMN_ACCTIME
& attr
) {
1158 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1159 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1160 ++((struct user_timespec
*)attrbufptr
);
1163 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1164 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1165 ++((struct timespec
*)attrbufptr
);
1168 if (ATTR_CMN_BKUPTIME
& attr
) {
1170 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbVolBkUp
;
1171 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1172 ++((struct user_timespec
*)attrbufptr
);
1175 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbVolBkUp
;
1176 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1177 ++((struct timespec
*)attrbufptr
);
1180 if (ATTR_CMN_FNDRINFO
& attr
) {
1181 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1182 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1184 if (ATTR_CMN_OWNERID
& attr
) {
1185 if (cp
->c_uid
== UNKNOWNUID
)
1186 *((uid_t
*)attrbufptr
)++ = kauth_cred_getuid(proc_ucred(p
));
1188 *((uid_t
*)attrbufptr
)++ = cp
->c_uid
;
1190 if (ATTR_CMN_GRPID
& attr
) {
1191 *((gid_t
*)attrbufptr
)++ = cp
->c_gid
;
1194 if (ATTR_CMN_ACCESSMASK
& attr
) {
1196 * [2856576] Since we are dynamically changing the owner, also
1197 * effectively turn off the set-user-id and set-group-id bits,
1198 * just like chmod(2) would when changing ownership. This prevents
1199 * a security hole where set-user-id programs run as whoever is
1200 * logged on (or root if nobody is logged in yet!)
1202 *((uint32_t *)attrbufptr
)++ =
1203 (cp
->c_uid
== UNKNOWNUID
) ? cp
->c_mode
& ~(S_ISUID
| S_ISGID
) : cp
->c_mode
;
1205 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1206 *((uint32_t *)attrbufptr
)++ = 0; /* XXX PPD TBC */
1208 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1210 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1211 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1213 * Advance beyond the space just allocated and
1214 * round up to the next 4-byte boundary:
1216 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1217 ++((struct attrreference
*)attrbufptr
);
1219 if (ATTR_CMN_FLAGS
& attr
) {
1220 *((uint32_t *)attrbufptr
)++ = cp
->c_flags
;
1222 if (ATTR_CMN_USERACCESS
& attr
) {
1223 *((uint32_t *)attrbufptr
)++ =
1224 DerivePermissionSummary(cp
->c_uid
, cp
->c_gid
, cp
->c_mode
,
1225 VTOVFS(vp
), kauth_cred_get(), proc_self());
1228 *abp
->ab_attrbufpp
= attrbufptr
;
1229 *abp
->ab_varbufpp
= varbufptr
;
1234 packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
)
1237 void *attrbufptr
= *abp
->ab_attrbufpp
;
1238 void *varbufptr
= *abp
->ab_varbufpp
;
1239 struct cnode
*cp
= VTOC(vp
);
1240 struct mount
*mp
= VTOVFS(vp
);
1241 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1242 uint32_t attrlength
;
1244 attr
= abp
->ab_attrlist
->volattr
;
1246 if (ATTR_VOL_FSTYPE
& attr
) {
1247 *((uint32_t *)attrbufptr
)++ = (uint32_t)vfs_typenum(mp
);
1249 if (ATTR_VOL_SIGNATURE
& attr
) {
1250 *((uint32_t *)attrbufptr
)++ = (uint32_t)vcb
->vcbSigWord
;
1252 if (ATTR_VOL_SIZE
& attr
) {
1253 *((off_t
*)attrbufptr
)++ =
1254 (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1256 if (ATTR_VOL_SPACEFREE
& attr
) {
1257 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 0) *
1258 (off_t
)vcb
->blockSize
;
1260 if (ATTR_VOL_SPACEAVAIL
& attr
) {
1261 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 1) *
1262 (off_t
)vcb
->blockSize
;
1264 if (ATTR_VOL_MINALLOCATION
& attr
) {
1265 *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1267 if (ATTR_VOL_ALLOCATIONCLUMP
& attr
) {
1268 *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1270 if (ATTR_VOL_IOBLOCKSIZE
& attr
) {
1271 *((uint32_t *)attrbufptr
)++ = hfsmp
->hfs_logBlockSize
;
1273 if (ATTR_VOL_OBJCOUNT
& attr
) {
1274 *((uint32_t *)attrbufptr
)++ =
1275 (uint32_t)vcb
->vcbFilCnt
+ (uint32_t)vcb
->vcbDirCnt
;
1277 if (ATTR_VOL_FILECOUNT
& attr
) {
1278 *((uint32_t *)attrbufptr
)++ = (uint32_t)vcb
->vcbFilCnt
;
1280 if (ATTR_VOL_DIRCOUNT
& attr
) {
1281 *((uint32_t *)attrbufptr
)++ = (uint32_t)vcb
->vcbDirCnt
;
1283 if (ATTR_VOL_MAXOBJCOUNT
& attr
) {
1284 *((uint32_t *)attrbufptr
)++ = 0xFFFFFFFF;
1286 if (ATTR_VOL_MOUNTPOINT
& attr
) {
1287 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1288 (char *)varbufptr
- (char *)attrbufptr
;
1289 ((struct attrreference
*)attrbufptr
)->attr_length
=
1290 strlen(mp
->mnt_vfsstat
.f_mntonname
) + 1;
1291 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1292 /* round up to the next 4-byte boundary: */
1293 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1294 (void) bcopy(mp
->mnt_vfsstat
.f_mntonname
, varbufptr
, attrlength
);
1296 /* Advance beyond the space just allocated: */
1297 (char *)varbufptr
+= attrlength
;
1298 ++((struct attrreference
*)attrbufptr
);
1300 if (ATTR_VOL_NAME
& attr
) {
1301 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1302 (char *)varbufptr
- (char *)attrbufptr
;
1303 ((struct attrreference
*)attrbufptr
)->attr_length
=
1304 cp
->c_desc
.cd_namelen
+ 1;
1305 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1306 /* round up to the next 4-byte boundary: */
1307 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1308 /* XXX this could read off the end of cd_nameptr! */
1309 bcopy(cp
->c_desc
.cd_nameptr
, varbufptr
, attrlength
);
1311 /* Advance beyond the space just allocated: */
1312 (char *)varbufptr
+= attrlength
;
1313 ++((struct attrreference
*)attrbufptr
);
1315 if (ATTR_VOL_MOUNTFLAGS
& attr
) {
1316 *((uint32_t *)attrbufptr
)++ = (uint32_t)vfs_flags(mp
);
1318 if (ATTR_VOL_MOUNTEDDEVICE
& attr
) {
1319 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1320 (char *)varbufptr
- (char *)attrbufptr
;
1321 ((struct attrreference
*)attrbufptr
)->attr_length
=
1322 strlen(mp
->mnt_vfsstat
.f_mntfromname
) + 1;
1323 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1324 /* round up to the next 4-byte boundary: */
1325 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1326 (void) bcopy(mp
->mnt_vfsstat
.f_mntfromname
, varbufptr
, attrlength
);
1328 /* Advance beyond the space just allocated: */
1329 (char *)varbufptr
+= attrlength
;
1330 ++((struct attrreference
*)attrbufptr
);
1332 if (ATTR_VOL_ENCODINGSUSED
& attr
) {
1333 *((unsigned long long *)attrbufptr
)++ =
1334 (unsigned long long)vcb
->encodingsBitmap
;
1336 if (ATTR_VOL_CAPABILITIES
& attr
) {
1337 vol_capabilities_attr_t
*vcapattrptr
;
1339 vcapattrptr
= (vol_capabilities_attr_t
*)attrbufptr
;
1341 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1342 u_int32_t journal_active_cap
;
1343 u_int32_t case_sensitive
;
1346 journal_active_cap
= VOL_CAP_FMT_JOURNAL_ACTIVE
;
1348 journal_active_cap
= 0;
1350 if (hfsmp
->hfs_flags
& HFS_CASE_SENSITIVE
)
1351 case_sensitive
= VOL_CAP_FMT_CASE_SENSITIVE
;
1355 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1356 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1357 VOL_CAP_FMT_SYMBOLICLINKS
|
1358 VOL_CAP_FMT_HARDLINKS
|
1359 VOL_CAP_FMT_JOURNAL
|
1360 journal_active_cap
|
1362 VOL_CAP_FMT_CASE_PRESERVING
|
1363 VOL_CAP_FMT_FAST_STATFS
|
1364 VOL_CAP_FMT_2TB_FILESIZE
;
1365 } else { /* Plain HFS */
1366 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1367 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1368 VOL_CAP_FMT_CASE_PRESERVING
|
1369 VOL_CAP_FMT_FAST_STATFS
;
1371 vcapattrptr
->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1372 VOL_CAP_INT_SEARCHFS
|
1373 VOL_CAP_INT_ATTRLIST
|
1374 VOL_CAP_INT_NFSEXPORT
|
1375 VOL_CAP_INT_READDIRATTR
|
1376 VOL_CAP_INT_EXCHANGEDATA
|
1377 VOL_CAP_INT_ALLOCATE
|
1378 VOL_CAP_INT_VOL_RENAME
|
1379 VOL_CAP_INT_ADVLOCK
|
1381 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1382 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1384 vcapattrptr
->valid
[VOL_CAPABILITIES_FORMAT
] =
1385 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1386 VOL_CAP_FMT_SYMBOLICLINKS
|
1387 VOL_CAP_FMT_HARDLINKS
|
1388 VOL_CAP_FMT_JOURNAL
|
1389 VOL_CAP_FMT_JOURNAL_ACTIVE
|
1390 VOL_CAP_FMT_NO_ROOT_TIMES
|
1391 VOL_CAP_FMT_SPARSE_FILES
|
1392 VOL_CAP_FMT_ZERO_RUNS
|
1393 VOL_CAP_FMT_CASE_SENSITIVE
|
1394 VOL_CAP_FMT_CASE_PRESERVING
|
1395 VOL_CAP_FMT_FAST_STATFS
|
1396 VOL_CAP_FMT_2TB_FILESIZE
;
1397 vcapattrptr
->valid
[VOL_CAPABILITIES_INTERFACES
] =
1398 VOL_CAP_INT_SEARCHFS
|
1399 VOL_CAP_INT_ATTRLIST
|
1400 VOL_CAP_INT_NFSEXPORT
|
1401 VOL_CAP_INT_READDIRATTR
|
1402 VOL_CAP_INT_EXCHANGEDATA
|
1403 VOL_CAP_INT_COPYFILE
|
1404 VOL_CAP_INT_ALLOCATE
|
1405 VOL_CAP_INT_VOL_RENAME
|
1406 VOL_CAP_INT_ADVLOCK
|
1408 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1409 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1411 ++((vol_capabilities_attr_t
*)attrbufptr
);
1413 if (ATTR_VOL_ATTRIBUTES
& attr
) {
1414 vol_attributes_attr_t
*volattrattrp
;
1416 volattrattrp
= (vol_attributes_attr_t
*)attrbufptr
;
1417 volattrattrp
->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1418 volattrattrp
->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
1419 volattrattrp
->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1420 volattrattrp
->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1421 volattrattrp
->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1423 volattrattrp
->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1424 volattrattrp
->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
1425 volattrattrp
->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1426 volattrattrp
->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1427 volattrattrp
->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1428 ++((vol_attributes_attr_t
*)attrbufptr
);
1431 *abp
->ab_attrbufpp
= attrbufptr
;
1432 *abp
->ab_varbufpp
= varbufptr
;
1438 struct attrblock
*abp
,
1439 struct hfsmount
*hfsmp
,
1441 struct cat_desc
* cdp
,
1442 struct cat_attr
* cap
,
1445 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1446 struct mount
*mp
= HFSTOVFS(hfsmp
);
1447 void *attrbufptr
= *abp
->ab_attrbufpp
;
1448 void *varbufptr
= *abp
->ab_varbufpp
;
1449 uint32_t attrlength
= 0;
1450 boolean_t is_64_bit
= proc_is64bit(p
);
1452 if (ATTR_CMN_NAME
& attr
) {
1453 packnameattr(abp
, vp
, cdp
->cd_nameptr
, cdp
->cd_namelen
);
1454 attrbufptr
= *abp
->ab_attrbufpp
;
1455 varbufptr
= *abp
->ab_varbufpp
;
1457 if (ATTR_CMN_DEVID
& attr
) {
1458 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1460 if (ATTR_CMN_FSID
& attr
) {
1463 fsid
.val
[0] = (long)hfsmp
->hfs_raw_dev
;
1464 fsid
.val
[1] = (long)vfs_typenum(mp
);
1465 *((fsid_t
*)attrbufptr
) = fsid
;
1466 ++((fsid_t
*)attrbufptr
);
1468 if (ATTR_CMN_OBJTYPE
& attr
) {
1469 *((fsobj_type_t
*)attrbufptr
)++ = IFTOVT(cap
->ca_mode
);
1471 if (ATTR_CMN_OBJTAG
& attr
) {
1472 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1475 * Exporting file IDs from HFS Plus:
1477 * For "normal" files the c_fileid is the same value as the
1478 * c_cnid. But for hard link files, they are different - the
1479 * c_cnid belongs to the active directory entry (ie the link)
1480 * and the c_fileid is for the actual inode (ie the data file).
1482 * The stat call (getattr) will always return the c_fileid
1483 * and Carbon APIs, which are hardlink-ignorant, will always
1484 * receive the c_cnid (from getattrlist).
1486 if (ATTR_CMN_OBJID
& attr
) {
1487 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1488 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1489 ++((fsobj_id_t
*)attrbufptr
);
1491 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1492 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1493 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1494 ++((fsobj_id_t
*)attrbufptr
);
1496 if (ATTR_CMN_PAROBJID
& attr
) {
1497 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_parentcnid
;
1498 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1499 ++((fsobj_id_t
*)attrbufptr
);
1501 if (ATTR_CMN_SCRIPT
& attr
) {
1502 *((text_encoding_t
*)attrbufptr
)++ = cdp
->cd_encoding
;
1504 if (ATTR_CMN_CRTIME
& attr
) {
1506 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_itime
;
1507 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1508 ++((struct user_timespec
*)attrbufptr
);
1511 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_itime
;
1512 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1513 ++((struct timespec
*)attrbufptr
);
1516 if (ATTR_CMN_MODTIME
& attr
) {
1518 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_mtime
;
1519 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1520 ++((struct user_timespec
*)attrbufptr
);
1523 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_mtime
;
1524 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1525 ++((struct timespec
*)attrbufptr
);
1528 if (ATTR_CMN_CHGTIME
& attr
) {
1530 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_ctime
;
1531 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1532 ++((struct user_timespec
*)attrbufptr
);
1535 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_ctime
;
1536 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1537 ++((struct timespec
*)attrbufptr
);
1540 if (ATTR_CMN_ACCTIME
& attr
) {
1542 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_atime
;
1543 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1544 ++((struct user_timespec
*)attrbufptr
);
1547 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_atime
;
1548 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1549 ++((struct timespec
*)attrbufptr
);
1552 if (ATTR_CMN_BKUPTIME
& attr
) {
1554 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_btime
;
1555 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1556 ++((struct user_timespec
*)attrbufptr
);
1559 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_btime
;
1560 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1561 ++((struct timespec
*)attrbufptr
);
1564 if (ATTR_CMN_FNDRINFO
& attr
) {
1565 bcopy(&cap
->ca_finderinfo
, attrbufptr
, sizeof(u_int8_t
) * 32);
1566 (char *)attrbufptr
+= sizeof(u_int8_t
) * 32;
1568 if (ATTR_CMN_OWNERID
& attr
) {
1569 *((uid_t
*)attrbufptr
)++ =
1570 (cap
->ca_uid
== UNKNOWNUID
) ? kauth_cred_getuid(proc_ucred(p
)) : cap
->ca_uid
;
1572 if (ATTR_CMN_GRPID
& attr
) {
1573 *((gid_t
*)attrbufptr
)++ = cap
->ca_gid
;
1575 if (ATTR_CMN_ACCESSMASK
& attr
) {
1577 * [2856576] Since we are dynamically changing the owner, also
1578 * effectively turn off the set-user-id and set-group-id bits,
1579 * just like chmod(2) would when changing ownership. This prevents
1580 * a security hole where set-user-id programs run as whoever is
1581 * logged on (or root if nobody is logged in yet!)
1583 *((uint32_t *)attrbufptr
)++ =
1584 (cap
->ca_uid
== UNKNOWNUID
) ? cap
->ca_mode
& ~(S_ISUID
| S_ISGID
) : cap
->ca_mode
;
1586 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1587 *((uint32_t *)attrbufptr
)++ = 0;
1589 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1591 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1592 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1594 * Advance beyond the space just allocated and
1595 * round up to the next 4-byte boundary:
1597 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1598 ++((struct attrreference
*)attrbufptr
);
1600 if (ATTR_CMN_FLAGS
& attr
) {
1601 *((uint32_t *)attrbufptr
)++ = cap
->ca_flags
;
1603 if (ATTR_CMN_USERACCESS
& attr
) {
1604 *((uint32_t *)attrbufptr
)++ =
1605 DerivePermissionSummary(cap
->ca_uid
, cap
->ca_gid
,
1606 cap
->ca_mode
, mp
, proc_ucred(current_proc()),
1610 *abp
->ab_attrbufpp
= attrbufptr
;
1611 *abp
->ab_varbufpp
= varbufptr
;
1616 struct attrblock
*abp
,
1617 struct hfsmount
*hfsmp
,
1619 struct cat_desc
* descp
,
1620 struct cat_attr
* cattrp
)
1622 attrgroup_t attr
= abp
->ab_attrlist
->dirattr
;
1623 void *attrbufptr
= *abp
->ab_attrbufpp
;
1625 if (ATTR_DIR_LINKCOUNT
& attr
)
1626 *((uint32_t *)attrbufptr
)++ = cattrp
->ca_nlink
;
1627 if (ATTR_DIR_ENTRYCOUNT
& attr
) {
1628 uint32_t entries
= cattrp
->ca_entries
;
1630 if (descp
->cd_parentcnid
== kHFSRootParentID
) {
1631 if (hfsmp
->hfs_privdir_desc
.cd_cnid
!= 0)
1632 --entries
; /* hide private dir */
1633 if (hfsmp
->jnl
|| ((HFSTOVCB(hfsmp
)->vcbAtrb
& kHFSVolumeJournaledMask
) && (hfsmp
->hfs_flags
& HFS_READ_ONLY
)))
1634 entries
-= 2; /* hide the journal files */
1637 *((uint32_t *)attrbufptr
)++ = entries
;
1639 if (ATTR_DIR_MOUNTSTATUS
& attr
) {
1640 if (vp
!= NULL
&& vnode_mountedhere(vp
) != NULL
)
1641 *((uint32_t *)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
1643 *((uint32_t *)attrbufptr
)++ = 0;
1645 *abp
->ab_attrbufpp
= attrbufptr
;
1650 struct attrblock
*abp
,
1651 struct hfsmount
*hfsmp
,
1652 struct cat_attr
*cattrp
,
1653 struct cat_fork
*datafork
,
1654 struct cat_fork
*rsrcfork
)
1656 attrgroup_t attr
= abp
->ab_attrlist
->fileattr
;
1657 void *attrbufptr
= *abp
->ab_attrbufpp
;
1658 void *varbufptr
= *abp
->ab_varbufpp
;
1659 uint32_t attrlength
;
1660 uint32_t allocblksize
;
1662 allocblksize
= HFSTOVCB(hfsmp
)->blockSize
;
1664 if (ATTR_FILE_LINKCOUNT
& attr
) {
1665 *((uint32_t *)attrbufptr
)++ = cattrp
->ca_nlink
;
1667 if (ATTR_FILE_TOTALSIZE
& attr
) {
1668 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
+ rsrcfork
->cf_size
;
1670 if (ATTR_FILE_ALLOCSIZE
& attr
) {
1671 *((off_t
*)attrbufptr
)++ =
1672 (off_t
)cattrp
->ca_blocks
* (off_t
)allocblksize
;
1674 if (ATTR_FILE_IOBLOCKSIZE
& attr
) {
1675 *((uint32_t *)attrbufptr
)++ = hfsmp
->hfs_logBlockSize
;
1677 if (ATTR_FILE_CLUMPSIZE
& attr
) {
1678 *((uint32_t *)attrbufptr
)++ = HFSTOVCB(hfsmp
)->vcbClpSiz
;
1680 if (ATTR_FILE_DEVTYPE
& attr
) {
1681 if (S_ISBLK(cattrp
->ca_mode
) || S_ISCHR(cattrp
->ca_mode
))
1682 *((uint32_t *)attrbufptr
)++ = (uint32_t)cattrp
->ca_rdev
;
1684 *((uint32_t *)attrbufptr
)++ = 0;
1686 if (ATTR_FILE_FILETYPE
& attr
) {
1687 *((uint32_t *)attrbufptr
)++ = 0;
1689 if (ATTR_FILE_FORKCOUNT
& attr
) {
1690 *((uint32_t *)attrbufptr
)++ = 2;
1692 if (ATTR_FILE_FORKLIST
& attr
) {
1694 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1695 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1697 * Advance beyond the space just allocated and
1698 * round up to the next 4-byte boundary:
1700 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1701 ++((struct attrreference
*)attrbufptr
);
1703 if (ATTR_FILE_DATALENGTH
& attr
) {
1704 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
;
1706 if (ATTR_FILE_DATAALLOCSIZE
& attr
) {
1707 *((off_t
*)attrbufptr
)++ =
1708 (off_t
)datafork
->cf_blocks
* (off_t
)allocblksize
;
1710 if (ATTR_FILE_DATAEXTENTS
& attr
) {
1711 bcopy(&datafork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1712 (char *)attrbufptr
+= sizeof(extentrecord
);
1714 if (ATTR_FILE_RSRCLENGTH
& attr
) {
1715 *((off_t
*)attrbufptr
)++ = rsrcfork
->cf_size
;
1717 if (ATTR_FILE_RSRCALLOCSIZE
& attr
) {
1718 *((off_t
*)attrbufptr
)++ =
1719 (off_t
)rsrcfork
->cf_blocks
* (off_t
)allocblksize
;
1721 if (ATTR_FILE_RSRCEXTENTS
& attr
) {
1722 bcopy(&rsrcfork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1723 (char *)attrbufptr
+= sizeof(extentrecord
);
1725 *abp
->ab_attrbufpp
= attrbufptr
;
1726 *abp
->ab_varbufpp
= varbufptr
;
1731 unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
)
1733 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
1736 if (attrlistp
->volattr
) {
1737 error
= unpackvolattr(abp
, VTOHFS(vp
), vp
);
1740 } else if (attrlistp
->commonattr
) {
1741 unpackcommonattr(abp
, vp
);
1749 struct attrblock
*abp
,
1752 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1753 void *attrbufptr
= *abp
->ab_attrbufpp
;
1754 struct cnode
*cp
= VTOC(vp
);
1755 boolean_t is_64_bit
= proc_is64bit(current_proc());
1757 if (ATTR_CMN_SCRIPT
& attr
) {
1758 cp
->c_encoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
1759 hfs_setencodingbits(VTOHFS(vp
), cp
->c_encoding
);
1761 if (ATTR_CMN_CRTIME
& attr
) {
1763 cp
->c_itime
= ((struct user_timespec
*)attrbufptr
)->tv_sec
;
1764 ++((struct user_timespec
*)attrbufptr
);
1767 cp
->c_itime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1768 ++((struct timespec
*)attrbufptr
);
1771 if (ATTR_CMN_MODTIME
& attr
) {
1772 cp
->c_mtime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1773 ++((struct timespec
*)attrbufptr
);
1774 cp
->c_touch_modtime
= FALSE
;
1776 if (ATTR_CMN_CHGTIME
& attr
) {
1777 cp
->c_ctime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1778 ++((struct timespec
*)attrbufptr
);
1779 cp
->c_touch_chgtime
= FALSE
;
1781 if (ATTR_CMN_ACCTIME
& attr
) {
1782 cp
->c_atime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1783 ++((struct timespec
*)attrbufptr
);
1784 cp
->c_touch_acctime
= FALSE
;
1786 if (ATTR_CMN_BKUPTIME
& attr
) {
1787 cp
->c_btime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1788 ++((struct timespec
*)attrbufptr
);
1790 if (ATTR_CMN_FNDRINFO
& attr
) {
1791 bcopy(attrbufptr
, &cp
->c_attr
.ca_finderinfo
,
1792 sizeof(cp
->c_attr
.ca_finderinfo
));
1793 (char *)attrbufptr
+= sizeof(cp
->c_attr
.ca_finderinfo
);
1795 if (ATTR_CMN_OWNERID
& attr
) {
1796 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1797 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
1798 if (uid
!= (uid_t
)VNOVAL
)
1801 ((uid_t
*)attrbufptr
)++;
1804 if (ATTR_CMN_GRPID
& attr
) {
1805 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
1806 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1807 if (gid
!= (gid_t
)VNOVAL
)
1811 if (ATTR_CMN_ACCESSMASK
& attr
) {
1812 u_int16_t mode
= (u_int16_t
)*((uint32_t *)attrbufptr
)++;
1813 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1814 if (mode
!= (mode_t
)VNOVAL
) {
1815 cp
->c_mode
&= ~ALLPERMS
;
1816 cp
->c_mode
|= (mode
& ALLPERMS
);
1820 if (ATTR_CMN_FLAGS
& attr
) {
1821 uint32_t flags
= *((uint32_t *)attrbufptr
)++;
1823 * Flags are settable only on HFS+ volumes. A special
1824 * exception is made for the IMMUTABLE flags
1825 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1826 * HFS volumes as well:
1828 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
1829 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) &&
1830 ((flags
& ~IMMUTABLE
) == 0))) {
1831 if (flags
!= (uint32_t)VNOVAL
) {
1832 cp
->c_flags
= flags
;
1836 *abp
->ab_attrbufpp
= attrbufptr
;
1842 struct attrblock
*abp
,
1843 struct hfsmount
*hfsmp
,
1844 struct vnode
*root_vp
)
1846 void *attrbufptr
= *abp
->ab_attrbufpp
;
1849 boolean_t is_64_bit
= proc_is64bit(current_proc());
1851 HFS_MOUNT_LOCK(hfsmp
, TRUE
);
1853 attr
= abp
->ab_attrlist
->commonattr
;
1857 if (ATTR_CMN_SCRIPT
& attr
) {
1858 hfsmp
->volumeNameEncodingHint
=
1859 (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
1861 if (ATTR_CMN_CRTIME
& attr
) {
1863 hfsmp
->vcbCrDate
= ((struct user_timespec
*)attrbufptr
)->tv_sec
;
1864 ++((struct user_timespec
*)attrbufptr
);
1867 hfsmp
->vcbCrDate
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1868 ++((struct timespec
*)attrbufptr
);
1871 /* The volume's create date comes from the root directory */
1872 VTOC(root_vp
)->c_itime
= hfsmp
->vcbCrDate
;
1873 VTOC(root_vp
)->c_flag
|= C_MODIFIED
;
1875 * XXX Should we also do a relative change to the
1876 * the volume header's create date in local time?
1879 if (ATTR_CMN_MODTIME
& attr
) {
1880 hfsmp
->vcbLsMod
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1881 ++((struct timespec
*)attrbufptr
);
1883 if (ATTR_CMN_BKUPTIME
& attr
) {
1884 hfsmp
->vcbVolBkUp
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1885 ++((struct timespec
*)attrbufptr
);
1887 if (ATTR_CMN_FNDRINFO
& attr
) {
1888 bcopy(attrbufptr
, &hfsmp
->vcbFndrInfo
, sizeof(hfsmp
->vcbFndrInfo
));
1889 (char *)attrbufptr
+= sizeof(hfsmp
->vcbFndrInfo
);
1893 attr
= abp
->ab_attrlist
->volattr
& ~ATTR_VOL_INFO
;
1895 * XXX - no validation is done on the name!
1896 * It could be empty or garbage (bad UTF-8).
1898 if (ATTR_VOL_NAME
& attr
) {
1899 attrreference_t
* attr_refp
= (attrreference_t
*) attrbufptr
;
1901 error
= copystr(((char *)attrbufptr
) + attr_refp
->attr_dataoffset
,
1902 hfsmp
->vcbVN
, MIN(attr_refp
->attr_length
, sizeof(hfsmp
->vcbVN
)),
1905 (char *)attrbufptr
+= sizeof(struct attrreference
);
1907 *abp
->ab_attrbufpp
= attrbufptr
;
1909 hfsmp
->vcbFlags
|= 0xFF00;
1910 HFS_MOUNT_UNLOCK(hfsmp
, TRUE
);
1917 * Calculate the total size of an attribute block.
1921 hfs_attrblksize(struct attrlist
*attrlist
)
1925 int sizeof_timespec
;
1926 boolean_t is_64_bit
= proc_is64bit(current_proc());
1929 sizeof_timespec
= sizeof(struct user_timespec
);
1931 sizeof_timespec
= sizeof(struct timespec
);
1933 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1934 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \
1935 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \
1936 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \
1937 ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1938 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \
1939 ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \
1940 != ATTR_CMN_VALIDMASK)
1941 #error hfs_attrblksize: Missing bits in common mask computation!
1943 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1945 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \
1946 ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
1947 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1948 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \
1949 ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \
1950 ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \
1951 ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1952 != ATTR_VOL_VALIDMASK)
1953 #error hfs_attrblksize: Missing bits in volume mask computation!
1955 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1957 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \
1958 != ATTR_DIR_VALIDMASK)
1959 #error hfs_attrblksize: Missing bits in directory mask computation!
1961 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1963 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
1964 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \
1965 ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \
1966 ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1967 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \
1968 != ATTR_FILE_VALIDMASK)
1969 #error hfs_attrblksize: Missing bits in file mask computation!
1971 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1973 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1974 #error hfs_attrblksize: Missing bits in fork mask computation!
1976 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1980 if ((a
= attrlist
->commonattr
) != 0) {
1981 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1982 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1983 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1984 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1985 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1986 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1987 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1988 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1989 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1990 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof_timespec
;
1991 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof_timespec
;
1992 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof_timespec
;
1993 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof_timespec
;
1994 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof_timespec
;
1995 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(u_int8_t
);
1996 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1997 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1998 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(uint32_t);
1999 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(uint32_t);
2000 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
2001 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(uint32_t);
2002 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(uint32_t);
2004 if ((a
= attrlist
->volattr
) != 0) {
2005 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(uint32_t);
2006 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(uint32_t);
2007 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
2008 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
2009 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
2010 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
2011 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
2012 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(uint32_t);
2013 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(uint32_t);
2014 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(uint32_t);
2015 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(uint32_t);
2016 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(uint32_t);
2017 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
2018 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
2019 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(uint32_t);
2020 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
2021 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
2022 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
2023 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
2025 if ((a
= attrlist
->dirattr
) != 0) {
2026 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(uint32_t);
2027 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(uint32_t);
2028 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(uint32_t);
2030 if ((a
= attrlist
->fileattr
) != 0) {
2031 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(uint32_t);
2032 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
2033 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
2034 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(uint32_t);
2035 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(uint32_t);
2036 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(uint32_t);
2037 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(uint32_t);
2038 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(uint32_t);
2039 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
2040 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
2041 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
2042 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
2043 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
2044 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
2045 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
2047 if ((a
= attrlist
->forkattr
) != 0) {
2048 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
2049 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
2058 DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
,
2059 struct mount
*mp
, kauth_cred_t cred
, struct proc
*p
)
2061 unsigned long permissions
;
2063 if (obj_uid
== UNKNOWNUID
)
2064 obj_uid
= kauth_cred_getuid(proc_ucred(p
));
2066 /* User id 0 (root) always gets access. */
2067 if (!suser(cred
, NULL
)) {
2068 permissions
= R_OK
| W_OK
| X_OK
;
2072 /* Otherwise, check the owner. */
2073 if (hfs_owner_rights(VFSTOHFS(mp
), obj_uid
, cred
, p
, false) == 0) {
2074 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
2078 /* Otherwise, check the groups. */
2079 if (! (((unsigned int)vfs_flags(mp
)) & MNT_UNKNOWNPERMISSIONS
)) {
2082 if (kauth_cred_ismember_gid(cred
, obj_gid
, &is_member
) == 0 && is_member
) {
2083 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
2088 /* Otherwise, settle for 'others' access. */
2089 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
2092 return (permissions
);