2 * Copyright (c) 2000-2002 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>
38 #include "hfs_cnode.h"
39 #include "hfs_mount.h"
41 #include "hfs_attrlist.h"
45 extern uid_t console_user
;
48 /* Routines that are shared by hfs_setattr: */
49 extern int hfs_write_access(struct vnode
*vp
, struct ucred
*cred
,
50 struct proc
*p
, Boolean considerFlags
);
52 extern int hfs_chflags(struct vnode
*vp
, u_long flags
, struct ucred
*cred
,
55 extern int hfs_chmod(struct vnode
*vp
, int mode
, struct ucred
*cred
,
58 extern int hfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, struct ucred
*cred
,
61 extern char * hfs_getnamehint(struct cnode
*dcp
, int index
);
63 extern void hfs_savenamehint(struct cnode
*dcp
, int index
, const char * namehint
);
65 extern void hfs_relnamehint(struct cnode
*dcp
, int index
);
67 /* Packing routines: */
70 static void packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
73 static void packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
76 static void packcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
77 struct vnode
*vp
, struct cat_desc
* cdp
,
78 struct cat_attr
* cap
);
80 static void packfileattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
81 struct cat_attr
*cattrp
, struct cat_fork
*datafork
,
82 struct cat_fork
*rsrcfork
);
84 static void packdirattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
85 struct vnode
*vp
, struct cat_desc
* descp
,
86 struct cat_attr
* cattrp
);
88 static void unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
);
90 static void unpackcommonattr(struct attrblock
*abp
, struct vnode
*vp
);
92 static void unpackvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
93 struct vnode
*rootvp
);
99 #% getattrlist vp = = =
103 IN struct attrlist *alist;
104 INOUT struct uio *uio;
105 IN struct ucred *cred;
113 struct vop_getattrlist_args
/* {
115 struct attrlist *a_alist
117 struct ucred *a_cred;
121 struct vnode
*vp
= ap
->a_vp
;
122 struct cnode
*cp
= VTOC(vp
);
123 struct hfsmount
*hfsmp
= VTOHFS(vp
);
124 struct attrlist
*alist
= ap
->a_alist
;
132 struct attrblock attrblk
;
133 struct cat_fork
*datafp
= NULL
;
134 struct cat_fork
*rsrcfp
= NULL
;
135 struct cat_fork rsrcfork
= {0};
138 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
139 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
140 ((alist
->volattr
& ~ATTR_VOL_VALIDMASK
) != 0) ||
141 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
142 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0)) {
147 * Requesting volume information requires setting the
148 * ATTR_VOL_INFO bit. Also, volume info requests are
149 * mutually exclusive with all other info requests.
151 if ((alist
->volattr
!= 0) &&
152 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
153 (alist
->dirattr
!= 0) || (alist
->fileattr
!= 0))) {
157 /* Reject requests for unsupported options for now: */
158 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
)) ||
159 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
| ATTR_FILE_FORKLIST
))) {
163 /* Requesting volume information requires root vnode */
164 if ((alist
->volattr
) && cp
->c_fileid
!= kRootDirID
)
167 /* Asking for data fork attributes from the rsrc fork is not supported */
168 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
))
175 /* This file doesn't have a name! */
176 if ((cp
->c_desc
.cd_namelen
== 0) && (alist
->commonattr
& ATTR_CMN_NAME
))
179 /* Update cnode times if needed */
181 CTIMES(cp
, &tv
, &tv
);
184 * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on
185 * an HFS volume we must be sure to create the thread
186 * record before returning it. (yikes)
188 if ((vp
->v_type
== VREG
) &&
189 (alist
->commonattr
& ATTR_CMN_OBJPERMANENTID
) &&
190 (VTOVCB(vp
)->vcbSigWord
!= kHFSPlusSigWord
)) {
192 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
)
194 if ((error
= hfs_write_access(vp
, ap
->a_cred
, ap
->a_p
, false)) != 0)
198 hfs_global_shared_lock_acquire(hfsmp
);
200 if ((error
= journal_start_transaction(hfsmp
->jnl
)) != 0) {
201 hfs_global_shared_lock_release(hfsmp
);
206 /* Lock catalog b-tree */
207 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, ap
->a_p
);
210 journal_end_transaction(hfsmp
->jnl
);
212 hfs_global_shared_lock_release(hfsmp
);
216 error
= cat_insertfilethread(hfsmp
, &cp
->c_desc
);
218 /* Unlock catalog b-tree */
219 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, ap
->a_p
);
222 journal_end_transaction(hfsmp
->jnl
);
224 hfs_global_shared_lock_release(hfsmp
);
230 /* Establish known fork data */
231 if (cp
->c_datafork
!= NULL
) {
232 datafp
= &cp
->c_datafork
->ff_data
;
233 if ((cp
->c_rsrcfork
== NULL
) &&
234 (cp
->c_blocks
== datafp
->cf_blocks
))
235 rsrcfp
= &rsrcfork
; /* rsrc fork is empty */
237 if (cp
->c_rsrcfork
!= NULL
)
238 rsrcfp
= &cp
->c_rsrcfork
->ff_data
;
241 * When resource fork data is requested and its not available
242 * in the cnode and the fork is not empty then it needs to be
243 * fetched from the catalog.
245 if ((alist
->fileattr
& ATTR_RSRCFORK_MASK
) && (rsrcfp
== NULL
)) {
246 /* Lock catalog b-tree */
247 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, ap
->a_p
);
251 /* Get resource fork data */
252 error
= cat_lookup(hfsmp
, &cp
->c_desc
, 1,
253 (struct cat_desc
*)0, (struct cat_attr
*)0, &rsrcfork
);
255 /* Unlock the Catalog */
256 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, ap
->a_p
);
263 fixedblocksize
= hfs_attrblksize(alist
);
264 attrblocksize
= fixedblocksize
+ (sizeof(u_long
)); /* u_long for length longword */
265 if (alist
->commonattr
& ATTR_CMN_NAME
)
266 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
267 if (alist
->volattr
& ATTR_VOL_MOUNTPOINT
)
268 attrblocksize
+= PATH_MAX
;
269 if (alist
->volattr
& ATTR_VOL_NAME
)
270 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
272 if (alist
->commonattr
& ATTR_CMN_NAMEDATTRLIST
)
274 if (alist
->fileattr
& ATTR_FILE_FORKLIST
)
277 attrbufsize
= MIN(ap
->a_uio
->uio_resid
, attrblocksize
);
278 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
279 attrptr
= attrbufptr
;
280 *((u_long
*)attrptr
) = 0; /* Set buffer length in case of errors */
281 ++((u_long
*)attrptr
); /* Reserve space for length field */
282 varptr
= ((char *)attrptr
) + fixedblocksize
;
284 attrblk
.ab_attrlist
= alist
;
285 attrblk
.ab_attrbufpp
= &attrptr
;
286 attrblk
.ab_varbufpp
= &varptr
;
287 attrblk
.ab_flags
= 0;
288 attrblk
.ab_blocksize
= attrblocksize
;
290 hfs_packattrblk(&attrblk
, hfsmp
, vp
, &cp
->c_desc
, &cp
->c_attr
,
293 /* Don't copy out more data than was generated */
294 attrbufsize
= MIN(attrbufsize
, (u_int
)varptr
- (u_int
)attrbufptr
);
295 /* Set actual buffer length for return to caller */
296 *((u_long
*)attrbufptr
) = attrbufsize
;
297 error
= uiomove((caddr_t
)attrbufptr
, attrbufsize
, ap
->a_uio
);
299 FREE(attrbufptr
, M_TEMP
);
307 #% setattrlist vp L L L
311 IN struct attrlist *alist;
312 INOUT struct uio *uio;
313 IN struct ucred *cred;
321 struct vop_setattrlist_args
/* {
323 struct attrlist *a_alist
325 struct ucred *a_cred;
329 struct vnode
*vp
= ap
->a_vp
;
330 struct cnode
*cp
= VTOC(vp
);
331 struct hfsmount
* hfsmp
= VTOHFS(vp
);
332 struct attrlist
*alist
= ap
->a_alist
;
333 struct ucred
*cred
= ap
->a_cred
;
334 struct proc
*p
= ap
->a_p
;
336 void *attrbufptr
= NULL
;
339 struct attrblock attrblk
;
346 if (VTOVFS(vp
)->mnt_flag
& MNT_RDONLY
)
348 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
349 ((alist
->commonattr
& ~ATTR_CMN_SETMASK
) != 0) ||
350 ((alist
->volattr
& ~ATTR_VOL_SETMASK
) != 0) ||
351 ((alist
->dirattr
& ~ATTR_DIR_SETMASK
) != 0) ||
352 ((alist
->fileattr
& ~ATTR_FILE_SETMASK
) != 0)) {
356 * When setting volume attributes make sure
357 * that ATTR_VOL_INFO is set and that all
358 * the attributes are valid.
360 if ((alist
->volattr
!= 0) &&
361 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
362 (alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
363 (cp
->c_fileid
!= kRootDirID
))) {
364 if ((alist
->volattr
& ATTR_VOL_INFO
) == 0)
365 printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
367 printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
368 alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
);
371 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
374 // XXXdbg - don't allow modifying the journal or journal_info_block
375 if (hfsmp
->jnl
&& cp
->c_datafork
) {
376 struct HFSPlusExtentDescriptor
*extd
;
378 extd
= &cp
->c_datafork
->ff_data
.cf_extents
[0];
379 if (extd
->startBlock
== HFSTOVCB(hfsmp
)->vcbJinfoBlock
|| extd
->startBlock
== hfsmp
->jnl_start
) {
385 * Ownership of a file is required in one of two classes of calls:
387 * (a) When setting any ownership-requiring attribute other
388 * than ATTR_CMN_FLAGS, or
389 * (b) When setting ATTR_CMN_FLAGS on a volume that's not
390 * plain HFS (for which no real per-object ownership
391 * information is stored)
393 if ((alist
->commonattr
& (ATTR_OWNERSHIP_SETMASK
& ~ATTR_CMN_FLAGS
)) ||
394 ((alist
->commonattr
& ATTR_CMN_FLAGS
) &&
395 (VTOVCB(vp
)->vcbSigWord
!= kHFSSigWord
))) {
397 * NOTE: The following isn't ENTIRELY complete: even if
398 * you're the superuser you cannot change the flags as
399 * long as SF_IMMUTABLE or SF_APPEND is set and the
400 * securelevel > 0. This is verified in hfs_chflags
401 * which gets invoked to do the actual flags field
402 * change so this check is sufficient for now.
404 if ((error
= hfs_owner_rights(hfsmp
, cp
->c_uid
, cred
, p
, true)) != 0)
408 * For any other attributes, check to see if the user has
409 * write access to the cnode in question [unlike VOP_ACCESS,
410 * ignore IMMUTABLE here]:
412 if (((alist
->commonattr
& ~ATTR_OWNERSHIP_SETMASK
) != 0) ||
413 (alist
->volattr
!= 0) || (alist
->dirattr
!= 0) ||
414 (alist
->fileattr
!= 0)) {
415 if ((error
= hfs_write_access(vp
, cred
, p
, false)) != 0)
420 * Allocate the buffer now to minimize the time we might
421 * be blocked holding the catalog lock.
423 attrblocksize
= ap
->a_uio
->uio_resid
;
424 if (attrblocksize
< hfs_attrblksize(alist
))
427 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
429 error
= uiomove((caddr_t
)attrbufptr
, attrblocksize
, ap
->a_uio
);
433 /* Save original state so changes can be detected. */
434 saved_uid
= cp
->c_uid
;
435 saved_gid
= cp
->c_gid
;
436 saved_mode
= cp
->c_mode
;
437 saved_flags
= cp
->c_flags
;
439 attrptr
= attrbufptr
;
440 attrblk
.ab_attrlist
= alist
;
441 attrblk
.ab_attrbufpp
= &attrptr
;
442 attrblk
.ab_varbufpp
= &varptr
;
443 attrblk
.ab_flags
= 0;
444 attrblk
.ab_blocksize
= attrblocksize
;
445 unpackattrblk(&attrblk
, vp
);
447 /* If unpacking changed the owner/group then call hfs_chown() */
448 if ((saved_uid
!= cp
->c_uid
) || (saved_gid
!= cp
->c_gid
)) {
453 cp
->c_uid
= saved_uid
;
455 cp
->c_gid
= saved_gid
;
456 if ((error
= hfs_chown(vp
, uid
, gid
, cred
, p
)))
459 /* If unpacking changed the mode then call hfs_chmod() */
460 if (saved_mode
!= cp
->c_mode
) {
464 cp
->c_mode
= saved_mode
;
465 if ((error
= hfs_chmod(vp
, mode
, cred
, p
)))
468 /* If unpacking changed the flags then call hfs_chflags() */
469 if (saved_flags
!=cp
->c_flags
) {
473 cp
->c_flags
= saved_flags
;
474 if ((error
= hfs_chflags(vp
, flags
, cred
, p
)))
478 * If any cnode attributes changed then do an update.
480 if (alist
->volattr
== 0) {
483 cp
->c_flag
|= C_MODIFIED
;
485 CTIMES(cp
, &tv
, &tv
);
486 if ((error
= VOP_UPDATE(vp
, &tv
, &tv
, 1)))
490 if (alist
->volattr
& ATTR_VOL_NAME
) {
491 ExtendedVCB
*vcb
= VTOVCB(vp
);
493 if (vcb
->vcbVN
[0] == 0) {
495 * Ignore attempts to rename a volume to a zero-length name:
496 * restore the original name from the cnode.
498 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
500 struct cat_desc to_desc
= {0};
501 struct cat_desc todir_desc
= {0};
502 struct cat_desc new_desc
= {0};
504 todir_desc
.cd_parentcnid
= kRootParID
;
505 todir_desc
.cd_cnid
= kRootParID
;
506 todir_desc
.cd_flags
= CD_ISDIR
;
508 to_desc
.cd_nameptr
= vcb
->vcbVN
;
509 to_desc
.cd_namelen
= strlen(vcb
->vcbVN
);
510 to_desc
.cd_parentcnid
= kRootParID
;
511 to_desc
.cd_cnid
= cp
->c_cnid
;
512 to_desc
.cd_flags
= CD_ISDIR
;
515 hfs_global_shared_lock_acquire(hfsmp
);
517 if (journal_start_transaction(hfsmp
->jnl
) != 0) {
518 hfs_global_shared_lock_release(hfsmp
);
520 /* Restore the old name in the VCB */
521 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
522 vcb
->vcbFlags
|= 0xFF00;
528 /* Lock catalog b-tree */
529 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
532 journal_end_transaction(hfsmp
->jnl
);
534 hfs_global_shared_lock_release(hfsmp
);
536 /* Restore the old name in the VCB */
537 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
538 vcb
->vcbFlags
|= 0xFF00;
542 error
= cat_rename(hfsmp
, &cp
->c_desc
, &todir_desc
, &to_desc
, &new_desc
);
544 /* Unlock the Catalog */
545 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
548 journal_end_transaction(hfsmp
->jnl
);
550 hfs_global_shared_lock_release(hfsmp
);
553 /* Restore the old name in the VCB */
554 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
555 vcb
->vcbFlags
|= 0xFF00;
558 /* Release old allocated name buffer */
559 if (cp
->c_desc
.cd_flags
& CD_HASBUF
) {
560 char *name
= cp
->c_desc
.cd_nameptr
;
562 cp
->c_desc
.cd_nameptr
= 0;
563 cp
->c_desc
.cd_namelen
= 0;
564 cp
->c_desc
.cd_flags
&= ~CD_HASBUF
;
567 /* Update cnode's catalog descriptor */
568 replace_desc(cp
, &new_desc
);
569 vcb
->volumeNameEncodingHint
= new_desc
.cd_encoding
;
570 cp
->c_flag
|= C_CHANGE
;
575 * When the volume name changes or the volume's finder info
576 * changes then force them to disk immediately.
578 if ((alist
->volattr
& ATTR_VOL_INFO
) &&
579 ((alist
->volattr
& ATTR_VOL_NAME
) ||
580 (alist
->commonattr
& ATTR_CMN_FNDRINFO
))) {
581 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
585 FREE(attrbufptr
, M_TEMP
);
592 * readdirattr operation will return attributes for the items in the
593 * directory specified.
595 * It does not do . and .. entries. The problem is if you are at the root of the
596 * hfs directory and go to .. you could be crossing a mountpoint into a
597 * different (ufs) file system. The attributes that apply for it may not
598 * apply for the file system you are doing the readdirattr on. To make life
599 * simpler, this call will only return entries in its directory, hfs like.
601 * 1. more than one for uiovcnt support.
602 * 2. put knohint (hints) in state for next call in
603 * 3. credentials checking when rest of hfs does it.
604 * 4. Do return permissions concatenation ???
609 #% readdirattr vp L L L
613 IN struct attrlist *alist;
614 INOUT struct uio *uio;
617 OUT u_long *newstate;
619 OUT u_long *actualCount;
620 OUT u_long **cookies;
621 IN struct ucred *cred;
627 struct vop_readdirattr_args
/* {
629 struct attrlist *a_alist;
635 u_long *a_actualcount;
637 struct ucred *a_cred;
640 struct vnode
*dvp
= ap
->a_vp
;
641 struct cnode
*dcp
= VTOC(dvp
);
642 struct hfsmount
* hfsmp
= VTOHFS(dvp
);
643 struct attrlist
*alist
= ap
->a_alist
;
644 struct uio
*uio
= ap
->a_uio
;
645 int maxcount
= ap
->a_maxcount
;
646 struct proc
*p
= current_proc();
647 u_long fixedblocksize
;
648 u_long maxattrblocksize
;
649 u_long currattrbufsize
;
650 void *attrbufptr
= NULL
;
653 struct attrblock attrblk
;
656 int index
, startindex
;
658 struct cat_desc
*lastdescp
= NULL
;
659 struct cat_desc prevdesc
;
660 char * prevnamebuf
= NULL
;
661 struct cat_entrylist
*ce_list
= NULL
;
663 dir_entries
= dcp
->c_entries
;
664 if (dcp
->c_attr
.ca_fileid
== kHFSRootFolderID
&& hfsmp
->jnl
) {
668 *(ap
->a_actualcount
) = 0;
669 *(ap
->a_eofflag
) = 0;
671 if (ap
->a_cookies
!= NULL
) {
672 printf("readdirattr: no cookies!\n");
676 /* Check for invalid options and buffer space. */
677 if (((ap
->a_options
& ~(FSOPT_NOINMEMUPDATE
| FSOPT_NOFOLLOW
)) != 0)
678 || (uio
->uio_resid
<= 0) || (uio
->uio_iovcnt
> 1) || (maxcount
<= 0))
681 /* This call doesn't take volume attributes. */
682 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
683 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
684 (alist
->volattr
!= 0) ||
685 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
686 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0))
689 /* Reject requests for unsupported options. */
690 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
|
691 ATTR_CMN_OBJPERMANENTID
)) ||
692 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
|
693 ATTR_FILE_FORKLIST
| ATTR_FILE_DATAEXTENTS
| ATTR_FILE_RSRCEXTENTS
))) {
694 printf("readdirattr: unsupported attributes! (%s)\n", dcp
->c_desc
.cd_nameptr
);
698 /* Convert uio_offset into a directory index. */
699 startindex
= index
= uio
->uio_offset
/ sizeof(struct dirent
);
700 if ((index
+ 1) > dir_entries
) {
701 *(ap
->a_eofflag
) = 1;
706 /* Get a buffer to hold packed attributes. */
707 fixedblocksize
= (sizeof(u_long
) + hfs_attrblksize(alist
)); /* u_long 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 /* Initialize a starting descriptor. */
721 bzero(&prevdesc
, sizeof(prevdesc
));
722 prevdesc
.cd_flags
= CD_DECOMPOSED
;
723 prevdesc
.cd_hint
= dcp
->c_childhint
;
724 prevdesc
.cd_parentcnid
= dcp
->c_cnid
;
725 prevdesc
.cd_nameptr
= hfs_getnamehint(dcp
, index
);
726 prevdesc
.cd_namelen
= prevdesc
.cd_nameptr
? strlen(prevdesc
.cd_nameptr
) : 0;
729 * Obtain a list of catalog entries and pack their attributes until
730 * the output buffer is full or maxcount entries have been packed.
735 /* Constrain our list size. */
736 maxentries
= uio
->uio_resid
/ (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
);
737 maxentries
= min(maxentries
, dcp
->c_entries
- index
);
738 maxentries
= min(maxentries
, maxcount
);
739 ce_list
->maxentries
= min(maxentries
, ce_list
->maxentries
);
742 /* Lock catalog b-tree. */
743 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, p
);
747 error
= cat_getentriesattr(hfsmp
, &prevdesc
, index
, ce_list
);
748 /* Don't forget to release the descriptors later! */
750 /* Unlock catalog b-tree. */
751 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
753 if (error
== ENOENT
) {
754 *(ap
->a_eofflag
) = TRUE
;
761 /* Process the catalog entries. */
762 for (i
= 0; i
< ce_list
->realentries
; ++i
) {
763 struct cnode
*cp
= NULL
;
764 struct vnode
*vp
= NULL
;
765 struct vnode
*rvp
= NULL
;
766 struct cat_desc
* cdescp
;
767 struct cat_attr
* cattrp
;
768 struct cat_fork c_datafork
= {0};
769 struct cat_fork c_rsrcfork
= {0};
771 cdescp
= &ce_list
->entry
[i
].ce_desc
;
772 cattrp
= &ce_list
->entry
[i
].ce_attr
;
773 c_datafork
.cf_size
= ce_list
->entry
[i
].ce_datasize
;
774 c_datafork
.cf_blocks
= ce_list
->entry
[i
].ce_datablks
;
775 c_rsrcfork
.cf_size
= ce_list
->entry
[i
].ce_rsrcsize
;
776 c_rsrcfork
.cf_blocks
= ce_list
->entry
[i
].ce_rsrcblks
;
778 * Get in memory cnode data (if any).
780 if (!(ap
->a_options
& FSOPT_NOINMEMUPDATE
)) {
781 cp
= hfs_chashget(dcp
->c_dev
, cattrp
->ca_fileid
, 0, &vp
, &rvp
);
783 /* Only use cnode's decriptor for non-hardlinks */
784 if (!(cp
->c_flag
& C_HARDLINK
))
785 cdescp
= &cp
->c_desc
;
786 cattrp
= &cp
->c_attr
;
787 if (cp
->c_datafork
) {
788 c_datafork
.cf_size
= cp
->c_datafork
->ff_data
.cf_size
;
789 c_datafork
.cf_clump
= cp
->c_datafork
->ff_data
.cf_clump
;
790 c_datafork
.cf_blocks
= cp
->c_datafork
->ff_data
.cf_blocks
;
792 if (cp
->c_rsrcfork
) {
793 c_rsrcfork
.cf_size
= cp
->c_rsrcfork
->ff_data
.cf_size
;
794 c_rsrcfork
.cf_clump
= cp
->c_rsrcfork
->ff_data
.cf_clump
;
795 c_rsrcfork
.cf_blocks
= cp
->c_rsrcfork
->ff_data
.cf_blocks
;
799 *((u_long
*)attrptr
)++ = 0; /* move it past length */
800 attrblk
.ab_attrlist
= alist
;
801 attrblk
.ab_attrbufpp
= &attrptr
;
802 attrblk
.ab_varbufpp
= &varptr
;
803 attrblk
.ab_flags
= 0;
804 attrblk
.ab_blocksize
= maxattrblocksize
;
806 /* Pack catalog entries into attribute buffer. */
807 hfs_packattrblk(&attrblk
, hfsmp
, vp
, cdescp
, cattrp
,
808 &c_datafork
, &c_rsrcfork
);
809 currattrbufsize
= ((char *)varptr
- (char *)attrbufptr
);
811 /* All done with cnode. */
821 /* Make sure there's enough buffer space remaining. */
822 if (currattrbufsize
> uio
->uio_resid
) {
826 *((u_long
*)attrbufptr
) = currattrbufsize
;
827 error
= uiomove((caddr_t
)attrbufptr
, currattrbufsize
, ap
->a_uio
);
828 if (error
!= E_NONE
) {
832 attrptr
= attrbufptr
;
833 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
834 /* Save the last valid catalog entry */
835 lastdescp
= &ce_list
->entry
[i
].ce_desc
;
837 *ap
->a_actualcount
+= 1;
839 /* Termination checks */
840 if ((--maxcount
<= 0) ||
841 (uio
->uio_resid
< (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
)) ||
842 (index
>= dir_entries
)) {
847 } /* for each catalog entry */
849 /* If there are more entries then save the last name. */
850 if (index
< dir_entries
851 && !(*(ap
->a_eofflag
))
852 && lastdescp
!= NULL
) {
853 if (prevnamebuf
== NULL
)
854 MALLOC(prevnamebuf
, char *, kHFSPlusMaxFileNameBytes
+ 1, M_TEMP
, M_WAITOK
);
855 bcopy(lastdescp
->cd_nameptr
, prevnamebuf
, lastdescp
->cd_namelen
+ 1);
857 prevdesc
.cd_hint
= lastdescp
->cd_hint
;
858 prevdesc
.cd_nameptr
= prevnamebuf
;
859 prevdesc
.cd_namelen
= lastdescp
->cd_namelen
+ 1;
863 /* All done with the catalog descriptors. */
864 for (i
= 0; i
< ce_list
->realentries
; ++i
)
865 cat_releasedesc(&ce_list
->entry
[i
].ce_desc
);
866 ce_list
->realentries
= 0;
868 } /* while not depleted */
870 *ap
->a_newstate
= dcp
->c_mtime
;
872 /* All done with last name hint */
873 hfs_relnamehint(dcp
, startindex
);
876 /* Convert directory index into uio_offset. */
877 uio
->uio_offset
= index
* sizeof(struct dirent
);
879 /* Save a name hint if there are more entries */
880 if ((error
== 0) && prevnamebuf
&& (index
+ 1) < dcp
->c_entries
)
881 hfs_savenamehint(dcp
, index
, prevnamebuf
);
884 hfs_relnamehint(dcp
, startindex
);
887 FREE(attrbufptr
, M_TEMP
);
889 FREE(ce_list
, M_TEMP
);
891 FREE(prevnamebuf
, M_TEMP
);
897 /*==================== Attribute list support routines ====================*/
900 * Pack cnode attributes into an attribute block.
904 hfs_packattrblk(struct attrblock
*abp
,
905 struct hfsmount
*hfsmp
,
907 struct cat_desc
*descp
,
908 struct cat_attr
*attrp
,
909 struct cat_fork
*datafork
,
910 struct cat_fork
*rsrcfork
)
912 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
914 if (attrlistp
->volattr
) {
915 if (attrlistp
->commonattr
)
916 packvolcommonattr(abp
, hfsmp
, vp
);
918 if (attrlistp
->volattr
& ~ATTR_VOL_INFO
)
919 packvolattr(abp
, hfsmp
, vp
);
921 if (attrlistp
->commonattr
)
922 packcommonattr(abp
, hfsmp
, vp
, descp
, attrp
);
924 if (attrlistp
->dirattr
&& S_ISDIR(attrp
->ca_mode
))
925 packdirattr(abp
, hfsmp
, vp
, descp
,attrp
);
927 if (attrlistp
->fileattr
&& !S_ISDIR(attrp
->ca_mode
))
928 packfileattr(abp
, hfsmp
, attrp
, datafork
, rsrcfork
);
934 mountpointname(struct mount
*mp
)
936 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
944 * Look backwards through the name string, looking for
945 * the first slash encountered (which must precede the
946 * last part of the pathname).
948 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1;
949 namelength
> 0; --c
, --namelength
) {
952 } else if (foundchars
) {
957 return (mp
->mnt_stat
.f_mntonname
);
963 struct attrblock
*abp
,
969 struct attrreference
* attr_refptr
;
975 /* A cnode's name may be incorrect for the root of a mounted
976 * filesystem (it can be mounted on a different directory name
977 * than the name of the volume, such as "blah-1"). So for the
978 * root directory, it's best to return the last element of the
979 location where the volume's mounted:
981 if ((vp
!= NULL
) && (vp
->v_flag
& VROOT
) &&
982 (mpname
= mountpointname(vp
->v_mount
))) {
983 mpnamelen
= strlen(mpname
);
985 /* Trim off any trailing slashes: */
986 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/'))
989 /* If there's anything left, use it instead of the volume's name */
1000 varbufptr
= *abp
->ab_varbufpp
;
1001 attr_refptr
= (struct attrreference
*)(*abp
->ab_attrbufpp
);
1003 attrlength
= namelen
+ 1;
1004 attr_refptr
->attr_dataoffset
= (char *)varbufptr
- (char *)attr_refptr
;
1005 attr_refptr
->attr_length
= attrlength
;
1006 (void) strncpy((unsigned char *)varbufptr
, name
, attrlength
);
1008 * Advance beyond the space just allocated and
1009 * round up to the next 4-byte boundary:
1011 (char *)(varbufptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1014 *abp
->ab_attrbufpp
= attr_refptr
;
1015 *abp
->ab_varbufpp
= varbufptr
;
1019 * Pack common volume attributes.
1022 packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
)
1025 void *attrbufptr
= *abp
->ab_attrbufpp
;
1026 void *varbufptr
= *abp
->ab_varbufpp
;
1027 struct cnode
*cp
= VTOC(vp
);
1028 struct mount
*mp
= VTOVFS(vp
);
1029 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1032 attr
= abp
->ab_attrlist
->commonattr
;
1034 if (ATTR_CMN_NAME
& attr
) {
1035 packnameattr(abp
, vp
, cp
->c_desc
.cd_nameptr
, cp
->c_desc
.cd_namelen
);
1036 attrbufptr
= *abp
->ab_attrbufpp
;
1037 varbufptr
= *abp
->ab_varbufpp
;
1039 if (ATTR_CMN_DEVID
& attr
) {
1040 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1042 if (ATTR_CMN_FSID
& attr
) {
1043 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1044 ++((fsid_t
*)attrbufptr
);
1046 if (ATTR_CMN_OBJTYPE
& attr
) {
1047 *((fsobj_type_t
*)attrbufptr
)++ = 0;
1049 if (ATTR_CMN_OBJTAG
& attr
) {
1050 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1052 if (ATTR_CMN_OBJID
& attr
) {
1053 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1054 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1055 ++((fsobj_id_t
*)attrbufptr
);
1057 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1058 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1059 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1060 ++((fsobj_id_t
*)attrbufptr
);
1062 if (ATTR_CMN_PAROBJID
& attr
) {
1063 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1064 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1065 ++((fsobj_id_t
*)attrbufptr
);
1067 if (ATTR_CMN_SCRIPT
& attr
) {
1070 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1071 encoding
= vcb
->volumeNameEncodingHint
;
1073 encoding
= hfsmp
->hfs_encoding
;
1074 *((text_encoding_t
*)attrbufptr
)++ = encoding
;
1076 if (ATTR_CMN_CRTIME
& attr
) {
1077 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbCrDate
;
1078 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1079 ++((struct timespec
*)attrbufptr
);
1081 if (ATTR_CMN_MODTIME
& attr
) {
1082 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1083 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1084 ++((struct timespec
*)attrbufptr
);
1086 if (ATTR_CMN_CHGTIME
& attr
) {
1087 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1088 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1089 ++((struct timespec
*)attrbufptr
);
1091 if (ATTR_CMN_ACCTIME
& attr
) {
1092 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1093 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1094 ++((struct timespec
*)attrbufptr
);
1096 if (ATTR_CMN_BKUPTIME
& attr
) {
1097 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbVolBkUp
;
1098 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1099 ++((struct timespec
*)attrbufptr
);
1101 if (ATTR_CMN_FNDRINFO
& attr
) {
1102 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1103 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1105 if (ATTR_CMN_OWNERID
& attr
) {
1106 if (cp
->c_uid
== UNKNOWNUID
)
1107 *((uid_t
*)attrbufptr
)++ = console_user
;
1109 *((uid_t
*)attrbufptr
)++ = cp
->c_uid
;
1111 if (ATTR_CMN_GRPID
& attr
) {
1112 *((gid_t
*)attrbufptr
)++ = cp
->c_gid
;
1114 if (ATTR_CMN_ACCESSMASK
& attr
) {
1116 * [2856576] Since we are dynamically changing the owner, also
1117 * effectively turn off the set-user-id and set-group-id bits,
1118 * just like chmod(2) would when changing ownership. This prevents
1119 * a security hole where set-user-id programs run as whoever is
1120 * logged on (or root if nobody is logged in yet!)
1122 *((u_long
*)attrbufptr
)++ =
1123 (cp
->c_uid
== UNKNOWNUID
) ? cp
->c_mode
& ~(S_ISUID
| S_ISGID
) : cp
->c_mode
;
1125 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1126 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1128 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1130 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1131 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1133 * Advance beyond the space just allocated and
1134 * round up to the next 4-byte boundary:
1136 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1137 ++((struct attrreference
*)attrbufptr
);
1139 if (ATTR_CMN_FLAGS
& attr
) {
1140 *((u_long
*)attrbufptr
)++ = cp
->c_flags
;
1142 if (ATTR_CMN_USERACCESS
& attr
) {
1143 *((u_long
*)attrbufptr
)++ =
1144 DerivePermissionSummary(cp
->c_uid
, cp
->c_gid
, cp
->c_mode
,
1145 VTOVFS(vp
), current_proc()->p_ucred
, current_proc());
1148 *abp
->ab_attrbufpp
= attrbufptr
;
1149 *abp
->ab_varbufpp
= varbufptr
;
1154 packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
)
1157 void *attrbufptr
= *abp
->ab_attrbufpp
;
1158 void *varbufptr
= *abp
->ab_varbufpp
;
1159 struct cnode
*cp
= VTOC(vp
);
1160 struct mount
*mp
= VTOVFS(vp
);
1161 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1164 attr
= abp
->ab_attrlist
->volattr
;
1166 if (ATTR_VOL_FSTYPE
& attr
) {
1167 *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1169 if (ATTR_VOL_SIGNATURE
& attr
) {
1170 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1172 if (ATTR_VOL_SIZE
& attr
) {
1173 *((off_t
*)attrbufptr
)++ =
1174 (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1176 if (ATTR_VOL_SPACEFREE
& attr
) {
1177 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 0) *
1178 (off_t
)vcb
->blockSize
;
1181 if (ATTR_VOL_SPACEAVAIL
& attr
) {
1182 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 1) *
1183 (off_t
)vcb
->blockSize
;
1185 if (ATTR_VOL_MINALLOCATION
& attr
) {
1186 *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1188 if (ATTR_VOL_ALLOCATIONCLUMP
& attr
) {
1189 *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1191 if (ATTR_VOL_IOBLOCKSIZE
& attr
) {
1192 *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1194 if (ATTR_VOL_OBJCOUNT
& attr
) {
1195 *((u_long
*)attrbufptr
)++ =
1196 (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1198 if (ATTR_VOL_FILECOUNT
& attr
) {
1199 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1201 if (ATTR_VOL_DIRCOUNT
& attr
) {
1202 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1204 if (ATTR_VOL_MAXOBJCOUNT
& attr
) {
1205 *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1207 if (ATTR_VOL_MOUNTPOINT
& attr
) {
1208 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1209 (char *)varbufptr
- (char *)attrbufptr
;
1210 ((struct attrreference
*)attrbufptr
)->attr_length
=
1211 strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1212 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1213 /* round up to the next 4-byte boundary: */
1214 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1215 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1217 /* Advance beyond the space just allocated: */
1218 (char *)varbufptr
+= attrlength
;
1219 ++((struct attrreference
*)attrbufptr
);
1221 if (ATTR_VOL_NAME
& attr
) {
1222 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1223 (char *)varbufptr
- (char *)attrbufptr
;
1224 ((struct attrreference
*)attrbufptr
)->attr_length
=
1225 cp
->c_desc
.cd_namelen
+ 1;
1226 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1227 /* round up to the next 4-byte boundary: */
1228 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1229 /* XXX this could read off the end of cd_nameptr! */
1230 bcopy(cp
->c_desc
.cd_nameptr
, varbufptr
, attrlength
);
1232 /* Advance beyond the space just allocated: */
1233 (char *)varbufptr
+= attrlength
;
1234 ++((struct attrreference
*)attrbufptr
);
1236 if (ATTR_VOL_MOUNTFLAGS
& attr
) {
1237 *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
1239 if (ATTR_VOL_MOUNTEDDEVICE
& attr
) {
1240 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1241 (char *)varbufptr
- (char *)attrbufptr
;
1242 ((struct attrreference
*)attrbufptr
)->attr_length
=
1243 strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
1244 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1245 /* round up to the next 4-byte boundary: */
1246 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1247 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
1249 /* Advance beyond the space just allocated: */
1250 (char *)varbufptr
+= attrlength
;
1251 ++((struct attrreference
*)attrbufptr
);
1253 if (ATTR_VOL_ENCODINGSUSED
& attr
) {
1254 *((unsigned long long *)attrbufptr
)++ =
1255 (unsigned long long)vcb
->encodingsBitmap
;
1257 if (ATTR_VOL_CAPABILITIES
& attr
) {
1258 vol_capabilities_attr_t
*vcapattrptr
;
1260 vcapattrptr
= (vol_capabilities_attr_t
*)attrbufptr
;
1262 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1263 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1264 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1265 VOL_CAP_FMT_SYMBOLICLINKS
|
1266 VOL_CAP_FMT_HARDLINKS
;
1267 } else { /* Plain HFS */
1268 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1269 VOL_CAP_FMT_PERSISTENTOBJECTIDS
;
1271 vcapattrptr
->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1272 VOL_CAP_INT_SEARCHFS
|
1273 VOL_CAP_INT_ATTRLIST
|
1274 VOL_CAP_INT_NFSEXPORT
|
1275 VOL_CAP_INT_READDIRATTR
;
1276 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1277 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1279 vcapattrptr
->valid
[VOL_CAPABILITIES_FORMAT
] =
1280 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1281 VOL_CAP_FMT_SYMBOLICLINKS
|
1282 VOL_CAP_FMT_HARDLINKS
;
1283 vcapattrptr
->valid
[VOL_CAPABILITIES_INTERFACES
] =
1284 VOL_CAP_INT_SEARCHFS
|
1285 VOL_CAP_INT_ATTRLIST
|
1286 VOL_CAP_INT_NFSEXPORT
|
1287 VOL_CAP_INT_READDIRATTR
;
1288 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1289 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1291 ++((vol_capabilities_attr_t
*)attrbufptr
);
1293 if (ATTR_VOL_ATTRIBUTES
& attr
) {
1294 vol_attributes_attr_t
*volattrattrp
;
1296 volattrattrp
= (vol_attributes_attr_t
*)attrbufptr
;
1297 volattrattrp
->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1298 volattrattrp
->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
1299 volattrattrp
->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1300 volattrattrp
->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1301 volattrattrp
->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1303 volattrattrp
->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1304 volattrattrp
->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
1305 volattrattrp
->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1306 volattrattrp
->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1307 volattrattrp
->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1308 ++((vol_attributes_attr_t
*)attrbufptr
);
1311 *abp
->ab_attrbufpp
= attrbufptr
;
1312 *abp
->ab_varbufpp
= varbufptr
;
1318 struct attrblock
*abp
,
1319 struct hfsmount
*hfsmp
,
1321 struct cat_desc
* cdp
,
1322 struct cat_attr
* cap
)
1324 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1325 struct mount
*mp
= HFSTOVFS(hfsmp
);
1326 void *attrbufptr
= *abp
->ab_attrbufpp
;
1327 void *varbufptr
= *abp
->ab_varbufpp
;
1328 u_long attrlength
= 0;
1330 if (ATTR_CMN_NAME
& attr
) {
1331 packnameattr(abp
, vp
, cdp
->cd_nameptr
, cdp
->cd_namelen
);
1332 attrbufptr
= *abp
->ab_attrbufpp
;
1333 varbufptr
= *abp
->ab_varbufpp
;
1335 if (ATTR_CMN_DEVID
& attr
) {
1336 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1338 if (ATTR_CMN_FSID
& attr
) {
1339 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1340 ++((fsid_t
*)attrbufptr
);
1342 if (ATTR_CMN_OBJTYPE
& attr
) {
1343 *((fsobj_type_t
*)attrbufptr
)++ = IFTOVT(cap
->ca_mode
);
1345 if (ATTR_CMN_OBJTAG
& attr
) {
1346 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1349 * Exporting file IDs from HFS Plus:
1351 * For "normal" files the c_fileid is the same value as the
1352 * c_cnid. But for hard link files, they are different - the
1353 * c_cnid belongs to the active directory entry (ie the link)
1354 * and the c_fileid is for the actual inode (ie the data file).
1356 * The stat call (getattr) will always return the c_fileid
1357 * and Carbon APIs, which are hardlink-ignorant, will always
1358 * receive the c_cnid (from getattrlist).
1360 if (ATTR_CMN_OBJID
& attr
) {
1361 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1362 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1363 ++((fsobj_id_t
*)attrbufptr
);
1365 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1366 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1367 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1368 ++((fsobj_id_t
*)attrbufptr
);
1370 if (ATTR_CMN_PAROBJID
& attr
) {
1371 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_parentcnid
;
1372 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1373 ++((fsobj_id_t
*)attrbufptr
);
1375 if (ATTR_CMN_SCRIPT
& attr
) {
1376 *((text_encoding_t
*)attrbufptr
)++ = cdp
->cd_encoding
;
1378 if (ATTR_CMN_CRTIME
& attr
) {
1379 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_itime
;
1380 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1381 ++((struct timespec
*)attrbufptr
);
1383 if (ATTR_CMN_MODTIME
& attr
) {
1384 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_mtime
;
1385 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1386 ++((struct timespec
*)attrbufptr
);
1388 if (ATTR_CMN_CHGTIME
& attr
) {
1389 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_ctime
;
1390 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1391 ++((struct timespec
*)attrbufptr
);
1393 if (ATTR_CMN_ACCTIME
& attr
) {
1394 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_atime
;
1395 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1396 ++((struct timespec
*)attrbufptr
);
1398 if (ATTR_CMN_BKUPTIME
& attr
) {
1399 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_btime
;
1400 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1401 ++((struct timespec
*)attrbufptr
);
1403 if (ATTR_CMN_FNDRINFO
& attr
) {
1404 bcopy(&cap
->ca_finderinfo
, attrbufptr
, sizeof(u_int8_t
) * 32);
1405 (char *)attrbufptr
+= sizeof(u_int8_t
) * 32;
1407 if (ATTR_CMN_OWNERID
& attr
) {
1408 *((uid_t
*)attrbufptr
)++ =
1409 (cap
->ca_uid
== UNKNOWNUID
) ? console_user
: cap
->ca_uid
;
1411 if (ATTR_CMN_GRPID
& attr
) {
1412 *((gid_t
*)attrbufptr
)++ = cap
->ca_gid
;
1414 if (ATTR_CMN_ACCESSMASK
& attr
) {
1416 * [2856576] Since we are dynamically changing the owner, also
1417 * effectively turn off the set-user-id and set-group-id bits,
1418 * just like chmod(2) would when changing ownership. This prevents
1419 * a security hole where set-user-id programs run as whoever is
1420 * logged on (or root if nobody is logged in yet!)
1422 *((u_long
*)attrbufptr
)++ =
1423 (cap
->ca_uid
== UNKNOWNUID
) ? cap
->ca_mode
& ~(S_ISUID
| S_ISGID
) : cap
->ca_mode
;
1425 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1426 *((u_long
*)attrbufptr
)++ = 0;
1428 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1430 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1431 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1433 * Advance beyond the space just allocated and
1434 * round up to the next 4-byte boundary:
1436 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1437 ++((struct attrreference
*)attrbufptr
);
1439 if (ATTR_CMN_FLAGS
& attr
) {
1440 *((u_long
*)attrbufptr
)++ = cap
->ca_flags
;
1442 if (ATTR_CMN_USERACCESS
& attr
) {
1443 *((u_long
*)attrbufptr
)++ =
1444 DerivePermissionSummary(cap
->ca_uid
, cap
->ca_gid
,
1445 cap
->ca_mode
, mp
, current_proc()->p_ucred
,
1449 *abp
->ab_attrbufpp
= attrbufptr
;
1450 *abp
->ab_varbufpp
= varbufptr
;
1455 struct attrblock
*abp
,
1456 struct hfsmount
*hfsmp
,
1458 struct cat_desc
* descp
,
1459 struct cat_attr
* cattrp
)
1461 attrgroup_t attr
= abp
->ab_attrlist
->dirattr
;
1462 void *attrbufptr
= *abp
->ab_attrbufpp
;
1464 if (ATTR_DIR_LINKCOUNT
& attr
)
1465 *((u_long
*)attrbufptr
)++ = cattrp
->ca_nlink
;
1466 if (ATTR_DIR_ENTRYCOUNT
& attr
) {
1467 u_long entries
= cattrp
->ca_entries
;
1469 if (descp
->cd_parentcnid
== kRootParID
) {
1470 if (hfsmp
->hfs_private_metadata_dir
!= 0)
1471 --entries
; /* hide private dir */
1473 entries
-= 2; /* hide the journal files */
1476 *((u_long
*)attrbufptr
)++ = entries
;
1478 if (ATTR_DIR_MOUNTSTATUS
& attr
) {
1479 if (vp
!= NULL
&& vp
->v_mountedhere
!= NULL
)
1480 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
1482 *((u_long
*)attrbufptr
)++ = 0;
1484 *abp
->ab_attrbufpp
= attrbufptr
;
1489 struct attrblock
*abp
,
1490 struct hfsmount
*hfsmp
,
1491 struct cat_attr
*cattrp
,
1492 struct cat_fork
*datafork
,
1493 struct cat_fork
*rsrcfork
)
1495 attrgroup_t attr
= abp
->ab_attrlist
->fileattr
;
1496 void *attrbufptr
= *abp
->ab_attrbufpp
;
1497 void *varbufptr
= *abp
->ab_varbufpp
;
1499 u_long allocblksize
;
1501 allocblksize
= HFSTOVCB(hfsmp
)->blockSize
;
1503 if (ATTR_FILE_LINKCOUNT
& attr
) {
1504 *((u_long
*)attrbufptr
)++ = cattrp
->ca_nlink
;
1506 if (ATTR_FILE_TOTALSIZE
& attr
) {
1507 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
+ rsrcfork
->cf_size
;
1509 if (ATTR_FILE_ALLOCSIZE
& attr
) {
1510 *((off_t
*)attrbufptr
)++ =
1511 (off_t
)cattrp
->ca_blocks
* (off_t
)allocblksize
;
1513 if (ATTR_FILE_IOBLOCKSIZE
& attr
) {
1514 *((u_long
*)attrbufptr
)++ = hfsmp
->hfs_logBlockSize
;
1516 if (ATTR_FILE_CLUMPSIZE
& attr
) {
1517 *((u_long
*)attrbufptr
)++ = datafork
->cf_clump
; /* XXX ambiguity */
1519 if (ATTR_FILE_DEVTYPE
& attr
) {
1520 if (S_ISBLK(cattrp
->ca_mode
) || S_ISCHR(cattrp
->ca_mode
))
1521 *((u_long
*)attrbufptr
)++ = (u_long
)cattrp
->ca_rdev
;
1523 *((u_long
*)attrbufptr
)++ = 0;
1525 if (ATTR_FILE_FILETYPE
& attr
) {
1526 *((u_long
*)attrbufptr
)++ = 0;
1528 if (ATTR_FILE_FORKCOUNT
& attr
) {
1529 *((u_long
*)attrbufptr
)++ = 2;
1531 if (ATTR_FILE_FORKLIST
& attr
) {
1533 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1534 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1536 * Advance beyond the space just allocated and
1537 * round up to the next 4-byte boundary:
1539 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1540 ++((struct attrreference
*)attrbufptr
);
1542 if (ATTR_FILE_DATALENGTH
& attr
) {
1543 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
;
1545 if (ATTR_FILE_DATAALLOCSIZE
& attr
) {
1546 *((off_t
*)attrbufptr
)++ =
1547 (off_t
)datafork
->cf_blocks
* (off_t
)allocblksize
;
1549 if (ATTR_FILE_DATAEXTENTS
& attr
) {
1550 bcopy(&datafork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1551 (char *)attrbufptr
+= sizeof(extentrecord
);
1553 if (ATTR_FILE_RSRCLENGTH
& attr
) {
1554 *((off_t
*)attrbufptr
)++ = rsrcfork
->cf_size
;
1556 if (ATTR_FILE_RSRCALLOCSIZE
& attr
) {
1557 *((off_t
*)attrbufptr
)++ =
1558 (off_t
)rsrcfork
->cf_blocks
* (off_t
)allocblksize
;
1560 if (ATTR_FILE_RSRCEXTENTS
& attr
) {
1561 bcopy(&rsrcfork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1562 (char *)attrbufptr
+= sizeof(extentrecord
);
1564 *abp
->ab_attrbufpp
= attrbufptr
;
1565 *abp
->ab_varbufpp
= varbufptr
;
1570 unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
)
1572 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
1574 if (attrlistp
->volattr
)
1575 unpackvolattr(abp
, VTOHFS(vp
), vp
);
1576 else if (attrlistp
->commonattr
)
1577 unpackcommonattr(abp
, vp
);
1583 struct attrblock
*abp
,
1586 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1587 void *attrbufptr
= *abp
->ab_attrbufpp
;
1588 struct cnode
*cp
= VTOC(vp
);
1590 if (ATTR_CMN_SCRIPT
& attr
) {
1591 cp
->c_encoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
1592 hfs_setencodingbits(VTOHFS(vp
), cp
->c_encoding
);
1594 if (ATTR_CMN_CRTIME
& attr
) {
1595 cp
->c_itime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1596 ++((struct timespec
*)attrbufptr
);
1598 if (ATTR_CMN_MODTIME
& attr
) {
1599 cp
->c_mtime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1600 cp
->c_mtime_nsec
= ((struct timespec
*)attrbufptr
)->tv_nsec
;
1601 ++((struct timespec
*)attrbufptr
);
1602 cp
->c_flag
&= ~C_UPDATE
;
1604 if (ATTR_CMN_CHGTIME
& attr
) {
1605 cp
->c_ctime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1606 ++((struct timespec
*)attrbufptr
);
1607 cp
->c_flag
&= ~C_CHANGE
;
1609 if (ATTR_CMN_ACCTIME
& attr
) {
1610 cp
->c_atime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1611 ++((struct timespec
*)attrbufptr
);
1612 cp
->c_flag
&= ~C_ACCESS
;
1614 if (ATTR_CMN_BKUPTIME
& attr
) {
1615 cp
->c_btime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1616 ++((struct timespec
*)attrbufptr
);
1618 if (ATTR_CMN_FNDRINFO
& attr
) {
1619 bcopy(attrbufptr
, &cp
->c_attr
.ca_finderinfo
,
1620 sizeof(cp
->c_attr
.ca_finderinfo
));
1621 (char *)attrbufptr
+= sizeof(cp
->c_attr
.ca_finderinfo
);
1623 if (ATTR_CMN_OWNERID
& attr
) {
1624 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1625 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
1626 if (uid
!= (uid_t
)VNOVAL
)
1629 ((uid_t
*)attrbufptr
)++;
1632 if (ATTR_CMN_GRPID
& attr
) {
1633 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
1634 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1635 if (gid
!= (gid_t
)VNOVAL
)
1639 if (ATTR_CMN_ACCESSMASK
& attr
) {
1640 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
1641 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1642 if (mode
!= (mode_t
)VNOVAL
) {
1643 cp
->c_mode
&= ~ALLPERMS
;
1644 cp
->c_mode
|= (mode
& ALLPERMS
);
1648 if (ATTR_CMN_FLAGS
& attr
) {
1649 u_long flags
= *((u_long
*)attrbufptr
)++;
1651 * Flags are settable only on HFS+ volumes. A special
1652 * exception is made for the IMMUTABLE flags
1653 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1654 * HFS volumes as well:
1656 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
1657 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) &&
1658 ((flags
& ~IMMUTABLE
) == 0))) {
1659 if (flags
!= (u_long
)VNOVAL
) {
1660 cp
->c_flags
= flags
;
1664 *abp
->ab_attrbufpp
= attrbufptr
;
1670 struct attrblock
*abp
,
1671 struct hfsmount
*hfsmp
,
1672 struct vnode
*rootvp
)
1674 void *attrbufptr
= *abp
->ab_attrbufpp
;
1675 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1678 attr
= abp
->ab_attrlist
->commonattr
;
1682 if (ATTR_CMN_SCRIPT
& attr
) {
1683 vcb
->volumeNameEncodingHint
=
1684 (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
1686 if (ATTR_CMN_CRTIME
& attr
) {
1687 vcb
->vcbCrDate
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1688 ++((struct timespec
*)attrbufptr
);
1690 /* The volume's create date comes from the root directory */
1691 VTOC(rootvp
)->c_itime
= vcb
->vcbCrDate
;
1692 VTOC(rootvp
)->c_flag
|= C_MODIFIED
;
1694 * XXX Should we also do a relative change to the
1695 * the volume header's create date in local time?
1698 if (ATTR_CMN_MODTIME
& attr
) {
1699 vcb
->vcbLsMod
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1700 ++((struct timespec
*)attrbufptr
);
1702 if (ATTR_CMN_BKUPTIME
& attr
) {
1703 vcb
->vcbVolBkUp
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1704 ++((struct timespec
*)attrbufptr
);
1706 if (ATTR_CMN_FNDRINFO
& attr
) {
1707 bcopy(attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
1708 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1712 attr
= abp
->ab_attrlist
->volattr
& ~ATTR_VOL_INFO
;
1714 * XXX - no validation is done on the name!
1715 * It could be empty or garbage (bad UTF-8).
1717 if (ATTR_VOL_NAME
& attr
) {
1718 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
),
1719 vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
1720 (char *)attrbufptr
+= sizeof(struct attrreference
);
1722 *abp
->ab_attrbufpp
= attrbufptr
;
1724 vcb
->vcbFlags
|= 0xFF00;
1728 * Calculate the total size of an attribute block.
1732 hfs_attrblksize(struct attrlist
*attrlist
)
1737 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1738 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \
1739 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \
1740 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \
1741 ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1742 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \
1743 ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \
1744 != ATTR_CMN_VALIDMASK)
1745 #error hfs_attrblksize: Missing bits in common mask computation!
1747 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1749 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \
1750 ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
1751 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1752 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \
1753 ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \
1754 ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \
1755 ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1756 != ATTR_VOL_VALIDMASK)
1757 #error hfs_attrblksize: Missing bits in volume mask computation!
1759 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1761 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \
1762 != ATTR_DIR_VALIDMASK)
1763 #error hfs_attrblksize: Missing bits in directory mask computation!
1765 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1767 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
1768 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \
1769 ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \
1770 ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1771 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \
1772 != ATTR_FILE_VALIDMASK)
1773 #error hfs_attrblksize: Missing bits in file mask computation!
1775 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1777 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1778 #error hfs_attrblksize: Missing bits in fork mask computation!
1780 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1784 if ((a
= attrlist
->commonattr
) != 0) {
1785 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1786 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1787 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1788 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1789 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1790 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1791 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1792 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1793 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1794 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1795 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1796 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1797 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1798 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1799 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(u_int8_t
);
1800 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1801 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1802 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1803 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1804 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1805 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1806 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1808 if ((a
= attrlist
->volattr
) != 0) {
1809 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1810 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1811 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1812 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1813 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1814 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1815 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1816 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1817 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1818 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1819 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1820 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1821 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1822 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1823 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1824 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1825 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1826 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1827 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1829 if ((a
= attrlist
->dirattr
) != 0) {
1830 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1831 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1832 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1834 if ((a
= attrlist
->fileattr
) != 0) {
1835 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1836 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1837 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1838 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1839 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1840 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1841 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1842 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1843 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1844 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1845 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1846 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1847 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1848 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1849 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1851 if ((a
= attrlist
->forkattr
) != 0) {
1852 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1853 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1862 DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
,
1863 struct mount
*mp
, struct ucred
*cred
, struct proc
*p
)
1866 unsigned long permissions
;
1869 if (obj_uid
== UNKNOWNUID
)
1870 obj_uid
= console_user
;
1872 /* User id 0 (root) always gets access. */
1873 if (cred
->cr_uid
== 0) {
1874 permissions
= R_OK
| W_OK
| X_OK
;
1878 /* Otherwise, check the owner. */
1879 if (hfs_owner_rights(VFSTOHFS(mp
), obj_uid
, cred
, p
, false) == 0) {
1880 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1884 /* Otherwise, check the groups. */
1885 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1886 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1887 if (obj_gid
== *gp
) {
1888 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1894 /* Otherwise, settle for 'others' access. */
1895 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1898 return (permissions
);