2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * hfs_attrlist.c - HFS attribute list processing
26 * Copyright (c) 1998-2002, Apple Computer, Inc. All Rights Reserved.
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
35 #include <sys/unistd.h>
36 #include <sys/mount_internal.h>
37 #include <sys/kauth.h>
39 #include <kern/locks.h>
42 #include "hfs_cnode.h"
43 #include "hfs_mount.h"
45 #include "hfs_attrlist.h"
49 /* Routines that are shared by hfs_setattr: */
50 extern int hfs_write_access(struct vnode
*vp
, kauth_cred_t cred
,
51 struct proc
*p
, Boolean considerFlags
);
53 extern int hfs_chflags(struct vnode
*vp
, uint32_t flags
, kauth_cred_t cred
,
56 extern int hfs_chmod(struct vnode
*vp
, int mode
, kauth_cred_t cred
,
59 extern int hfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, kauth_cred_t cred
,
62 __private_extern__
int hfs_vnop_readdirattr(struct vnop_readdirattr_args
*ap
);
64 __private_extern__
int hfs_vnop_setattrlist(struct vnop_setattrlist_args
*ap
);
66 __private_extern__
int hfs_vnop_getattrlist(struct vnop_getattrlist_args
*ap
);
68 /* Packing routines: */
71 static void packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
72 struct vnode
*vp
, struct proc
*p
);
74 static void packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
77 static void packcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
78 struct vnode
*vp
, struct cat_desc
* cdp
,
79 struct cat_attr
* cap
, struct proc
*p
);
81 static void packfileattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
82 struct cat_attr
*cattrp
, struct cat_fork
*datafork
,
83 struct cat_fork
*rsrcfork
);
85 static void packdirattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
86 struct vnode
*vp
, struct cat_desc
* descp
,
87 struct cat_attr
* cattrp
);
91 static int unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
);
93 static void unpackcommonattr(struct attrblock
*abp
, struct vnode
*vp
);
95 static int unpackvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
96 struct vnode
*root_vp
);
100 * Get a list of attributes.
104 hfs_vnop_getattrlist(ap
)
105 struct vnop_getattrlist_args
/* {
107 struct attrlist *a_alist
110 vfs_context_t a_context;
113 struct vnode
*vp
= ap
->a_vp
;
115 struct hfsmount
*hfsmp
;
116 struct attrlist
*alist
= ap
->a_alist
;
117 proc_t p
= vfs_context_proc(ap
->a_context
);
121 void *attrbufptr
= NULL
;
124 struct attrblock attrblk
;
125 struct cat_fork
*datafp
= NULL
;
126 struct cat_fork
*rsrcfp
= NULL
;
127 struct cat_fork rsrcfork
;
131 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
132 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
133 ((alist
->volattr
& ~ATTR_VOL_VALIDMASK
) != 0) ||
134 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
135 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0)) {
140 * Requesting volume information requires setting the
141 * ATTR_VOL_INFO bit. Also, volume info requests are
142 * mutually exclusive with all other info requests.
144 if ((alist
->volattr
!= 0) &&
145 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
146 (alist
->dirattr
!= 0) || (alist
->fileattr
!= 0))) {
150 /* Reject requests for unsupported options for now: */
151 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
)) ||
152 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
| ATTR_FILE_FORKLIST
))) {
156 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
)))
161 /* Requesting volume information requires root vnode */
162 if ((alist
->volattr
) && cp
->c_fileid
!= kHFSRootFolderID
) {
166 /* Asking for data fork attributes from the rsrc fork is not supported */
167 if (VNODE_IS_RSRC(vp
) && (alist
->fileattr
& ATTR_DATAFORK_MASK
)) {
171 /* This file no longer exists! */
172 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
176 /* This file doesn't have a name! */
177 if ((cp
->c_desc
.cd_namelen
== 0) && (alist
->commonattr
& ATTR_CMN_NAME
)) {
182 /* Update cnode times if needed */
183 hfs_touchtimes(hfsmp
, cp
);
186 * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on
187 * an HFS volume we must be sure to create the thread
188 * record before returning it. (yikes)
190 if (vnode_isreg(vp
) &&
191 (alist
->commonattr
& ATTR_CMN_OBJPERMANENTID
) &&
192 (VTOVCB(vp
)->vcbSigWord
!= kHFSPlusSigWord
)) {
196 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
) {
200 if ((error
= hfs_write_access(vp
, vfs_context_ucred(ap
->a_context
),
205 * Reserve some space in the Catalog file.
207 bzero(&cookie
, sizeof(cookie
));
208 error
= cat_preflight(hfsmp
, CAT_CREATE
, &cookie
, p
);
213 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
215 error
= cat_insertfilethread(hfsmp
, &cp
->c_desc
);
217 hfs_systemfile_unlock(hfsmp
, lockflags
);
219 cat_postflight(hfsmp
, &cookie
, p
);
224 bzero(&rsrcfork
, sizeof(rsrcfork
));
225 /* Establish known fork data */
226 if (cp
->c_datafork
!= NULL
) {
227 datafp
= &cp
->c_datafork
->ff_data
;
228 if ((cp
->c_rsrcfork
== NULL
) &&
229 (cp
->c_blocks
== datafp
->cf_blocks
))
230 rsrcfp
= &rsrcfork
; /* rsrc fork is empty */
232 if (cp
->c_rsrcfork
!= NULL
)
233 rsrcfp
= &cp
->c_rsrcfork
->ff_data
;
236 * When resource fork data is requested and its not available
237 * in the cnode and the fork is not empty then it needs to be
238 * fetched from the catalog.
240 if ((alist
->fileattr
& ATTR_RSRCFORK_MASK
) && (rsrcfp
== NULL
)) {
242 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
244 /* Get resource fork data */
245 error
= cat_lookup(hfsmp
, &cp
->c_desc
, 1,
246 (struct cat_desc
*)0, (struct cat_attr
*)0, &rsrcfork
, NULL
);
248 hfs_systemfile_unlock(hfsmp
, lockflags
);
256 fixedblocksize
= hfs_attrblksize(alist
);
257 attrblocksize
= fixedblocksize
+ (sizeof(uint32_t)); /* uint32_t for length word */
258 if (alist
->commonattr
& ATTR_CMN_NAME
)
259 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
260 if (alist
->volattr
& ATTR_VOL_MOUNTPOINT
)
261 attrblocksize
+= PATH_MAX
;
262 if (alist
->volattr
& ATTR_VOL_NAME
)
263 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
265 if (alist
->commonattr
& ATTR_CMN_NAMEDATTRLIST
)
267 if (alist
->fileattr
& ATTR_FILE_FORKLIST
)
270 attrbufsize
= MIN(uio_resid(ap
->a_uio
), attrblocksize
);
271 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
272 attrptr
= attrbufptr
;
273 *((uint32_t *)attrptr
) = 0; /* Set buffer length in case of errors */
274 ++((uint32_t *)attrptr
); /* Reserve space for length field */
275 varptr
= ((char *)attrptr
) + fixedblocksize
;
277 attrblk
.ab_attrlist
= alist
;
278 attrblk
.ab_attrbufpp
= &attrptr
;
279 attrblk
.ab_varbufpp
= &varptr
;
280 attrblk
.ab_flags
= 0;
281 attrblk
.ab_blocksize
= attrblocksize
;
283 hfs_packattrblk(&attrblk
, hfsmp
, vp
, &cp
->c_desc
, &cp
->c_attr
,
286 /* Don't copy out more data than was generated */
287 attrbufsize
= MIN((u_int
)attrbufsize
, (u_int
)varptr
- (u_int
)attrbufptr
);
288 /* Set actual buffer length for return to caller */
289 *((uint32_t *)attrbufptr
) = attrbufsize
;
290 error
= uiomove((caddr_t
)attrbufptr
, attrbufsize
, ap
->a_uio
);
293 FREE(attrbufptr
, M_TEMP
);
300 * Set a list of attributes.
304 hfs_vnop_setattrlist(ap
)
305 struct vnop_setattrlist_args
/* {
307 struct attrlist *a_alist
310 vfs_context_t a_context;
313 struct vnode
*vp
= ap
->a_vp
;
315 struct hfsmount
* hfsmp
;
316 struct attrlist
*alist
= ap
->a_alist
;
317 kauth_cred_t cred
= vfs_context_ucred(ap
->a_context
);
318 struct proc
*p
= vfs_context_proc(ap
->a_context
);
320 void *attrbufptr
= NULL
;
323 struct attrblock attrblk
;
327 uint32_t saved_flags
;
332 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
)
334 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
335 ((alist
->commonattr
& ~ATTR_CMN_SETMASK
) != 0) ||
336 ((alist
->volattr
& ~ATTR_VOL_SETMASK
) != 0) ||
337 ((alist
->dirattr
& ~ATTR_DIR_SETMASK
) != 0) ||
338 ((alist
->fileattr
& ~ATTR_FILE_SETMASK
) != 0)) {
341 if ((error
= hfs_lock(VTOC(vp
), HFS_EXCLUSIVE_LOCK
)))
346 * When setting volume attributes make sure
347 * that ATTR_VOL_INFO is set and that all
348 * the attributes are valid.
350 if ((alist
->volattr
!= 0) &&
351 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
352 (alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
353 (cp
->c_fileid
!= kHFSRootFolderID
))) {
354 if ((alist
->volattr
& ATTR_VOL_INFO
) == 0)
355 printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
357 printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
358 alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
);
362 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
)) {
366 // XXXdbg - don't allow modifying the journal or journal_info_block
367 if (hfsmp
->jnl
&& cp
->c_datafork
) {
368 struct HFSPlusExtentDescriptor
*extd
;
370 extd
= &cp
->c_datafork
->ff_extents
[0];
371 if (extd
->startBlock
== HFSTOVCB(hfsmp
)->vcbJinfoBlock
|| extd
->startBlock
== hfsmp
->jnl_start
) {
378 * Ownership of a file is required in one of two classes of calls:
380 * (a) When setting any ownership-requiring attribute other
381 * than ATTR_CMN_FLAGS, or
382 * (b) When setting ATTR_CMN_FLAGS on a volume that's not
383 * plain HFS (for which no real per-object ownership
384 * information is stored)
386 if ((alist
->commonattr
& (ATTR_OWNERSHIP_SETMASK
& ~ATTR_CMN_FLAGS
)) ||
387 ((alist
->commonattr
& ATTR_CMN_FLAGS
) &&
388 (VTOVCB(vp
)->vcbSigWord
!= kHFSSigWord
))) {
390 * NOTE: The following isn't ENTIRELY complete: even if
391 * you're the superuser you cannot change the flags as
392 * long as SF_IMMUTABLE or SF_APPEND is set and the
393 * securelevel > 0. This is verified in hfs_chflags
394 * which gets invoked to do the actual flags field
395 * change so this check is sufficient for now.
397 if ((error
= hfs_owner_rights(hfsmp
, cp
->c_uid
, cred
, p
, true)) != 0)
401 * For any other attributes, check to see if the user has
402 * write access to the cnode in question [unlike vn_access,
403 * ignore IMMUTABLE here]:
405 if (((alist
->commonattr
& ~ATTR_OWNERSHIP_SETMASK
) != 0) ||
406 (alist
->volattr
!= 0) || (alist
->dirattr
!= 0) ||
407 (alist
->fileattr
!= 0)) {
408 if ((error
= hfs_write_access(vp
, cred
, p
, false)) != 0)
413 * Allocate the buffer now to minimize the time we might
414 * be blocked holding the catalog lock.
416 // LP64todo - fix this
417 attrblocksize
= uio_resid(ap
->a_uio
);
418 if (attrblocksize
< hfs_attrblksize(alist
)) {
423 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
425 error
= uiomove((caddr_t
)attrbufptr
, attrblocksize
, ap
->a_uio
);
429 /* Save original state so changes can be detected. */
430 saved_uid
= cp
->c_uid
;
431 saved_gid
= cp
->c_gid
;
432 saved_mode
= cp
->c_mode
;
433 saved_flags
= cp
->c_flags
;
435 attrptr
= attrbufptr
;
436 attrblk
.ab_attrlist
= alist
;
437 attrblk
.ab_attrbufpp
= &attrptr
;
438 attrblk
.ab_varbufpp
= &varptr
;
439 attrblk
.ab_flags
= 0;
440 attrblk
.ab_blocksize
= attrblocksize
;
441 error
= unpackattrblk(&attrblk
, vp
);
445 /* If unpacking changed the owner/group then call hfs_chown() */
446 if ((saved_uid
!= cp
->c_uid
) || (saved_gid
!= cp
->c_gid
)) {
451 cp
->c_uid
= saved_uid
;
453 cp
->c_gid
= saved_gid
;
454 if ((error
= hfs_chown(vp
, uid
, gid
, cred
, p
)))
457 /* If unpacking changed the mode then call hfs_chmod() */
458 if (saved_mode
!= cp
->c_mode
) {
462 cp
->c_mode
= saved_mode
;
463 if ((error
= hfs_chmod(vp
, mode
, cred
, p
)))
466 /* If unpacking changed the flags then call hfs_chflags() */
467 if (saved_flags
!=cp
->c_flags
) {
471 cp
->c_flags
= saved_flags
;
472 if ((error
= hfs_chflags(vp
, flags
, cred
, p
)))
476 * If any cnode attributes changed then do an update.
478 if (alist
->volattr
== 0) {
479 cp
->c_flag
|= C_MODIFIED
;
480 if ((error
= hfs_update(vp
, TRUE
))) {
485 if (alist
->volattr
& ATTR_VOL_NAME
) {
486 ExtendedVCB
*vcb
= VTOVCB(vp
);
488 if (vcb
->vcbVN
[0] == 0) {
490 * Ignore attempts to rename a volume to a zero-length name:
491 * restore the original name from the cnode.
493 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
495 struct cat_desc to_desc
;
496 struct cat_desc todir_desc
;
497 struct cat_desc new_desc
;
504 bzero(&to_desc
, sizeof(to_desc
));
505 bzero(&todir_desc
, sizeof(todir_desc
));
506 bzero(&new_desc
, sizeof(new_desc
));
507 bzero(&cookie
, sizeof(cookie
));
509 todir_desc
.cd_parentcnid
= kHFSRootParentID
;
510 todir_desc
.cd_cnid
= kHFSRootFolderID
;
511 todir_desc
.cd_flags
= CD_ISDIR
;
513 to_desc
.cd_nameptr
= vcb
->vcbVN
;
514 to_desc
.cd_namelen
= strlen(vcb
->vcbVN
);
515 to_desc
.cd_parentcnid
= kHFSRootParentID
;
516 to_desc
.cd_cnid
= cp
->c_cnid
;
517 to_desc
.cd_flags
= CD_ISDIR
;
519 if ((error
= hfs_start_transaction(hfsmp
) != 0)) {
525 * Reserve some space in the Catalog file.
527 error
= cat_preflight(hfsmp
, CAT_RENAME
, &cookie
, p
);
533 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_EXCLUSIVE_LOCK
);
536 error
= cat_rename(hfsmp
, &cp
->c_desc
, &todir_desc
, &to_desc
, &new_desc
);
539 hfs_systemfile_unlock(hfsmp
, lockflags
);
542 cat_postflight(hfsmp
, &cookie
, p
);
544 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
546 hfs_end_transaction(hfsmp
);
550 /* Restore the old name in the VCB */
551 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
552 vcb
->vcbFlags
|= 0xFF00;
555 /* Release old allocated name buffer */
556 if (cp
->c_desc
.cd_flags
& CD_HASBUF
) {
557 char *name
= cp
->c_desc
.cd_nameptr
;
559 cp
->c_desc
.cd_nameptr
= 0;
560 cp
->c_desc
.cd_namelen
= 0;
561 cp
->c_desc
.cd_flags
&= ~CD_HASBUF
;
562 vfs_removename(name
);
564 /* Update cnode's catalog descriptor */
565 replace_desc(cp
, &new_desc
);
566 vcb
->volumeNameEncodingHint
= new_desc
.cd_encoding
;
567 cp
->c_touch_chgtime
= TRUE
;
572 * When the volume name changes or the volume's finder info
573 * changes then force them to disk immediately.
575 if ((alist
->volattr
& ATTR_VOL_INFO
) &&
576 ((alist
->volattr
& ATTR_VOL_NAME
) ||
577 (alist
->commonattr
& ATTR_CMN_FNDRINFO
))) {
578 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
582 FREE(attrbufptr
, M_TEMP
);
590 * readdirattr operation will return attributes for the items in the
591 * directory specified.
593 * It does not do . and .. entries. The problem is if you are at the root of the
594 * hfs directory and go to .. you could be crossing a mountpoint into a
595 * different (ufs) file system. The attributes that apply for it may not
596 * apply for the file system you are doing the readdirattr on. To make life
597 * simpler, this call will only return entries in its directory, hfs like.
599 * 1. more than one for uiovcnt support.
600 * 2. put knohint (hints) in state for next call in
601 * 3. credentials checking when rest of hfs does it.
602 * 4. Do return permissions concatenation ???
607 #% readdirattr vp L L L
611 IN struct attrlist *alist;
612 INOUT struct uio *uio;
615 OUT u_long *newstate;
617 OUT u_long *actualCount;
618 OUT u_long **cookies;
619 IN kauth_cred_t cred;
624 hfs_vnop_readdirattr(ap
)
625 struct vnop_readdirattr_args
/* {
627 struct attrlist *a_alist;
633 u_long *a_actualcount;
634 vfs_context_t a_context;
637 struct vnode
*dvp
= ap
->a_vp
;
639 struct hfsmount
* hfsmp
;
640 struct attrlist
*alist
= ap
->a_alist
;
641 uio_t uio
= ap
->a_uio
;
642 int maxcount
= ap
->a_maxcount
;
643 struct proc
*p
= vfs_context_proc(ap
->a_context
);
644 uint32_t fixedblocksize
;
645 uint32_t maxattrblocksize
;
646 uint32_t currattrbufsize
;
647 void *attrbufptr
= NULL
;
650 struct attrblock attrblk
;
655 struct cat_desc
*lastdescp
= NULL
;
656 struct cat_entrylist
*ce_list
= NULL
;
657 directoryhint_t
*dirhint
= NULL
;
659 int shared_cnode_lock
= 0;
661 *(ap
->a_actualcount
) = 0;
662 *(ap
->a_eofflag
) = 0;
664 /* Check for invalid options and buffer space. */
665 if (((ap
->a_options
& ~(FSOPT_NOINMEMUPDATE
| FSOPT_NOFOLLOW
)) != 0)
666 || (uio_resid(uio
) <= 0) || (uio_iovcnt(uio
) > 1) || (maxcount
<= 0))
669 /* This call doesn't take volume attributes. */
670 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
671 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
672 (alist
->volattr
!= 0) ||
673 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
674 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0))
677 if ((error
= hfs_lock(VTOC(dvp
), HFS_EXCLUSIVE_LOCK
)))
682 /* Reject requests for unsupported options. */
683 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
|
684 ATTR_CMN_OBJPERMANENTID
)) ||
685 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
|
686 ATTR_FILE_FORKLIST
| ATTR_FILE_DATAEXTENTS
| ATTR_FILE_RSRCEXTENTS
))) {
687 printf("readdirattr: unsupported attributes! (%s)\n", dcp
->c_desc
.cd_nameptr
);
692 dir_entries
= dcp
->c_entries
;
693 if (dcp
->c_attr
.ca_fileid
== kHFSRootFolderID
&& (hfsmp
->jnl
|| ((HFSTOVCB(hfsmp
)->vcbAtrb
& kHFSVolumeJournaledMask
) && (hfsmp
->hfs_flags
& HFS_READ_ONLY
)))) {
697 /* Convert uio_offset into a directory index. */
698 index
= uio_offset(uio
) & HFS_INDEX_MASK
;
699 tag
= uio_offset(uio
) & ~HFS_INDEX_MASK
;
700 if ((index
+ 1) > dir_entries
) {
701 *(ap
->a_eofflag
) = 1;
706 /* Get a buffer to hold packed attributes. */
707 fixedblocksize
= (sizeof(uint32_t) + hfs_attrblksize(alist
)); /* 4 bytes for length */
708 maxattrblocksize
= fixedblocksize
;
709 if (alist
->commonattr
& ATTR_CMN_NAME
)
710 maxattrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
711 MALLOC(attrbufptr
, void *, maxattrblocksize
, M_TEMP
, M_WAITOK
);
712 attrptr
= attrbufptr
;
713 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
715 /* Initialize a catalog entry list. */
716 MALLOC(ce_list
, struct cat_entrylist
*, sizeof(*ce_list
), M_TEMP
, M_WAITOK
);
717 bzero(ce_list
, sizeof(*ce_list
));
718 ce_list
->maxentries
= MAXCATENTRIES
;
720 /* Get a directory hint (cnode must be locked exclusive) */
721 dirhint
= hfs_getdirhint(dcp
, ((index
- 1) & HFS_INDEX_MASK
) | tag
);
723 /* Hide tag from catalog layer. */
724 dirhint
->dh_index
&= HFS_INDEX_MASK
;
725 if (dirhint
->dh_index
== HFS_INDEX_MASK
) {
726 dirhint
->dh_index
= -1;
730 * An ATTR_CMN_USERACCESS attribute request can result in a
731 * call to kauth_cred_ismember_gid(). So when requesting
732 * this attribute we downgrade our exclusive lock on dcp to
733 * a shared lock in case kauth_cred_ismember_gid generates
734 * an indirect call back into the file system.
736 if (alist
->commonattr
& ATTR_CMN_USERACCESS
) {
737 lck_rw_lock_exclusive_to_shared(&dcp
->c_rwlock
);
738 dcp
->c_lockowner
= HFS_SHARED_OWNER
;
739 shared_cnode_lock
= 1;
742 * Obtain a list of catalog entries and pack their attributes until
743 * the output buffer is full or maxcount entries have been packed.
749 /* Constrain our list size. */
750 maxentries
= uio_resid(uio
) / (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
);
751 maxentries
= min(maxentries
, dcp
->c_entries
- index
);
752 maxentries
= min(maxentries
, maxcount
);
753 ce_list
->maxentries
= min(maxentries
, ce_list
->maxentries
);
756 lockflags
= hfs_systemfile_lock(hfsmp
, SFL_CATALOG
, HFS_SHARED_LOCK
);
758 error
= cat_getentriesattr(hfsmp
, dirhint
, ce_list
);
759 /* Don't forget to release the descriptors later! */
761 hfs_systemfile_unlock(hfsmp
, lockflags
);
763 if (error
== ENOENT
) {
764 *(ap
->a_eofflag
) = TRUE
;
771 /* Process the catalog entries. */
772 for (i
= 0; i
< (int)ce_list
->realentries
; ++i
) {
773 struct cnode
*cp
= NULL
;
774 struct vnode
*vp
= NULL
;
775 struct cat_desc
* cdescp
;
776 struct cat_attr
* cattrp
;
777 struct cat_fork c_datafork
;
778 struct cat_fork c_rsrcfork
;
780 bzero(&c_datafork
, sizeof(c_datafork
));
781 bzero(&c_rsrcfork
, sizeof(c_rsrcfork
));
782 cdescp
= &ce_list
->entry
[i
].ce_desc
;
783 cattrp
= &ce_list
->entry
[i
].ce_attr
;
784 c_datafork
.cf_size
= ce_list
->entry
[i
].ce_datasize
;
785 c_datafork
.cf_blocks
= ce_list
->entry
[i
].ce_datablks
;
786 c_rsrcfork
.cf_size
= ce_list
->entry
[i
].ce_rsrcsize
;
787 c_rsrcfork
.cf_blocks
= ce_list
->entry
[i
].ce_rsrcblks
;
789 * Get in memory cnode data (if any).
791 if (!(ap
->a_options
& FSOPT_NOINMEMUPDATE
)) {
792 vp
= hfs_chash_getvnode(dcp
->c_dev
, cattrp
->ca_fileid
, 0, 0);
796 /* Only use cnode's decriptor for non-hardlinks */
797 if (!(cp
->c_flag
& C_HARDLINK
))
798 cdescp
= &cp
->c_desc
;
799 cattrp
= &cp
->c_attr
;
800 if (cp
->c_datafork
) {
801 c_datafork
.cf_size
= cp
->c_datafork
->ff_size
;
802 c_datafork
.cf_blocks
= cp
->c_datafork
->ff_blocks
;
804 if (cp
->c_rsrcfork
) {
805 c_rsrcfork
.cf_size
= cp
->c_rsrcfork
->ff_size
;
806 c_rsrcfork
.cf_blocks
= cp
->c_rsrcfork
->ff_blocks
;
810 *((uint32_t *)attrptr
)++ = 0; /* move it past length */
811 attrblk
.ab_attrlist
= alist
;
812 attrblk
.ab_attrbufpp
= &attrptr
;
813 attrblk
.ab_varbufpp
= &varptr
;
814 attrblk
.ab_flags
= 0;
815 attrblk
.ab_blocksize
= maxattrblocksize
;
817 /* Pack catalog entries into attribute buffer. */
818 hfs_packattrblk(&attrblk
, hfsmp
, vp
, cdescp
, cattrp
,
819 &c_datafork
, &c_rsrcfork
, p
);
820 currattrbufsize
= ((char *)varptr
- (char *)attrbufptr
);
822 /* All done with cnode. */
824 hfs_unlock(VTOC(vp
));
830 /* Make sure there's enough buffer space remaining. */
831 // LP64todo - fix this!
832 if (uio_resid(uio
) < 0 || currattrbufsize
> (uint32_t)uio_resid(uio
)) {
836 *((uint32_t *)attrbufptr
) = currattrbufsize
;
837 error
= uiomove((caddr_t
)attrbufptr
, currattrbufsize
, ap
->a_uio
);
838 if (error
!= E_NONE
) {
842 attrptr
= attrbufptr
;
843 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
844 /* Save the last valid catalog entry */
845 lastdescp
= &ce_list
->entry
[i
].ce_desc
;
847 *ap
->a_actualcount
+= 1;
849 /* Termination checks */
850 if ((--maxcount
<= 0) ||
851 // LP64todo - fix this!
852 uio_resid(uio
) < 0 ||
853 ((uint32_t)uio_resid(uio
) < (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
)) ||
854 (index
>= dir_entries
)) {
859 } /* for each catalog entry */
861 /* If there are more entries then save the last name. */
862 if (index
< dir_entries
863 && !(*(ap
->a_eofflag
))
864 && lastdescp
!= NULL
) {
866 /* Remember last entry */
867 if (dirhint
->dh_desc
.cd_nameptr
!= NULL
) {
868 vfs_removename(dirhint
->dh_desc
.cd_nameptr
);
870 dirhint
->dh_desc
.cd_namelen
= lastdescp
->cd_namelen
;
871 dirhint
->dh_desc
.cd_nameptr
=
872 vfs_addname(lastdescp
->cd_nameptr
, lastdescp
->cd_namelen
, 0, 0);
873 dirhint
->dh_index
= index
- 1;
874 dirhint
->dh_desc
.cd_cnid
= lastdescp
->cd_cnid
;
875 dirhint
->dh_desc
.cd_hint
= lastdescp
->cd_hint
;
876 dirhint
->dh_desc
.cd_encoding
= lastdescp
->cd_encoding
;
879 /* All done with the catalog descriptors. */
880 for (i
= 0; i
< (int)ce_list
->realentries
; ++i
)
881 cat_releasedesc(&ce_list
->entry
[i
].ce_desc
);
882 ce_list
->realentries
= 0;
884 } /* while not depleted */
886 *ap
->a_newstate
= dcp
->c_mtime
;
888 /* Make sure dcp is locked exclusive before changing c_dirhinttag. */
889 if (shared_cnode_lock
) {
891 * If the upgrade fails we loose the lock and
892 * have to take the exclusive lock on our own.
894 if (lck_rw_lock_shared_to_exclusive(&dcp
->c_rwlock
) != 0)
895 lck_rw_lock_exclusive(&dcp
->c_rwlock
);
896 dcp
->c_lockowner
= current_thread();
897 shared_cnode_lock
= 0;
900 /* Convert directory index back into a uio_offset. */
901 while (tag
== 0) tag
= (++dcp
->c_dirhinttag
) << HFS_INDEX_BITS
;
902 uio_setoffset(uio
, index
| tag
);
903 dirhint
->dh_index
|= tag
;
906 /* Drop directory hint on error or if there are no more entries */
907 if (dirhint
&& (error
|| index
>= dir_entries
)) {
908 if (shared_cnode_lock
) {
910 * If the upgrade fails we loose the lock and
911 * have to take the exclusive lock on our own.
913 if (lck_rw_lock_shared_to_exclusive(&dcp
->c_rwlock
) != 0)
914 lck_rw_lock_exclusive(&dcp
->c_rwlock
);
915 dcp
->c_lockowner
= current_thread();
917 hfs_reldirhint(dcp
, dirhint
);
920 FREE(attrbufptr
, M_TEMP
);
922 FREE(ce_list
, M_TEMP
);
929 /*==================== Attribute list support routines ====================*/
932 * Pack cnode attributes into an attribute block.
936 hfs_packattrblk(struct attrblock
*abp
,
937 struct hfsmount
*hfsmp
,
939 struct cat_desc
*descp
,
940 struct cat_attr
*attrp
,
941 struct cat_fork
*datafork
,
942 struct cat_fork
*rsrcfork
,
945 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
947 if (attrlistp
->volattr
) {
948 if (attrlistp
->commonattr
)
949 packvolcommonattr(abp
, hfsmp
, vp
, p
);
951 if (attrlistp
->volattr
& ~ATTR_VOL_INFO
)
952 packvolattr(abp
, hfsmp
, vp
);
954 if (attrlistp
->commonattr
)
955 packcommonattr(abp
, hfsmp
, vp
, descp
, attrp
, p
);
957 if (attrlistp
->dirattr
&& S_ISDIR(attrp
->ca_mode
))
958 packdirattr(abp
, hfsmp
, vp
, descp
,attrp
);
960 if (attrlistp
->fileattr
&& !S_ISDIR(attrp
->ca_mode
))
961 packfileattr(abp
, hfsmp
, attrp
, datafork
, rsrcfork
);
967 mountpointname(struct mount
*mp
)
969 size_t namelength
= strlen(mp
->mnt_vfsstat
.f_mntonname
);
977 * Look backwards through the name string, looking for
978 * the first slash encountered (which must precede the
979 * last part of the pathname).
981 for (c
= mp
->mnt_vfsstat
.f_mntonname
+ namelength
- 1;
982 namelength
> 0; --c
, --namelength
) {
985 } else if (foundchars
) {
990 return (mp
->mnt_vfsstat
.f_mntonname
);
996 struct attrblock
*abp
,
1002 struct attrreference
* attr_refptr
;
1005 uint32_t attrlength
;
1008 /* A cnode's name may be incorrect for the root of a mounted
1009 * filesystem (it can be mounted on a different directory name
1010 * than the name of the volume, such as "blah-1"). So for the
1011 * root directory, it's best to return the last element of the
1012 location where the volume's mounted:
1014 if ((vp
!= NULL
) && vnode_isvroot(vp
) &&
1015 (mpname
= mountpointname(vnode_mount(vp
)))) {
1016 mpnamelen
= strlen(mpname
);
1018 /* Trim off any trailing slashes: */
1019 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/'))
1022 /* If there's anything left, use it instead of the volume's name */
1023 if (mpnamelen
> 0) {
1025 namelen
= mpnamelen
;
1033 varbufptr
= *abp
->ab_varbufpp
;
1034 attr_refptr
= (struct attrreference
*)(*abp
->ab_attrbufpp
);
1036 attrlength
= namelen
+ 1;
1037 attr_refptr
->attr_dataoffset
= (char *)varbufptr
- (char *)attr_refptr
;
1038 attr_refptr
->attr_length
= attrlength
;
1039 (void) strncpy((unsigned char *)varbufptr
, name
, attrlength
);
1041 * Advance beyond the space just allocated and
1042 * round up to the next 4-byte boundary:
1044 (char *)(varbufptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1047 *abp
->ab_attrbufpp
= attr_refptr
;
1048 *abp
->ab_varbufpp
= varbufptr
;
1052 * Pack common volume attributes.
1055 packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
, struct proc
*p
)
1058 void *attrbufptr
= *abp
->ab_attrbufpp
;
1059 void *varbufptr
= *abp
->ab_varbufpp
;
1060 struct cnode
*cp
= VTOC(vp
);
1061 struct mount
*mp
= VTOVFS(vp
);
1062 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1063 u_int32_t attrlength
;
1064 boolean_t is_64_bit
= proc_is64bit(p
);
1066 attr
= abp
->ab_attrlist
->commonattr
;
1068 if (ATTR_CMN_NAME
& attr
) {
1069 packnameattr(abp
, vp
, cp
->c_desc
.cd_nameptr
, cp
->c_desc
.cd_namelen
);
1070 attrbufptr
= *abp
->ab_attrbufpp
;
1071 varbufptr
= *abp
->ab_varbufpp
;
1073 if (ATTR_CMN_DEVID
& attr
) {
1074 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1076 if (ATTR_CMN_FSID
& attr
) {
1079 fsid
.val
[0] = (long)hfsmp
->hfs_raw_dev
;
1080 fsid
.val
[1] = (long)vfs_typenum(mp
);
1081 *((fsid_t
*)attrbufptr
) = fsid
;
1082 ++((fsid_t
*)attrbufptr
);
1084 if (ATTR_CMN_OBJTYPE
& attr
) {
1085 *((fsobj_type_t
*)attrbufptr
)++ = 0;
1087 if (ATTR_CMN_OBJTAG
& attr
) {
1088 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1090 if (ATTR_CMN_OBJID
& attr
) {
1091 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1092 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1093 ++((fsobj_id_t
*)attrbufptr
);
1095 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1096 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1097 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1098 ++((fsobj_id_t
*)attrbufptr
);
1100 if (ATTR_CMN_PAROBJID
& attr
) {
1101 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1102 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1103 ++((fsobj_id_t
*)attrbufptr
);
1105 if (ATTR_CMN_SCRIPT
& attr
) {
1108 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1109 encoding
= vcb
->volumeNameEncodingHint
;
1111 encoding
= hfsmp
->hfs_encoding
;
1112 *((text_encoding_t
*)attrbufptr
)++ = encoding
;
1114 if (ATTR_CMN_CRTIME
& attr
) {
1116 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbCrDate
;
1117 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1118 ++((struct user_timespec
*)attrbufptr
);
1121 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbCrDate
;
1122 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1123 ++((struct timespec
*)attrbufptr
);
1126 if (ATTR_CMN_MODTIME
& attr
) {
1128 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1129 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1130 ++((struct user_timespec
*)attrbufptr
);
1133 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1134 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1135 ++((struct timespec
*)attrbufptr
);
1138 if (ATTR_CMN_CHGTIME
& attr
) {
1140 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1141 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1142 ++((struct user_timespec
*)attrbufptr
);
1145 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1146 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1147 ++((struct timespec
*)attrbufptr
);
1150 if (ATTR_CMN_ACCTIME
& attr
) {
1152 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1153 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1154 ++((struct user_timespec
*)attrbufptr
);
1157 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1158 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1159 ++((struct timespec
*)attrbufptr
);
1162 if (ATTR_CMN_BKUPTIME
& attr
) {
1164 ((struct user_timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbVolBkUp
;
1165 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1166 ++((struct user_timespec
*)attrbufptr
);
1169 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbVolBkUp
;
1170 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1171 ++((struct timespec
*)attrbufptr
);
1174 if (ATTR_CMN_FNDRINFO
& attr
) {
1175 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1176 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1178 if (ATTR_CMN_OWNERID
& attr
) {
1179 if (cp
->c_uid
== UNKNOWNUID
)
1180 *((uid_t
*)attrbufptr
)++ = kauth_cred_getuid(proc_ucred(p
));
1182 *((uid_t
*)attrbufptr
)++ = cp
->c_uid
;
1184 if (ATTR_CMN_GRPID
& attr
) {
1185 *((gid_t
*)attrbufptr
)++ = cp
->c_gid
;
1188 if (ATTR_CMN_ACCESSMASK
& attr
) {
1190 * [2856576] Since we are dynamically changing the owner, also
1191 * effectively turn off the set-user-id and set-group-id bits,
1192 * just like chmod(2) would when changing ownership. This prevents
1193 * a security hole where set-user-id programs run as whoever is
1194 * logged on (or root if nobody is logged in yet!)
1196 *((uint32_t *)attrbufptr
)++ =
1197 (cp
->c_uid
== UNKNOWNUID
) ? cp
->c_mode
& ~(S_ISUID
| S_ISGID
) : cp
->c_mode
;
1199 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1200 *((uint32_t *)attrbufptr
)++ = 0; /* XXX PPD TBC */
1202 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1204 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1205 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1207 * Advance beyond the space just allocated and
1208 * round up to the next 4-byte boundary:
1210 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1211 ++((struct attrreference
*)attrbufptr
);
1213 if (ATTR_CMN_FLAGS
& attr
) {
1214 *((uint32_t *)attrbufptr
)++ = cp
->c_flags
;
1216 if (ATTR_CMN_USERACCESS
& attr
) {
1217 *((uint32_t *)attrbufptr
)++ =
1218 DerivePermissionSummary(cp
->c_uid
, cp
->c_gid
, cp
->c_mode
,
1219 VTOVFS(vp
), kauth_cred_get(), proc_self());
1222 *abp
->ab_attrbufpp
= attrbufptr
;
1223 *abp
->ab_varbufpp
= varbufptr
;
1228 packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
)
1231 void *attrbufptr
= *abp
->ab_attrbufpp
;
1232 void *varbufptr
= *abp
->ab_varbufpp
;
1233 struct cnode
*cp
= VTOC(vp
);
1234 struct mount
*mp
= VTOVFS(vp
);
1235 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1236 uint32_t attrlength
;
1238 attr
= abp
->ab_attrlist
->volattr
;
1240 if (ATTR_VOL_FSTYPE
& attr
) {
1241 *((uint32_t *)attrbufptr
)++ = (uint32_t)vfs_typenum(mp
);
1243 if (ATTR_VOL_SIGNATURE
& attr
) {
1244 *((uint32_t *)attrbufptr
)++ = (uint32_t)vcb
->vcbSigWord
;
1246 if (ATTR_VOL_SIZE
& attr
) {
1247 *((off_t
*)attrbufptr
)++ =
1248 (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1250 if (ATTR_VOL_SPACEFREE
& attr
) {
1251 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 0) *
1252 (off_t
)vcb
->blockSize
;
1254 if (ATTR_VOL_SPACEAVAIL
& attr
) {
1255 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 1) *
1256 (off_t
)vcb
->blockSize
;
1258 if (ATTR_VOL_MINALLOCATION
& attr
) {
1259 *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1261 if (ATTR_VOL_ALLOCATIONCLUMP
& attr
) {
1262 *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1264 if (ATTR_VOL_IOBLOCKSIZE
& attr
) {
1265 *((uint32_t *)attrbufptr
)++ = hfsmp
->hfs_logBlockSize
;
1267 if (ATTR_VOL_OBJCOUNT
& attr
) {
1268 *((uint32_t *)attrbufptr
)++ =
1269 (uint32_t)vcb
->vcbFilCnt
+ (uint32_t)vcb
->vcbDirCnt
;
1271 if (ATTR_VOL_FILECOUNT
& attr
) {
1272 *((uint32_t *)attrbufptr
)++ = (uint32_t)vcb
->vcbFilCnt
;
1274 if (ATTR_VOL_DIRCOUNT
& attr
) {
1275 *((uint32_t *)attrbufptr
)++ = (uint32_t)vcb
->vcbDirCnt
;
1277 if (ATTR_VOL_MAXOBJCOUNT
& attr
) {
1278 *((uint32_t *)attrbufptr
)++ = 0xFFFFFFFF;
1280 if (ATTR_VOL_MOUNTPOINT
& attr
) {
1281 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1282 (char *)varbufptr
- (char *)attrbufptr
;
1283 ((struct attrreference
*)attrbufptr
)->attr_length
=
1284 strlen(mp
->mnt_vfsstat
.f_mntonname
) + 1;
1285 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1286 /* round up to the next 4-byte boundary: */
1287 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1288 (void) bcopy(mp
->mnt_vfsstat
.f_mntonname
, varbufptr
, attrlength
);
1290 /* Advance beyond the space just allocated: */
1291 (char *)varbufptr
+= attrlength
;
1292 ++((struct attrreference
*)attrbufptr
);
1294 if (ATTR_VOL_NAME
& attr
) {
1295 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1296 (char *)varbufptr
- (char *)attrbufptr
;
1297 ((struct attrreference
*)attrbufptr
)->attr_length
=
1298 cp
->c_desc
.cd_namelen
+ 1;
1299 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1300 /* round up to the next 4-byte boundary: */
1301 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1302 /* XXX this could read off the end of cd_nameptr! */
1303 bcopy(cp
->c_desc
.cd_nameptr
, varbufptr
, attrlength
);
1305 /* Advance beyond the space just allocated: */
1306 (char *)varbufptr
+= attrlength
;
1307 ++((struct attrreference
*)attrbufptr
);
1309 if (ATTR_VOL_MOUNTFLAGS
& attr
) {
1310 *((uint32_t *)attrbufptr
)++ = (uint32_t)vfs_flags(mp
);
1312 if (ATTR_VOL_MOUNTEDDEVICE
& attr
) {
1313 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1314 (char *)varbufptr
- (char *)attrbufptr
;
1315 ((struct attrreference
*)attrbufptr
)->attr_length
=
1316 strlen(mp
->mnt_vfsstat
.f_mntfromname
) + 1;
1317 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1318 /* round up to the next 4-byte boundary: */
1319 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1320 (void) bcopy(mp
->mnt_vfsstat
.f_mntfromname
, varbufptr
, attrlength
);
1322 /* Advance beyond the space just allocated: */
1323 (char *)varbufptr
+= attrlength
;
1324 ++((struct attrreference
*)attrbufptr
);
1326 if (ATTR_VOL_ENCODINGSUSED
& attr
) {
1327 *((unsigned long long *)attrbufptr
)++ =
1328 (unsigned long long)vcb
->encodingsBitmap
;
1330 if (ATTR_VOL_CAPABILITIES
& attr
) {
1331 vol_capabilities_attr_t
*vcapattrptr
;
1333 vcapattrptr
= (vol_capabilities_attr_t
*)attrbufptr
;
1335 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1336 u_int32_t journal_active_cap
;
1337 u_int32_t case_sensitive
;
1340 journal_active_cap
= VOL_CAP_FMT_JOURNAL_ACTIVE
;
1342 journal_active_cap
= 0;
1344 if (hfsmp
->hfs_flags
& HFS_CASE_SENSITIVE
)
1345 case_sensitive
= VOL_CAP_FMT_CASE_SENSITIVE
;
1349 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1350 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1351 VOL_CAP_FMT_SYMBOLICLINKS
|
1352 VOL_CAP_FMT_HARDLINKS
|
1353 VOL_CAP_FMT_JOURNAL
|
1354 journal_active_cap
|
1356 VOL_CAP_FMT_CASE_PRESERVING
|
1357 VOL_CAP_FMT_FAST_STATFS
|
1358 VOL_CAP_FMT_2TB_FILESIZE
;
1359 } else { /* Plain HFS */
1360 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1361 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1362 VOL_CAP_FMT_CASE_PRESERVING
|
1363 VOL_CAP_FMT_FAST_STATFS
;
1365 vcapattrptr
->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1366 VOL_CAP_INT_SEARCHFS
|
1367 VOL_CAP_INT_ATTRLIST
|
1368 VOL_CAP_INT_NFSEXPORT
|
1369 VOL_CAP_INT_READDIRATTR
|
1370 VOL_CAP_INT_EXCHANGEDATA
|
1371 VOL_CAP_INT_ALLOCATE
|
1372 VOL_CAP_INT_VOL_RENAME
|
1373 VOL_CAP_INT_ADVLOCK
|
1375 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1376 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1378 vcapattrptr
->valid
[VOL_CAPABILITIES_FORMAT
] =
1379 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1380 VOL_CAP_FMT_SYMBOLICLINKS
|
1381 VOL_CAP_FMT_HARDLINKS
|
1382 VOL_CAP_FMT_JOURNAL
|
1383 VOL_CAP_FMT_JOURNAL_ACTIVE
|
1384 VOL_CAP_FMT_NO_ROOT_TIMES
|
1385 VOL_CAP_FMT_SPARSE_FILES
|
1386 VOL_CAP_FMT_ZERO_RUNS
|
1387 VOL_CAP_FMT_CASE_SENSITIVE
|
1388 VOL_CAP_FMT_CASE_PRESERVING
|
1389 VOL_CAP_FMT_FAST_STATFS
|
1390 VOL_CAP_FMT_2TB_FILESIZE
;
1391 vcapattrptr
->valid
[VOL_CAPABILITIES_INTERFACES
] =
1392 VOL_CAP_INT_SEARCHFS
|
1393 VOL_CAP_INT_ATTRLIST
|
1394 VOL_CAP_INT_NFSEXPORT
|
1395 VOL_CAP_INT_READDIRATTR
|
1396 VOL_CAP_INT_EXCHANGEDATA
|
1397 VOL_CAP_INT_COPYFILE
|
1398 VOL_CAP_INT_ALLOCATE
|
1399 VOL_CAP_INT_VOL_RENAME
|
1400 VOL_CAP_INT_ADVLOCK
|
1402 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1403 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1405 ++((vol_capabilities_attr_t
*)attrbufptr
);
1407 if (ATTR_VOL_ATTRIBUTES
& attr
) {
1408 vol_attributes_attr_t
*volattrattrp
;
1410 volattrattrp
= (vol_attributes_attr_t
*)attrbufptr
;
1411 volattrattrp
->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1412 volattrattrp
->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
1413 volattrattrp
->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1414 volattrattrp
->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1415 volattrattrp
->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1417 volattrattrp
->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1418 volattrattrp
->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
1419 volattrattrp
->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1420 volattrattrp
->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1421 volattrattrp
->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1422 ++((vol_attributes_attr_t
*)attrbufptr
);
1425 *abp
->ab_attrbufpp
= attrbufptr
;
1426 *abp
->ab_varbufpp
= varbufptr
;
1432 struct attrblock
*abp
,
1433 struct hfsmount
*hfsmp
,
1435 struct cat_desc
* cdp
,
1436 struct cat_attr
* cap
,
1439 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1440 struct mount
*mp
= HFSTOVFS(hfsmp
);
1441 void *attrbufptr
= *abp
->ab_attrbufpp
;
1442 void *varbufptr
= *abp
->ab_varbufpp
;
1443 uint32_t attrlength
= 0;
1444 boolean_t is_64_bit
= proc_is64bit(p
);
1446 if (ATTR_CMN_NAME
& attr
) {
1447 packnameattr(abp
, vp
, cdp
->cd_nameptr
, cdp
->cd_namelen
);
1448 attrbufptr
= *abp
->ab_attrbufpp
;
1449 varbufptr
= *abp
->ab_varbufpp
;
1451 if (ATTR_CMN_DEVID
& attr
) {
1452 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1454 if (ATTR_CMN_FSID
& attr
) {
1457 fsid
.val
[0] = (long)hfsmp
->hfs_raw_dev
;
1458 fsid
.val
[1] = (long)vfs_typenum(mp
);
1459 *((fsid_t
*)attrbufptr
) = fsid
;
1460 ++((fsid_t
*)attrbufptr
);
1462 if (ATTR_CMN_OBJTYPE
& attr
) {
1463 *((fsobj_type_t
*)attrbufptr
)++ = IFTOVT(cap
->ca_mode
);
1465 if (ATTR_CMN_OBJTAG
& attr
) {
1466 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1469 * Exporting file IDs from HFS Plus:
1471 * For "normal" files the c_fileid is the same value as the
1472 * c_cnid. But for hard link files, they are different - the
1473 * c_cnid belongs to the active directory entry (ie the link)
1474 * and the c_fileid is for the actual inode (ie the data file).
1476 * The stat call (getattr) will always return the c_fileid
1477 * and Carbon APIs, which are hardlink-ignorant, will always
1478 * receive the c_cnid (from getattrlist).
1480 if (ATTR_CMN_OBJID
& attr
) {
1481 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1482 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1483 ++((fsobj_id_t
*)attrbufptr
);
1485 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1486 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1487 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1488 ++((fsobj_id_t
*)attrbufptr
);
1490 if (ATTR_CMN_PAROBJID
& attr
) {
1491 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_parentcnid
;
1492 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1493 ++((fsobj_id_t
*)attrbufptr
);
1495 if (ATTR_CMN_SCRIPT
& attr
) {
1496 *((text_encoding_t
*)attrbufptr
)++ = cdp
->cd_encoding
;
1498 if (ATTR_CMN_CRTIME
& attr
) {
1500 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_itime
;
1501 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1502 ++((struct user_timespec
*)attrbufptr
);
1505 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_itime
;
1506 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1507 ++((struct timespec
*)attrbufptr
);
1510 if (ATTR_CMN_MODTIME
& attr
) {
1512 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_mtime
;
1513 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1514 ++((struct user_timespec
*)attrbufptr
);
1517 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_mtime
;
1518 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1519 ++((struct timespec
*)attrbufptr
);
1522 if (ATTR_CMN_CHGTIME
& attr
) {
1524 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_ctime
;
1525 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1526 ++((struct user_timespec
*)attrbufptr
);
1529 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_ctime
;
1530 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1531 ++((struct timespec
*)attrbufptr
);
1534 if (ATTR_CMN_ACCTIME
& attr
) {
1536 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_atime
;
1537 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1538 ++((struct user_timespec
*)attrbufptr
);
1541 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_atime
;
1542 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1543 ++((struct timespec
*)attrbufptr
);
1546 if (ATTR_CMN_BKUPTIME
& attr
) {
1548 ((struct user_timespec
*)attrbufptr
)->tv_sec
= cap
->ca_btime
;
1549 ((struct user_timespec
*)attrbufptr
)->tv_nsec
= 0;
1550 ++((struct user_timespec
*)attrbufptr
);
1553 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_btime
;
1554 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1555 ++((struct timespec
*)attrbufptr
);
1558 if (ATTR_CMN_FNDRINFO
& attr
) {
1559 bcopy(&cap
->ca_finderinfo
, attrbufptr
, sizeof(u_int8_t
) * 32);
1560 (char *)attrbufptr
+= sizeof(u_int8_t
) * 32;
1562 if (ATTR_CMN_OWNERID
& attr
) {
1563 *((uid_t
*)attrbufptr
)++ =
1564 (cap
->ca_uid
== UNKNOWNUID
) ? kauth_cred_getuid(proc_ucred(p
)) : cap
->ca_uid
;
1566 if (ATTR_CMN_GRPID
& attr
) {
1567 *((gid_t
*)attrbufptr
)++ = cap
->ca_gid
;
1569 if (ATTR_CMN_ACCESSMASK
& attr
) {
1571 * [2856576] Since we are dynamically changing the owner, also
1572 * effectively turn off the set-user-id and set-group-id bits,
1573 * just like chmod(2) would when changing ownership. This prevents
1574 * a security hole where set-user-id programs run as whoever is
1575 * logged on (or root if nobody is logged in yet!)
1577 *((uint32_t *)attrbufptr
)++ =
1578 (cap
->ca_uid
== UNKNOWNUID
) ? cap
->ca_mode
& ~(S_ISUID
| S_ISGID
) : cap
->ca_mode
;
1580 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1581 *((uint32_t *)attrbufptr
)++ = 0;
1583 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1585 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1586 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1588 * Advance beyond the space just allocated and
1589 * round up to the next 4-byte boundary:
1591 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1592 ++((struct attrreference
*)attrbufptr
);
1594 if (ATTR_CMN_FLAGS
& attr
) {
1595 *((uint32_t *)attrbufptr
)++ = cap
->ca_flags
;
1597 if (ATTR_CMN_USERACCESS
& attr
) {
1598 *((uint32_t *)attrbufptr
)++ =
1599 DerivePermissionSummary(cap
->ca_uid
, cap
->ca_gid
,
1600 cap
->ca_mode
, mp
, proc_ucred(current_proc()),
1604 *abp
->ab_attrbufpp
= attrbufptr
;
1605 *abp
->ab_varbufpp
= varbufptr
;
1610 struct attrblock
*abp
,
1611 struct hfsmount
*hfsmp
,
1613 struct cat_desc
* descp
,
1614 struct cat_attr
* cattrp
)
1616 attrgroup_t attr
= abp
->ab_attrlist
->dirattr
;
1617 void *attrbufptr
= *abp
->ab_attrbufpp
;
1619 if (ATTR_DIR_LINKCOUNT
& attr
)
1620 *((uint32_t *)attrbufptr
)++ = cattrp
->ca_nlink
;
1621 if (ATTR_DIR_ENTRYCOUNT
& attr
) {
1622 uint32_t entries
= cattrp
->ca_entries
;
1624 if (descp
->cd_parentcnid
== kHFSRootParentID
) {
1625 if (hfsmp
->hfs_privdir_desc
.cd_cnid
!= 0)
1626 --entries
; /* hide private dir */
1627 if (hfsmp
->jnl
|| ((HFSTOVCB(hfsmp
)->vcbAtrb
& kHFSVolumeJournaledMask
) && (hfsmp
->hfs_flags
& HFS_READ_ONLY
)))
1628 entries
-= 2; /* hide the journal files */
1631 *((uint32_t *)attrbufptr
)++ = entries
;
1633 if (ATTR_DIR_MOUNTSTATUS
& attr
) {
1634 if (vp
!= NULL
&& vnode_mountedhere(vp
) != NULL
)
1635 *((uint32_t *)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
1637 *((uint32_t *)attrbufptr
)++ = 0;
1639 *abp
->ab_attrbufpp
= attrbufptr
;
1644 struct attrblock
*abp
,
1645 struct hfsmount
*hfsmp
,
1646 struct cat_attr
*cattrp
,
1647 struct cat_fork
*datafork
,
1648 struct cat_fork
*rsrcfork
)
1650 attrgroup_t attr
= abp
->ab_attrlist
->fileattr
;
1651 void *attrbufptr
= *abp
->ab_attrbufpp
;
1652 void *varbufptr
= *abp
->ab_varbufpp
;
1653 uint32_t attrlength
;
1654 uint32_t allocblksize
;
1656 allocblksize
= HFSTOVCB(hfsmp
)->blockSize
;
1658 if (ATTR_FILE_LINKCOUNT
& attr
) {
1659 *((uint32_t *)attrbufptr
)++ = cattrp
->ca_nlink
;
1661 if (ATTR_FILE_TOTALSIZE
& attr
) {
1662 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
+ rsrcfork
->cf_size
;
1664 if (ATTR_FILE_ALLOCSIZE
& attr
) {
1665 *((off_t
*)attrbufptr
)++ =
1666 (off_t
)cattrp
->ca_blocks
* (off_t
)allocblksize
;
1668 if (ATTR_FILE_IOBLOCKSIZE
& attr
) {
1669 *((uint32_t *)attrbufptr
)++ = hfsmp
->hfs_logBlockSize
;
1671 if (ATTR_FILE_CLUMPSIZE
& attr
) {
1672 *((uint32_t *)attrbufptr
)++ = HFSTOVCB(hfsmp
)->vcbClpSiz
;
1674 if (ATTR_FILE_DEVTYPE
& attr
) {
1675 if (S_ISBLK(cattrp
->ca_mode
) || S_ISCHR(cattrp
->ca_mode
))
1676 *((uint32_t *)attrbufptr
)++ = (uint32_t)cattrp
->ca_rdev
;
1678 *((uint32_t *)attrbufptr
)++ = 0;
1680 if (ATTR_FILE_FILETYPE
& attr
) {
1681 *((uint32_t *)attrbufptr
)++ = 0;
1683 if (ATTR_FILE_FORKCOUNT
& attr
) {
1684 *((uint32_t *)attrbufptr
)++ = 2;
1686 if (ATTR_FILE_FORKLIST
& attr
) {
1688 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1689 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1691 * Advance beyond the space just allocated and
1692 * round up to the next 4-byte boundary:
1694 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1695 ++((struct attrreference
*)attrbufptr
);
1697 if (ATTR_FILE_DATALENGTH
& attr
) {
1698 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
;
1700 if (ATTR_FILE_DATAALLOCSIZE
& attr
) {
1701 *((off_t
*)attrbufptr
)++ =
1702 (off_t
)datafork
->cf_blocks
* (off_t
)allocblksize
;
1704 if (ATTR_FILE_DATAEXTENTS
& attr
) {
1705 bcopy(&datafork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1706 (char *)attrbufptr
+= sizeof(extentrecord
);
1708 if (ATTR_FILE_RSRCLENGTH
& attr
) {
1709 *((off_t
*)attrbufptr
)++ = rsrcfork
->cf_size
;
1711 if (ATTR_FILE_RSRCALLOCSIZE
& attr
) {
1712 *((off_t
*)attrbufptr
)++ =
1713 (off_t
)rsrcfork
->cf_blocks
* (off_t
)allocblksize
;
1715 if (ATTR_FILE_RSRCEXTENTS
& attr
) {
1716 bcopy(&rsrcfork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1717 (char *)attrbufptr
+= sizeof(extentrecord
);
1719 *abp
->ab_attrbufpp
= attrbufptr
;
1720 *abp
->ab_varbufpp
= varbufptr
;
1725 unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
)
1727 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
1730 if (attrlistp
->volattr
) {
1731 error
= unpackvolattr(abp
, VTOHFS(vp
), vp
);
1734 } else if (attrlistp
->commonattr
) {
1735 unpackcommonattr(abp
, vp
);
1743 struct attrblock
*abp
,
1746 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1747 void *attrbufptr
= *abp
->ab_attrbufpp
;
1748 struct cnode
*cp
= VTOC(vp
);
1749 boolean_t is_64_bit
= proc_is64bit(current_proc());
1751 if (ATTR_CMN_SCRIPT
& attr
) {
1752 cp
->c_encoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
1753 hfs_setencodingbits(VTOHFS(vp
), cp
->c_encoding
);
1755 if (ATTR_CMN_CRTIME
& attr
) {
1757 cp
->c_itime
= ((struct user_timespec
*)attrbufptr
)->tv_sec
;
1758 ++((struct user_timespec
*)attrbufptr
);
1761 cp
->c_itime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1762 ++((struct timespec
*)attrbufptr
);
1765 if (ATTR_CMN_MODTIME
& attr
) {
1766 cp
->c_mtime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1767 ++((struct timespec
*)attrbufptr
);
1768 cp
->c_touch_modtime
= FALSE
;
1770 if (ATTR_CMN_CHGTIME
& attr
) {
1771 cp
->c_ctime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1772 ++((struct timespec
*)attrbufptr
);
1773 cp
->c_touch_chgtime
= FALSE
;
1775 if (ATTR_CMN_ACCTIME
& attr
) {
1776 cp
->c_atime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1777 ++((struct timespec
*)attrbufptr
);
1778 cp
->c_touch_acctime
= FALSE
;
1780 if (ATTR_CMN_BKUPTIME
& attr
) {
1781 cp
->c_btime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1782 ++((struct timespec
*)attrbufptr
);
1784 if (ATTR_CMN_FNDRINFO
& attr
) {
1785 bcopy(attrbufptr
, &cp
->c_attr
.ca_finderinfo
,
1786 sizeof(cp
->c_attr
.ca_finderinfo
));
1787 (char *)attrbufptr
+= sizeof(cp
->c_attr
.ca_finderinfo
);
1789 if (ATTR_CMN_OWNERID
& attr
) {
1790 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1791 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
1792 if (uid
!= (uid_t
)VNOVAL
)
1795 ((uid_t
*)attrbufptr
)++;
1798 if (ATTR_CMN_GRPID
& attr
) {
1799 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
1800 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1801 if (gid
!= (gid_t
)VNOVAL
)
1805 if (ATTR_CMN_ACCESSMASK
& attr
) {
1806 u_int16_t mode
= (u_int16_t
)*((uint32_t *)attrbufptr
)++;
1807 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1808 if (mode
!= (mode_t
)VNOVAL
) {
1809 cp
->c_mode
&= ~ALLPERMS
;
1810 cp
->c_mode
|= (mode
& ALLPERMS
);
1814 if (ATTR_CMN_FLAGS
& attr
) {
1815 uint32_t flags
= *((uint32_t *)attrbufptr
)++;
1817 * Flags are settable only on HFS+ volumes. A special
1818 * exception is made for the IMMUTABLE flags
1819 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1820 * HFS volumes as well:
1822 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
1823 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) &&
1824 ((flags
& ~IMMUTABLE
) == 0))) {
1825 if (flags
!= (uint32_t)VNOVAL
) {
1826 cp
->c_flags
= flags
;
1830 *abp
->ab_attrbufpp
= attrbufptr
;
1836 struct attrblock
*abp
,
1837 struct hfsmount
*hfsmp
,
1838 struct vnode
*root_vp
)
1840 void *attrbufptr
= *abp
->ab_attrbufpp
;
1843 boolean_t is_64_bit
= proc_is64bit(current_proc());
1845 HFS_MOUNT_LOCK(hfsmp
, TRUE
);
1847 attr
= abp
->ab_attrlist
->commonattr
;
1851 if (ATTR_CMN_SCRIPT
& attr
) {
1852 hfsmp
->volumeNameEncodingHint
=
1853 (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
1855 if (ATTR_CMN_CRTIME
& attr
) {
1857 hfsmp
->vcbCrDate
= ((struct user_timespec
*)attrbufptr
)->tv_sec
;
1858 ++((struct user_timespec
*)attrbufptr
);
1861 hfsmp
->vcbCrDate
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1862 ++((struct timespec
*)attrbufptr
);
1865 /* The volume's create date comes from the root directory */
1866 VTOC(root_vp
)->c_itime
= hfsmp
->vcbCrDate
;
1867 VTOC(root_vp
)->c_flag
|= C_MODIFIED
;
1869 * XXX Should we also do a relative change to the
1870 * the volume header's create date in local time?
1873 if (ATTR_CMN_MODTIME
& attr
) {
1874 hfsmp
->vcbLsMod
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1875 ++((struct timespec
*)attrbufptr
);
1877 if (ATTR_CMN_BKUPTIME
& attr
) {
1878 hfsmp
->vcbVolBkUp
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1879 ++((struct timespec
*)attrbufptr
);
1881 if (ATTR_CMN_FNDRINFO
& attr
) {
1882 bcopy(attrbufptr
, &hfsmp
->vcbFndrInfo
, sizeof(hfsmp
->vcbFndrInfo
));
1883 (char *)attrbufptr
+= sizeof(hfsmp
->vcbFndrInfo
);
1887 attr
= abp
->ab_attrlist
->volattr
& ~ATTR_VOL_INFO
;
1889 * XXX - no validation is done on the name!
1890 * It could be empty or garbage (bad UTF-8).
1892 if (ATTR_VOL_NAME
& attr
) {
1893 attrreference_t
* attr_refp
= (attrreference_t
*) attrbufptr
;
1895 error
= copystr(((char *)attrbufptr
) + attr_refp
->attr_dataoffset
,
1896 hfsmp
->vcbVN
, MIN(attr_refp
->attr_length
, sizeof(hfsmp
->vcbVN
)),
1899 (char *)attrbufptr
+= sizeof(struct attrreference
);
1901 *abp
->ab_attrbufpp
= attrbufptr
;
1903 hfsmp
->vcbFlags
|= 0xFF00;
1904 HFS_MOUNT_UNLOCK(hfsmp
, TRUE
);
1911 * Calculate the total size of an attribute block.
1915 hfs_attrblksize(struct attrlist
*attrlist
)
1919 int sizeof_timespec
;
1920 boolean_t is_64_bit
= proc_is64bit(current_proc());
1923 sizeof_timespec
= sizeof(struct user_timespec
);
1925 sizeof_timespec
= sizeof(struct timespec
);
1927 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1928 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \
1929 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \
1930 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \
1931 ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1932 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \
1933 ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \
1934 != ATTR_CMN_VALIDMASK)
1935 #error hfs_attrblksize: Missing bits in common mask computation!
1937 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1939 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \
1940 ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
1941 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1942 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \
1943 ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \
1944 ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \
1945 ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1946 != ATTR_VOL_VALIDMASK)
1947 #error hfs_attrblksize: Missing bits in volume mask computation!
1949 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1951 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \
1952 != ATTR_DIR_VALIDMASK)
1953 #error hfs_attrblksize: Missing bits in directory mask computation!
1955 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1957 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
1958 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \
1959 ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \
1960 ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1961 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \
1962 != ATTR_FILE_VALIDMASK)
1963 #error hfs_attrblksize: Missing bits in file mask computation!
1965 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1967 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1968 #error hfs_attrblksize: Missing bits in fork mask computation!
1970 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1974 if ((a
= attrlist
->commonattr
) != 0) {
1975 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1976 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1977 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1978 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1979 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1980 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1981 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1982 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1983 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1984 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof_timespec
;
1985 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof_timespec
;
1986 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof_timespec
;
1987 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof_timespec
;
1988 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof_timespec
;
1989 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(u_int8_t
);
1990 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1991 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1992 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(uint32_t);
1993 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(uint32_t);
1994 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1995 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(uint32_t);
1996 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(uint32_t);
1998 if ((a
= attrlist
->volattr
) != 0) {
1999 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(uint32_t);
2000 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(uint32_t);
2001 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
2002 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
2003 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
2004 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
2005 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
2006 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(uint32_t);
2007 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(uint32_t);
2008 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(uint32_t);
2009 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(uint32_t);
2010 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(uint32_t);
2011 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
2012 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
2013 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(uint32_t);
2014 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
2015 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
2016 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
2017 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
2019 if ((a
= attrlist
->dirattr
) != 0) {
2020 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(uint32_t);
2021 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(uint32_t);
2022 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(uint32_t);
2024 if ((a
= attrlist
->fileattr
) != 0) {
2025 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(uint32_t);
2026 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
2027 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
2028 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(uint32_t);
2029 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(uint32_t);
2030 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(uint32_t);
2031 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(uint32_t);
2032 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(uint32_t);
2033 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
2034 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
2035 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
2036 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
2037 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
2038 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
2039 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
2041 if ((a
= attrlist
->forkattr
) != 0) {
2042 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
2043 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
2052 DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
,
2053 struct mount
*mp
, kauth_cred_t cred
, struct proc
*p
)
2055 unsigned long permissions
;
2057 if (obj_uid
== UNKNOWNUID
)
2058 obj_uid
= kauth_cred_getuid(proc_ucred(p
));
2060 /* User id 0 (root) always gets access. */
2061 if (!suser(cred
, NULL
)) {
2062 permissions
= R_OK
| W_OK
| X_OK
;
2066 /* Otherwise, check the owner. */
2067 if (hfs_owner_rights(VFSTOHFS(mp
), obj_uid
, cred
, p
, false) == 0) {
2068 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
2072 /* Otherwise, check the groups. */
2073 if (! (((unsigned int)vfs_flags(mp
)) & MNT_UNKNOWNPERMISSIONS
)) {
2076 if (kauth_cred_ismember_gid(cred
, obj_gid
, &is_member
) == 0 && is_member
) {
2077 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
2082 /* Otherwise, settle for 'others' access. */
2083 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
2086 return (permissions
);