2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * hfs_attrlist.c - HFS attribute list processing
29 * Copyright (c) 1998-2002, Apple Computer, Inc. All Rights Reserved.
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
38 #include <sys/unistd.h>
41 #include "hfs_cnode.h"
42 #include "hfs_mount.h"
44 #include "hfs_attrlist.h"
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
,
71 struct vnode
*vp
, struct proc
*p
);
73 static void packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
74 struct vnode
*vp
, struct proc
*p
);
76 static void packcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
77 struct vnode
*vp
, struct cat_desc
* cdp
,
78 struct cat_attr
* cap
, struct proc
*p
);
80 static void packfileattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
81 struct cat_attr
*cattrp
, struct cat_fork
*datafork
,
82 struct cat_fork
*rsrcfork
, struct proc
*p
);
84 static void packdirattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
85 struct vnode
*vp
, struct cat_desc
* descp
,
86 struct cat_attr
* cattrp
, struct proc
*p
);
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 cat_cookie_t cookie
= {0};
194 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
)
196 if ((error
= hfs_write_access(vp
, ap
->a_cred
, ap
->a_p
, false)) != 0)
200 * Reserve some space in the Catalog file.
202 error
= cat_preflight(hfsmp
, CAT_CREATE
, &cookie
, ap
->a_p
);
206 /* Lock catalog b-tree */
207 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
,
208 LK_EXCLUSIVE
, ap
->a_p
);
210 cat_postflight(hfsmp
, &cookie
, ap
->a_p
);
214 error
= cat_insertfilethread(hfsmp
, &cp
->c_desc
);
216 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
,
219 cat_postflight(hfsmp
, &cookie
, ap
->a_p
);
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
)) {
241 /* Lock catalog b-tree */
242 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, ap
->a_p
);
246 /* Get resource fork data */
247 error
= cat_lookup(hfsmp
, &cp
->c_desc
, 1,
248 (struct cat_desc
*)0, (struct cat_attr
*)0, &rsrcfork
);
250 /* Unlock the Catalog */
251 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, ap
->a_p
);
258 fixedblocksize
= hfs_attrblksize(alist
);
259 attrblocksize
= fixedblocksize
+ (sizeof(u_long
)); /* u_long for length longword */
260 if (alist
->commonattr
& ATTR_CMN_NAME
)
261 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
262 if (alist
->volattr
& ATTR_VOL_MOUNTPOINT
)
263 attrblocksize
+= PATH_MAX
;
264 if (alist
->volattr
& ATTR_VOL_NAME
)
265 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
267 if (alist
->commonattr
& ATTR_CMN_NAMEDATTRLIST
)
269 if (alist
->fileattr
& ATTR_FILE_FORKLIST
)
272 attrbufsize
= MIN(ap
->a_uio
->uio_resid
, attrblocksize
);
273 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
274 attrptr
= attrbufptr
;
275 *((u_long
*)attrptr
) = 0; /* Set buffer length in case of errors */
276 ++((u_long
*)attrptr
); /* Reserve space for length field */
277 varptr
= ((char *)attrptr
) + fixedblocksize
;
279 attrblk
.ab_attrlist
= alist
;
280 attrblk
.ab_attrbufpp
= &attrptr
;
281 attrblk
.ab_varbufpp
= &varptr
;
282 attrblk
.ab_flags
= 0;
283 attrblk
.ab_blocksize
= attrblocksize
;
285 hfs_packattrblk(&attrblk
, hfsmp
, vp
, &cp
->c_desc
, &cp
->c_attr
,
286 datafp
, rsrcfp
, ap
->a_p
);
288 /* Don't copy out more data than was generated */
289 attrbufsize
= MIN(attrbufsize
, (u_int
)varptr
- (u_int
)attrbufptr
);
290 /* Set actual buffer length for return to caller */
291 *((u_long
*)attrbufptr
) = attrbufsize
;
292 error
= uiomove((caddr_t
)attrbufptr
, attrbufsize
, ap
->a_uio
);
294 FREE(attrbufptr
, M_TEMP
);
302 #% setattrlist vp L L L
306 IN struct attrlist *alist;
307 INOUT struct uio *uio;
308 IN struct ucred *cred;
316 struct vop_setattrlist_args
/* {
318 struct attrlist *a_alist
320 struct ucred *a_cred;
324 struct vnode
*vp
= ap
->a_vp
;
325 struct cnode
*cp
= VTOC(vp
);
326 struct hfsmount
* hfsmp
= VTOHFS(vp
);
327 struct attrlist
*alist
= ap
->a_alist
;
328 struct ucred
*cred
= ap
->a_cred
;
329 struct proc
*p
= ap
->a_p
;
331 void *attrbufptr
= NULL
;
334 struct attrblock attrblk
;
341 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
)
343 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
344 ((alist
->commonattr
& ~ATTR_CMN_SETMASK
) != 0) ||
345 ((alist
->volattr
& ~ATTR_VOL_SETMASK
) != 0) ||
346 ((alist
->dirattr
& ~ATTR_DIR_SETMASK
) != 0) ||
347 ((alist
->fileattr
& ~ATTR_FILE_SETMASK
) != 0)) {
351 * When setting volume attributes make sure
352 * that ATTR_VOL_INFO is set and that all
353 * the attributes are valid.
355 if ((alist
->volattr
!= 0) &&
356 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
357 (alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
358 (cp
->c_fileid
!= kRootDirID
))) {
359 if ((alist
->volattr
& ATTR_VOL_INFO
) == 0)
360 printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
362 printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
363 alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
);
366 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
369 // XXXdbg - don't allow modifying the journal or journal_info_block
370 if (hfsmp
->jnl
&& cp
->c_datafork
) {
371 struct HFSPlusExtentDescriptor
*extd
;
373 extd
= &cp
->c_datafork
->ff_extents
[0];
374 if (extd
->startBlock
== HFSTOVCB(hfsmp
)->vcbJinfoBlock
|| extd
->startBlock
== hfsmp
->jnl_start
) {
380 * Ownership of a file is required in one of two classes of calls:
382 * (a) When setting any ownership-requiring attribute other
383 * than ATTR_CMN_FLAGS, or
384 * (b) When setting ATTR_CMN_FLAGS on a volume that's not
385 * plain HFS (for which no real per-object ownership
386 * information is stored)
388 if ((alist
->commonattr
& (ATTR_OWNERSHIP_SETMASK
& ~ATTR_CMN_FLAGS
)) ||
389 ((alist
->commonattr
& ATTR_CMN_FLAGS
) &&
390 (VTOVCB(vp
)->vcbSigWord
!= kHFSSigWord
))) {
392 * NOTE: The following isn't ENTIRELY complete: even if
393 * you're the superuser you cannot change the flags as
394 * long as SF_IMMUTABLE or SF_APPEND is set and the
395 * securelevel > 0. This is verified in hfs_chflags
396 * which gets invoked to do the actual flags field
397 * change so this check is sufficient for now.
399 if ((error
= hfs_owner_rights(hfsmp
, cp
->c_uid
, cred
, p
, true)) != 0)
403 * For any other attributes, check to see if the user has
404 * write access to the cnode in question [unlike VOP_ACCESS,
405 * ignore IMMUTABLE here]:
407 if (((alist
->commonattr
& ~ATTR_OWNERSHIP_SETMASK
) != 0) ||
408 (alist
->volattr
!= 0) || (alist
->dirattr
!= 0) ||
409 (alist
->fileattr
!= 0)) {
410 if ((error
= hfs_write_access(vp
, cred
, p
, false)) != 0)
415 * Allocate the buffer now to minimize the time we might
416 * be blocked holding the catalog lock.
418 attrblocksize
= ap
->a_uio
->uio_resid
;
419 if (attrblocksize
< hfs_attrblksize(alist
))
422 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
424 error
= uiomove((caddr_t
)attrbufptr
, attrblocksize
, ap
->a_uio
);
428 /* Save original state so changes can be detected. */
429 saved_uid
= cp
->c_uid
;
430 saved_gid
= cp
->c_gid
;
431 saved_mode
= cp
->c_mode
;
432 saved_flags
= cp
->c_flags
;
434 attrptr
= attrbufptr
;
435 attrblk
.ab_attrlist
= alist
;
436 attrblk
.ab_attrbufpp
= &attrptr
;
437 attrblk
.ab_varbufpp
= &varptr
;
438 attrblk
.ab_flags
= 0;
439 attrblk
.ab_blocksize
= attrblocksize
;
440 unpackattrblk(&attrblk
, vp
);
442 /* If unpacking changed the owner/group then call hfs_chown() */
443 if ((saved_uid
!= cp
->c_uid
) || (saved_gid
!= cp
->c_gid
)) {
448 cp
->c_uid
= saved_uid
;
450 cp
->c_gid
= saved_gid
;
451 if ((error
= hfs_chown(vp
, uid
, gid
, cred
, p
)))
454 /* If unpacking changed the mode then call hfs_chmod() */
455 if (saved_mode
!= cp
->c_mode
) {
459 cp
->c_mode
= saved_mode
;
460 if ((error
= hfs_chmod(vp
, mode
, cred
, p
)))
463 /* If unpacking changed the flags then call hfs_chflags() */
464 if (saved_flags
!=cp
->c_flags
) {
468 cp
->c_flags
= saved_flags
;
469 if ((error
= hfs_chflags(vp
, flags
, cred
, p
)))
473 * If any cnode attributes changed then do an update.
475 if (alist
->volattr
== 0) {
478 cp
->c_flag
|= C_MODIFIED
;
480 CTIMES(cp
, &tv
, &tv
);
481 if ((error
= VOP_UPDATE(vp
, &tv
, &tv
, 1)))
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
= {0};
496 struct cat_desc todir_desc
= {0};
497 struct cat_desc new_desc
= {0};
498 cat_cookie_t cookie
= {0};
503 todir_desc
.cd_parentcnid
= kRootParID
;
504 todir_desc
.cd_cnid
= kRootParID
;
505 todir_desc
.cd_flags
= CD_ISDIR
;
507 to_desc
.cd_nameptr
= vcb
->vcbVN
;
508 to_desc
.cd_namelen
= strlen(vcb
->vcbVN
);
509 to_desc
.cd_parentcnid
= kRootParID
;
510 to_desc
.cd_cnid
= cp
->c_cnid
;
511 to_desc
.cd_flags
= CD_ISDIR
;
514 hfs_global_shared_lock_acquire(hfsmp
);
516 if ((error
= journal_start_transaction(hfsmp
->jnl
) != 0)) {
523 * Reserve some space in the Catalog file.
525 error
= cat_preflight(hfsmp
, CAT_RENAME
, &cookie
, p
);
531 /* Lock catalog b-tree */
532 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
538 error
= cat_rename(hfsmp
, &cp
->c_desc
, &todir_desc
, &to_desc
, &new_desc
);
541 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
544 cat_postflight(hfsmp
, &cookie
, p
);
547 journal_end_transaction(hfsmp
->jnl
);
549 hfs_global_shared_lock_release(hfsmp
);
552 /* Restore the old name in the VCB */
553 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
554 vcb
->vcbFlags
|= 0xFF00;
557 /* Release old allocated name buffer */
558 if (cp
->c_desc
.cd_flags
& CD_HASBUF
) {
559 char *name
= cp
->c_desc
.cd_nameptr
;
561 cp
->c_desc
.cd_nameptr
= 0;
562 cp
->c_desc
.cd_namelen
= 0;
563 cp
->c_desc
.cd_flags
&= ~CD_HASBUF
;
566 /* Update cnode's catalog descriptor */
567 replace_desc(cp
, &new_desc
);
568 vcb
->volumeNameEncodingHint
= new_desc
.cd_encoding
;
569 cp
->c_flag
|= C_CHANGE
;
574 * When the volume name changes or the volume's finder info
575 * changes then force them to disk immediately.
577 if ((alist
->volattr
& ATTR_VOL_INFO
) &&
578 ((alist
->volattr
& ATTR_VOL_NAME
) ||
579 (alist
->commonattr
& ATTR_CMN_FNDRINFO
))) {
580 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
584 FREE(attrbufptr
, M_TEMP
);
591 * readdirattr operation will return attributes for the items in the
592 * directory specified.
594 * It does not do . and .. entries. The problem is if you are at the root of the
595 * hfs directory and go to .. you could be crossing a mountpoint into a
596 * different (ufs) file system. The attributes that apply for it may not
597 * apply for the file system you are doing the readdirattr on. To make life
598 * simpler, this call will only return entries in its directory, hfs like.
600 * 1. more than one for uiovcnt support.
601 * 2. put knohint (hints) in state for next call in
602 * 3. credentials checking when rest of hfs does it.
603 * 4. Do return permissions concatenation ???
608 #% readdirattr vp L L L
612 IN struct attrlist *alist;
613 INOUT struct uio *uio;
616 OUT u_long *newstate;
618 OUT u_long *actualCount;
619 OUT u_long **cookies;
620 IN struct ucred *cred;
626 struct vop_readdirattr_args
/* {
628 struct attrlist *a_alist;
634 u_long *a_actualcount;
636 struct ucred *a_cred;
639 struct vnode
*dvp
= ap
->a_vp
;
640 struct cnode
*dcp
= VTOC(dvp
);
641 struct hfsmount
* hfsmp
= VTOHFS(dvp
);
642 struct attrlist
*alist
= ap
->a_alist
;
643 struct uio
*uio
= ap
->a_uio
;
644 int maxcount
= ap
->a_maxcount
;
645 struct proc
*p
= current_proc();
646 u_long fixedblocksize
;
647 u_long maxattrblocksize
;
648 u_long currattrbufsize
;
649 void *attrbufptr
= NULL
;
652 struct attrblock attrblk
;
655 int index
, startindex
;
657 struct cat_desc
*lastdescp
= NULL
;
658 struct cat_desc prevdesc
;
659 char * prevnamebuf
= NULL
;
660 struct cat_entrylist
*ce_list
= NULL
;
662 dir_entries
= dcp
->c_entries
;
663 if (dcp
->c_attr
.ca_fileid
== kHFSRootFolderID
&& hfsmp
->jnl
) {
667 *(ap
->a_actualcount
) = 0;
668 *(ap
->a_eofflag
) = 0;
670 if (ap
->a_cookies
!= NULL
) {
671 printf("readdirattr: no cookies!\n");
675 /* Check for invalid options and buffer space. */
676 if (((ap
->a_options
& ~(FSOPT_NOINMEMUPDATE
| FSOPT_NOFOLLOW
)) != 0)
677 || (uio
->uio_resid
<= 0) || (uio
->uio_iovcnt
> 1) || (maxcount
<= 0))
680 /* This call doesn't take volume attributes. */
681 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
682 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
683 (alist
->volattr
!= 0) ||
684 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
685 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0))
688 /* Reject requests for unsupported options. */
689 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
|
690 ATTR_CMN_OBJPERMANENTID
)) ||
691 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
|
692 ATTR_FILE_FORKLIST
| ATTR_FILE_DATAEXTENTS
| ATTR_FILE_RSRCEXTENTS
))) {
693 printf("readdirattr: unsupported attributes! (%s)\n", dcp
->c_desc
.cd_nameptr
);
697 /* Convert uio_offset into a directory index. */
698 startindex
= index
= uio
->uio_offset
/ sizeof(struct dirent
);
699 if ((index
+ 1) > dir_entries
) {
700 *(ap
->a_eofflag
) = 1;
705 /* Get a buffer to hold packed attributes. */
706 fixedblocksize
= (sizeof(u_long
) + hfs_attrblksize(alist
)); /* u_long for length */
707 maxattrblocksize
= fixedblocksize
;
708 if (alist
->commonattr
& ATTR_CMN_NAME
)
709 maxattrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
710 MALLOC(attrbufptr
, void *, maxattrblocksize
, M_TEMP
, M_WAITOK
);
711 attrptr
= attrbufptr
;
712 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
714 /* Initialize a catalog entry list. */
715 MALLOC(ce_list
, struct cat_entrylist
*, sizeof(*ce_list
), M_TEMP
, M_WAITOK
);
716 bzero(ce_list
, sizeof(*ce_list
));
717 ce_list
->maxentries
= MAXCATENTRIES
;
719 /* Initialize a starting descriptor. */
720 bzero(&prevdesc
, sizeof(prevdesc
));
721 prevdesc
.cd_flags
= CD_DECOMPOSED
;
722 prevdesc
.cd_hint
= dcp
->c_childhint
;
723 prevdesc
.cd_parentcnid
= dcp
->c_cnid
;
724 prevdesc
.cd_nameptr
= hfs_getnamehint(dcp
, index
);
725 prevdesc
.cd_namelen
= prevdesc
.cd_nameptr
? strlen(prevdesc
.cd_nameptr
) : 0;
728 * Obtain a list of catalog entries and pack their attributes until
729 * the output buffer is full or maxcount entries have been packed.
734 /* Constrain our list size. */
735 maxentries
= uio
->uio_resid
/ (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
);
736 maxentries
= min(maxentries
, dcp
->c_entries
- index
);
737 maxentries
= min(maxentries
, maxcount
);
738 ce_list
->maxentries
= min(maxentries
, ce_list
->maxentries
);
741 /* Lock catalog b-tree. */
742 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, p
);
746 error
= cat_getentriesattr(hfsmp
, &prevdesc
, index
, ce_list
);
747 /* Don't forget to release the descriptors later! */
749 /* Unlock catalog b-tree. */
750 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
752 if (error
== ENOENT
) {
753 *(ap
->a_eofflag
) = TRUE
;
760 /* Process the catalog entries. */
761 for (i
= 0; i
< ce_list
->realentries
; ++i
) {
762 struct cnode
*cp
= NULL
;
763 struct vnode
*vp
= NULL
;
764 struct vnode
*rvp
= NULL
;
765 struct cat_desc
* cdescp
;
766 struct cat_attr
* cattrp
;
767 struct cat_fork c_datafork
= {0};
768 struct cat_fork c_rsrcfork
= {0};
770 cdescp
= &ce_list
->entry
[i
].ce_desc
;
771 cattrp
= &ce_list
->entry
[i
].ce_attr
;
772 c_datafork
.cf_size
= ce_list
->entry
[i
].ce_datasize
;
773 c_datafork
.cf_blocks
= ce_list
->entry
[i
].ce_datablks
;
774 c_rsrcfork
.cf_size
= ce_list
->entry
[i
].ce_rsrcsize
;
775 c_rsrcfork
.cf_blocks
= ce_list
->entry
[i
].ce_rsrcblks
;
777 * Get in memory cnode data (if any).
779 if (!(ap
->a_options
& FSOPT_NOINMEMUPDATE
)) {
780 cp
= hfs_chashget(dcp
->c_dev
, cattrp
->ca_fileid
, 0, &vp
, &rvp
);
782 /* Only use cnode's decriptor for non-hardlinks */
783 if (!(cp
->c_flag
& C_HARDLINK
))
784 cdescp
= &cp
->c_desc
;
785 cattrp
= &cp
->c_attr
;
786 if (cp
->c_datafork
) {
787 c_datafork
.cf_size
= cp
->c_datafork
->ff_size
;
788 c_datafork
.cf_blocks
= cp
->c_datafork
->ff_blocks
;
790 if (cp
->c_rsrcfork
) {
791 c_rsrcfork
.cf_size
= cp
->c_rsrcfork
->ff_size
;
792 c_rsrcfork
.cf_blocks
= cp
->c_rsrcfork
->ff_blocks
;
796 *((u_long
*)attrptr
)++ = 0; /* move it past length */
797 attrblk
.ab_attrlist
= alist
;
798 attrblk
.ab_attrbufpp
= &attrptr
;
799 attrblk
.ab_varbufpp
= &varptr
;
800 attrblk
.ab_flags
= 0;
801 attrblk
.ab_blocksize
= maxattrblocksize
;
803 /* Pack catalog entries into attribute buffer. */
804 hfs_packattrblk(&attrblk
, hfsmp
, vp
, cdescp
, cattrp
,
805 &c_datafork
, &c_rsrcfork
, p
);
806 currattrbufsize
= ((char *)varptr
- (char *)attrbufptr
);
808 /* All done with cnode. */
818 /* Make sure there's enough buffer space remaining. */
819 if (currattrbufsize
> uio
->uio_resid
) {
823 *((u_long
*)attrbufptr
) = currattrbufsize
;
824 error
= uiomove((caddr_t
)attrbufptr
, currattrbufsize
, ap
->a_uio
);
825 if (error
!= E_NONE
) {
829 attrptr
= attrbufptr
;
830 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
831 /* Save the last valid catalog entry */
832 lastdescp
= &ce_list
->entry
[i
].ce_desc
;
834 *ap
->a_actualcount
+= 1;
836 /* Termination checks */
837 if ((--maxcount
<= 0) ||
838 (uio
->uio_resid
< (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
)) ||
839 (index
>= dir_entries
)) {
844 } /* for each catalog entry */
846 /* If there are more entries then save the last name. */
847 if (index
< dir_entries
848 && !(*(ap
->a_eofflag
))
849 && lastdescp
!= NULL
) {
850 if (prevnamebuf
== NULL
)
851 MALLOC(prevnamebuf
, char *, kHFSPlusMaxFileNameBytes
+ 1, M_TEMP
, M_WAITOK
);
852 bcopy(lastdescp
->cd_nameptr
, prevnamebuf
, lastdescp
->cd_namelen
+ 1);
854 prevdesc
.cd_hint
= lastdescp
->cd_hint
;
855 prevdesc
.cd_nameptr
= prevnamebuf
;
856 prevdesc
.cd_namelen
= lastdescp
->cd_namelen
+ 1;
860 /* All done with the catalog descriptors. */
861 for (i
= 0; i
< ce_list
->realentries
; ++i
)
862 cat_releasedesc(&ce_list
->entry
[i
].ce_desc
);
863 ce_list
->realentries
= 0;
865 } /* while not depleted */
867 *ap
->a_newstate
= dcp
->c_mtime
;
869 /* All done with last name hint */
870 hfs_relnamehint(dcp
, startindex
);
873 /* Convert directory index into uio_offset. */
874 uio
->uio_offset
= index
* sizeof(struct dirent
);
876 /* Save a name hint if there are more entries */
877 if ((error
== 0) && prevnamebuf
&& (index
+ 1) < dcp
->c_entries
)
878 hfs_savenamehint(dcp
, index
, prevnamebuf
);
881 hfs_relnamehint(dcp
, startindex
);
884 FREE(attrbufptr
, M_TEMP
);
886 FREE(ce_list
, M_TEMP
);
888 FREE(prevnamebuf
, M_TEMP
);
894 /*==================== Attribute list support routines ====================*/
897 * Pack cnode attributes into an attribute block.
901 hfs_packattrblk(struct attrblock
*abp
,
902 struct hfsmount
*hfsmp
,
904 struct cat_desc
*descp
,
905 struct cat_attr
*attrp
,
906 struct cat_fork
*datafork
,
907 struct cat_fork
*rsrcfork
,
910 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
912 if (attrlistp
->volattr
) {
913 if (attrlistp
->commonattr
)
914 packvolcommonattr(abp
, hfsmp
, vp
, p
);
916 if (attrlistp
->volattr
& ~ATTR_VOL_INFO
)
917 packvolattr(abp
, hfsmp
, vp
, p
);
919 if (attrlistp
->commonattr
)
920 packcommonattr(abp
, hfsmp
, vp
, descp
, attrp
, p
);
922 if (attrlistp
->dirattr
&& S_ISDIR(attrp
->ca_mode
))
923 packdirattr(abp
, hfsmp
, vp
, descp
,attrp
, p
);
925 if (attrlistp
->fileattr
&& !S_ISDIR(attrp
->ca_mode
))
926 packfileattr(abp
, hfsmp
, attrp
, datafork
, rsrcfork
, p
);
932 mountpointname(struct mount
*mp
)
934 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
942 * Look backwards through the name string, looking for
943 * the first slash encountered (which must precede the
944 * last part of the pathname).
946 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1;
947 namelength
> 0; --c
, --namelength
) {
950 } else if (foundchars
) {
955 return (mp
->mnt_stat
.f_mntonname
);
961 struct attrblock
*abp
,
968 struct attrreference
* attr_refptr
;
974 /* A cnode's name may be incorrect for the root of a mounted
975 * filesystem (it can be mounted on a different directory name
976 * than the name of the volume, such as "blah-1"). So for the
977 * root directory, it's best to return the last element of the
978 location where the volume's mounted:
980 if ((vp
!= NULL
) && (vp
->v_flag
& VROOT
) &&
981 (mpname
= mountpointname(vp
->v_mount
))) {
982 mpnamelen
= strlen(mpname
);
984 /* Trim off any trailing slashes: */
985 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/'))
988 /* If there's anything left, use it instead of the volume's name */
999 varbufptr
= *abp
->ab_varbufpp
;
1000 attr_refptr
= (struct attrreference
*)(*abp
->ab_attrbufpp
);
1002 attrlength
= namelen
+ 1;
1003 attr_refptr
->attr_dataoffset
= (char *)varbufptr
- (char *)attr_refptr
;
1004 attr_refptr
->attr_length
= attrlength
;
1005 (void) strncpy((unsigned char *)varbufptr
, name
, attrlength
);
1007 * Advance beyond the space just allocated and
1008 * round up to the next 4-byte boundary:
1010 (char *)(varbufptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1013 *abp
->ab_attrbufpp
= attr_refptr
;
1014 *abp
->ab_varbufpp
= varbufptr
;
1018 * Pack common volume attributes.
1021 packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
, struct proc
*p
)
1024 void *attrbufptr
= *abp
->ab_attrbufpp
;
1025 void *varbufptr
= *abp
->ab_varbufpp
;
1026 struct cnode
*cp
= VTOC(vp
);
1027 struct mount
*mp
= VTOVFS(vp
);
1028 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1031 attr
= abp
->ab_attrlist
->commonattr
;
1033 if (ATTR_CMN_NAME
& attr
) {
1034 packnameattr(abp
, vp
, cp
->c_desc
.cd_nameptr
, cp
->c_desc
.cd_namelen
, p
);
1035 attrbufptr
= *abp
->ab_attrbufpp
;
1036 varbufptr
= *abp
->ab_varbufpp
;
1038 if (ATTR_CMN_DEVID
& attr
) {
1039 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1041 if (ATTR_CMN_FSID
& attr
) {
1042 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1043 ++((fsid_t
*)attrbufptr
);
1045 if (ATTR_CMN_OBJTYPE
& attr
) {
1046 *((fsobj_type_t
*)attrbufptr
)++ = 0;
1048 if (ATTR_CMN_OBJTAG
& attr
) {
1049 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1051 if (ATTR_CMN_OBJID
& attr
) {
1052 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1053 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1054 ++((fsobj_id_t
*)attrbufptr
);
1056 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1057 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1058 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1059 ++((fsobj_id_t
*)attrbufptr
);
1061 if (ATTR_CMN_PAROBJID
& attr
) {
1062 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1063 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1064 ++((fsobj_id_t
*)attrbufptr
);
1066 if (ATTR_CMN_SCRIPT
& attr
) {
1069 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1070 encoding
= vcb
->volumeNameEncodingHint
;
1072 encoding
= hfsmp
->hfs_encoding
;
1073 *((text_encoding_t
*)attrbufptr
)++ = encoding
;
1075 if (ATTR_CMN_CRTIME
& attr
) {
1076 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbCrDate
;
1077 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1078 ++((struct timespec
*)attrbufptr
);
1080 if (ATTR_CMN_MODTIME
& attr
) {
1081 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1082 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1083 ++((struct timespec
*)attrbufptr
);
1085 if (ATTR_CMN_CHGTIME
& attr
) {
1086 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1087 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1088 ++((struct timespec
*)attrbufptr
);
1090 if (ATTR_CMN_ACCTIME
& attr
) {
1091 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1092 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1093 ++((struct timespec
*)attrbufptr
);
1095 if (ATTR_CMN_BKUPTIME
& attr
) {
1096 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbVolBkUp
;
1097 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1098 ++((struct timespec
*)attrbufptr
);
1100 if (ATTR_CMN_FNDRINFO
& attr
) {
1101 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1102 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1104 if (ATTR_CMN_OWNERID
& attr
) {
1105 if (cp
->c_uid
== UNKNOWNUID
)
1106 *((uid_t
*)attrbufptr
)++ = p
->p_ucred
->cr_uid
;
1108 *((uid_t
*)attrbufptr
)++ = cp
->c_uid
;
1110 if (ATTR_CMN_GRPID
& attr
) {
1111 *((gid_t
*)attrbufptr
)++ = cp
->c_gid
;
1113 if (ATTR_CMN_ACCESSMASK
& attr
) {
1115 * [2856576] Since we are dynamically changing the owner, also
1116 * effectively turn off the set-user-id and set-group-id bits,
1117 * just like chmod(2) would when changing ownership. This prevents
1118 * a security hole where set-user-id programs run as whoever is
1119 * logged on (or root if nobody is logged in yet!)
1121 *((u_long
*)attrbufptr
)++ =
1122 (cp
->c_uid
== UNKNOWNUID
) ? cp
->c_mode
& ~(S_ISUID
| S_ISGID
) : cp
->c_mode
;
1124 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1125 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1127 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1129 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1130 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1132 * Advance beyond the space just allocated and
1133 * round up to the next 4-byte boundary:
1135 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1136 ++((struct attrreference
*)attrbufptr
);
1138 if (ATTR_CMN_FLAGS
& attr
) {
1139 *((u_long
*)attrbufptr
)++ = cp
->c_flags
;
1141 if (ATTR_CMN_USERACCESS
& attr
) {
1142 *((u_long
*)attrbufptr
)++ =
1143 DerivePermissionSummary(cp
->c_uid
, cp
->c_gid
, cp
->c_mode
,
1144 VTOVFS(vp
), current_proc()->p_ucred
, current_proc());
1147 *abp
->ab_attrbufpp
= attrbufptr
;
1148 *abp
->ab_varbufpp
= varbufptr
;
1153 packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
, struct proc
*p
)
1156 void *attrbufptr
= *abp
->ab_attrbufpp
;
1157 void *varbufptr
= *abp
->ab_varbufpp
;
1158 struct cnode
*cp
= VTOC(vp
);
1159 struct mount
*mp
= VTOVFS(vp
);
1160 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1163 attr
= abp
->ab_attrlist
->volattr
;
1165 if (ATTR_VOL_FSTYPE
& attr
) {
1166 *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1168 if (ATTR_VOL_SIGNATURE
& attr
) {
1169 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1171 if (ATTR_VOL_SIZE
& attr
) {
1172 *((off_t
*)attrbufptr
)++ =
1173 (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1175 if (ATTR_VOL_SPACEFREE
& attr
) {
1176 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 0) *
1177 (off_t
)vcb
->blockSize
;
1179 if (ATTR_VOL_SPACEAVAIL
& attr
) {
1180 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 1) *
1181 (off_t
)vcb
->blockSize
;
1183 if (ATTR_VOL_MINALLOCATION
& attr
) {
1184 *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1186 if (ATTR_VOL_ALLOCATIONCLUMP
& attr
) {
1187 *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1189 if (ATTR_VOL_IOBLOCKSIZE
& attr
) {
1190 *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1192 if (ATTR_VOL_OBJCOUNT
& attr
) {
1193 *((u_long
*)attrbufptr
)++ =
1194 (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1196 if (ATTR_VOL_FILECOUNT
& attr
) {
1197 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1199 if (ATTR_VOL_DIRCOUNT
& attr
) {
1200 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1202 if (ATTR_VOL_MAXOBJCOUNT
& attr
) {
1203 *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1205 if (ATTR_VOL_MOUNTPOINT
& attr
) {
1206 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1207 (char *)varbufptr
- (char *)attrbufptr
;
1208 ((struct attrreference
*)attrbufptr
)->attr_length
=
1209 strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1210 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1211 /* round up to the next 4-byte boundary: */
1212 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1213 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1215 /* Advance beyond the space just allocated: */
1216 (char *)varbufptr
+= attrlength
;
1217 ++((struct attrreference
*)attrbufptr
);
1219 if (ATTR_VOL_NAME
& attr
) {
1220 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1221 (char *)varbufptr
- (char *)attrbufptr
;
1222 ((struct attrreference
*)attrbufptr
)->attr_length
=
1223 cp
->c_desc
.cd_namelen
+ 1;
1224 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1225 /* round up to the next 4-byte boundary: */
1226 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1227 /* XXX this could read off the end of cd_nameptr! */
1228 bcopy(cp
->c_desc
.cd_nameptr
, varbufptr
, attrlength
);
1230 /* Advance beyond the space just allocated: */
1231 (char *)varbufptr
+= attrlength
;
1232 ++((struct attrreference
*)attrbufptr
);
1234 if (ATTR_VOL_MOUNTFLAGS
& attr
) {
1235 *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
1237 if (ATTR_VOL_MOUNTEDDEVICE
& attr
) {
1238 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1239 (char *)varbufptr
- (char *)attrbufptr
;
1240 ((struct attrreference
*)attrbufptr
)->attr_length
=
1241 strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
1242 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1243 /* round up to the next 4-byte boundary: */
1244 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1245 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
1247 /* Advance beyond the space just allocated: */
1248 (char *)varbufptr
+= attrlength
;
1249 ++((struct attrreference
*)attrbufptr
);
1251 if (ATTR_VOL_ENCODINGSUSED
& attr
) {
1252 *((unsigned long long *)attrbufptr
)++ =
1253 (unsigned long long)vcb
->encodingsBitmap
;
1255 if (ATTR_VOL_CAPABILITIES
& attr
) {
1256 vol_capabilities_attr_t
*vcapattrptr
;
1258 vcapattrptr
= (vol_capabilities_attr_t
*)attrbufptr
;
1260 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1261 u_int32_t journal_active
;
1262 u_int32_t case_sensitive
;
1265 journal_active
= VOL_CAP_FMT_JOURNAL_ACTIVE
;
1269 if (hfsmp
->hfs_flags
& HFS_CASE_SENSITIVE
)
1270 case_sensitive
= VOL_CAP_FMT_CASE_SENSITIVE
;
1274 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1275 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1276 VOL_CAP_FMT_SYMBOLICLINKS
|
1277 VOL_CAP_FMT_HARDLINKS
|
1278 VOL_CAP_FMT_JOURNAL
|
1281 VOL_CAP_FMT_CASE_PRESERVING
|
1282 VOL_CAP_FMT_FAST_STATFS
;
1283 } else { /* Plain HFS */
1284 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1285 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1286 VOL_CAP_FMT_CASE_PRESERVING
|
1287 VOL_CAP_FMT_FAST_STATFS
;
1289 vcapattrptr
->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1290 VOL_CAP_INT_SEARCHFS
|
1291 VOL_CAP_INT_ATTRLIST
|
1292 VOL_CAP_INT_NFSEXPORT
|
1293 VOL_CAP_INT_READDIRATTR
|
1294 VOL_CAP_INT_EXCHANGEDATA
|
1295 VOL_CAP_INT_ALLOCATE
|
1296 VOL_CAP_INT_VOL_RENAME
|
1297 VOL_CAP_INT_ADVLOCK
|
1299 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1300 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1302 vcapattrptr
->valid
[VOL_CAPABILITIES_FORMAT
] =
1303 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1304 VOL_CAP_FMT_SYMBOLICLINKS
|
1305 VOL_CAP_FMT_HARDLINKS
|
1306 VOL_CAP_FMT_JOURNAL
|
1307 VOL_CAP_FMT_JOURNAL_ACTIVE
|
1308 VOL_CAP_FMT_NO_ROOT_TIMES
|
1309 VOL_CAP_FMT_SPARSE_FILES
|
1310 VOL_CAP_FMT_ZERO_RUNS
|
1311 VOL_CAP_FMT_CASE_SENSITIVE
|
1312 VOL_CAP_FMT_CASE_PRESERVING
|
1313 VOL_CAP_FMT_FAST_STATFS
;
1314 vcapattrptr
->valid
[VOL_CAPABILITIES_INTERFACES
] =
1315 VOL_CAP_INT_SEARCHFS
|
1316 VOL_CAP_INT_ATTRLIST
|
1317 VOL_CAP_INT_NFSEXPORT
|
1318 VOL_CAP_INT_READDIRATTR
|
1319 VOL_CAP_INT_EXCHANGEDATA
|
1320 VOL_CAP_INT_COPYFILE
|
1321 VOL_CAP_INT_ALLOCATE
|
1322 VOL_CAP_INT_VOL_RENAME
|
1323 VOL_CAP_INT_ADVLOCK
|
1325 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1326 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1328 ++((vol_capabilities_attr_t
*)attrbufptr
);
1330 if (ATTR_VOL_ATTRIBUTES
& attr
) {
1331 vol_attributes_attr_t
*volattrattrp
;
1333 volattrattrp
= (vol_attributes_attr_t
*)attrbufptr
;
1334 volattrattrp
->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1335 volattrattrp
->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
1336 volattrattrp
->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1337 volattrattrp
->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1338 volattrattrp
->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1340 volattrattrp
->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1341 volattrattrp
->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
1342 volattrattrp
->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1343 volattrattrp
->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1344 volattrattrp
->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1345 ++((vol_attributes_attr_t
*)attrbufptr
);
1348 *abp
->ab_attrbufpp
= attrbufptr
;
1349 *abp
->ab_varbufpp
= varbufptr
;
1355 struct attrblock
*abp
,
1356 struct hfsmount
*hfsmp
,
1358 struct cat_desc
* cdp
,
1359 struct cat_attr
* cap
,
1362 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1363 struct mount
*mp
= HFSTOVFS(hfsmp
);
1364 void *attrbufptr
= *abp
->ab_attrbufpp
;
1365 void *varbufptr
= *abp
->ab_varbufpp
;
1366 u_long attrlength
= 0;
1368 if (ATTR_CMN_NAME
& attr
) {
1369 packnameattr(abp
, vp
, cdp
->cd_nameptr
, cdp
->cd_namelen
, p
);
1370 attrbufptr
= *abp
->ab_attrbufpp
;
1371 varbufptr
= *abp
->ab_varbufpp
;
1373 if (ATTR_CMN_DEVID
& attr
) {
1374 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1376 if (ATTR_CMN_FSID
& attr
) {
1377 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1378 ++((fsid_t
*)attrbufptr
);
1380 if (ATTR_CMN_OBJTYPE
& attr
) {
1381 *((fsobj_type_t
*)attrbufptr
)++ = IFTOVT(cap
->ca_mode
);
1383 if (ATTR_CMN_OBJTAG
& attr
) {
1384 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1387 * Exporting file IDs from HFS Plus:
1389 * For "normal" files the c_fileid is the same value as the
1390 * c_cnid. But for hard link files, they are different - the
1391 * c_cnid belongs to the active directory entry (ie the link)
1392 * and the c_fileid is for the actual inode (ie the data file).
1394 * The stat call (getattr) will always return the c_fileid
1395 * and Carbon APIs, which are hardlink-ignorant, will always
1396 * receive the c_cnid (from getattrlist).
1398 if (ATTR_CMN_OBJID
& attr
) {
1399 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1400 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1401 ++((fsobj_id_t
*)attrbufptr
);
1403 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1404 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1405 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1406 ++((fsobj_id_t
*)attrbufptr
);
1408 if (ATTR_CMN_PAROBJID
& attr
) {
1409 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_parentcnid
;
1410 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1411 ++((fsobj_id_t
*)attrbufptr
);
1413 if (ATTR_CMN_SCRIPT
& attr
) {
1414 *((text_encoding_t
*)attrbufptr
)++ = cdp
->cd_encoding
;
1416 if (ATTR_CMN_CRTIME
& attr
) {
1417 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_itime
;
1418 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1419 ++((struct timespec
*)attrbufptr
);
1421 if (ATTR_CMN_MODTIME
& attr
) {
1422 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_mtime
;
1423 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1424 ++((struct timespec
*)attrbufptr
);
1426 if (ATTR_CMN_CHGTIME
& attr
) {
1427 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_ctime
;
1428 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1429 ++((struct timespec
*)attrbufptr
);
1431 if (ATTR_CMN_ACCTIME
& attr
) {
1432 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_atime
;
1433 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1434 ++((struct timespec
*)attrbufptr
);
1436 if (ATTR_CMN_BKUPTIME
& attr
) {
1437 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_btime
;
1438 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1439 ++((struct timespec
*)attrbufptr
);
1441 if (ATTR_CMN_FNDRINFO
& attr
) {
1442 bcopy(&cap
->ca_finderinfo
, attrbufptr
, sizeof(u_int8_t
) * 32);
1443 (char *)attrbufptr
+= sizeof(u_int8_t
) * 32;
1445 if (ATTR_CMN_OWNERID
& attr
) {
1446 *((uid_t
*)attrbufptr
)++ =
1447 (cap
->ca_uid
== UNKNOWNUID
) ? p
->p_ucred
->cr_uid
: cap
->ca_uid
;
1449 if (ATTR_CMN_GRPID
& attr
) {
1450 *((gid_t
*)attrbufptr
)++ = cap
->ca_gid
;
1452 if (ATTR_CMN_ACCESSMASK
& attr
) {
1454 * [2856576] Since we are dynamically changing the owner, also
1455 * effectively turn off the set-user-id and set-group-id bits,
1456 * just like chmod(2) would when changing ownership. This prevents
1457 * a security hole where set-user-id programs run as whoever is
1458 * logged on (or root if nobody is logged in yet!)
1460 *((u_long
*)attrbufptr
)++ =
1461 (cap
->ca_uid
== UNKNOWNUID
) ? cap
->ca_mode
& ~(S_ISUID
| S_ISGID
) : cap
->ca_mode
;
1463 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1464 *((u_long
*)attrbufptr
)++ = 0;
1466 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1468 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1469 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1471 * Advance beyond the space just allocated and
1472 * round up to the next 4-byte boundary:
1474 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1475 ++((struct attrreference
*)attrbufptr
);
1477 if (ATTR_CMN_FLAGS
& attr
) {
1478 *((u_long
*)attrbufptr
)++ = cap
->ca_flags
;
1480 if (ATTR_CMN_USERACCESS
& attr
) {
1481 *((u_long
*)attrbufptr
)++ =
1482 DerivePermissionSummary(cap
->ca_uid
, cap
->ca_gid
,
1483 cap
->ca_mode
, mp
, current_proc()->p_ucred
,
1487 *abp
->ab_attrbufpp
= attrbufptr
;
1488 *abp
->ab_varbufpp
= varbufptr
;
1493 struct attrblock
*abp
,
1494 struct hfsmount
*hfsmp
,
1496 struct cat_desc
* descp
,
1497 struct cat_attr
* cattrp
,
1500 attrgroup_t attr
= abp
->ab_attrlist
->dirattr
;
1501 void *attrbufptr
= *abp
->ab_attrbufpp
;
1503 if (ATTR_DIR_LINKCOUNT
& attr
)
1504 *((u_long
*)attrbufptr
)++ = cattrp
->ca_nlink
;
1505 if (ATTR_DIR_ENTRYCOUNT
& attr
) {
1506 u_long entries
= cattrp
->ca_entries
;
1508 if (descp
->cd_parentcnid
== kRootParID
) {
1509 if (hfsmp
->hfs_privdir_desc
.cd_cnid
!= 0)
1510 --entries
; /* hide private dir */
1512 entries
-= 2; /* hide the journal files */
1515 *((u_long
*)attrbufptr
)++ = entries
;
1517 if (ATTR_DIR_MOUNTSTATUS
& attr
) {
1518 if (vp
!= NULL
&& vp
->v_mountedhere
!= NULL
)
1519 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
1521 *((u_long
*)attrbufptr
)++ = 0;
1523 *abp
->ab_attrbufpp
= attrbufptr
;
1528 struct attrblock
*abp
,
1529 struct hfsmount
*hfsmp
,
1530 struct cat_attr
*cattrp
,
1531 struct cat_fork
*datafork
,
1532 struct cat_fork
*rsrcfork
,
1535 attrgroup_t attr
= abp
->ab_attrlist
->fileattr
;
1536 void *attrbufptr
= *abp
->ab_attrbufpp
;
1537 void *varbufptr
= *abp
->ab_varbufpp
;
1539 u_long allocblksize
;
1541 allocblksize
= HFSTOVCB(hfsmp
)->blockSize
;
1543 if (ATTR_FILE_LINKCOUNT
& attr
) {
1544 *((u_long
*)attrbufptr
)++ = cattrp
->ca_nlink
;
1546 if (ATTR_FILE_TOTALSIZE
& attr
) {
1547 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
+ rsrcfork
->cf_size
;
1549 if (ATTR_FILE_ALLOCSIZE
& attr
) {
1550 *((off_t
*)attrbufptr
)++ =
1551 (off_t
)cattrp
->ca_blocks
* (off_t
)allocblksize
;
1553 if (ATTR_FILE_IOBLOCKSIZE
& attr
) {
1554 *((u_long
*)attrbufptr
)++ = hfsmp
->hfs_logBlockSize
;
1556 if (ATTR_FILE_CLUMPSIZE
& attr
) {
1557 *((u_long
*)attrbufptr
)++ = HFSTOVCB(hfsmp
)->vcbClpSiz
;
1559 if (ATTR_FILE_DEVTYPE
& attr
) {
1560 if (S_ISBLK(cattrp
->ca_mode
) || S_ISCHR(cattrp
->ca_mode
))
1561 *((u_long
*)attrbufptr
)++ = (u_long
)cattrp
->ca_rdev
;
1563 *((u_long
*)attrbufptr
)++ = 0;
1565 if (ATTR_FILE_FILETYPE
& attr
) {
1566 *((u_long
*)attrbufptr
)++ = 0;
1568 if (ATTR_FILE_FORKCOUNT
& attr
) {
1569 *((u_long
*)attrbufptr
)++ = 2;
1571 if (ATTR_FILE_FORKLIST
& attr
) {
1573 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1574 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1576 * Advance beyond the space just allocated and
1577 * round up to the next 4-byte boundary:
1579 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1580 ++((struct attrreference
*)attrbufptr
);
1582 if (ATTR_FILE_DATALENGTH
& attr
) {
1583 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
;
1585 if (ATTR_FILE_DATAALLOCSIZE
& attr
) {
1586 *((off_t
*)attrbufptr
)++ =
1587 (off_t
)datafork
->cf_blocks
* (off_t
)allocblksize
;
1589 if (ATTR_FILE_DATAEXTENTS
& attr
) {
1590 bcopy(&datafork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1591 (char *)attrbufptr
+= sizeof(extentrecord
);
1593 if (ATTR_FILE_RSRCLENGTH
& attr
) {
1594 *((off_t
*)attrbufptr
)++ = rsrcfork
->cf_size
;
1596 if (ATTR_FILE_RSRCALLOCSIZE
& attr
) {
1597 *((off_t
*)attrbufptr
)++ =
1598 (off_t
)rsrcfork
->cf_blocks
* (off_t
)allocblksize
;
1600 if (ATTR_FILE_RSRCEXTENTS
& attr
) {
1601 bcopy(&rsrcfork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1602 (char *)attrbufptr
+= sizeof(extentrecord
);
1604 *abp
->ab_attrbufpp
= attrbufptr
;
1605 *abp
->ab_varbufpp
= varbufptr
;
1610 unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
)
1612 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
1614 if (attrlistp
->volattr
)
1615 unpackvolattr(abp
, VTOHFS(vp
), vp
);
1616 else if (attrlistp
->commonattr
)
1617 unpackcommonattr(abp
, vp
);
1623 struct attrblock
*abp
,
1626 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1627 void *attrbufptr
= *abp
->ab_attrbufpp
;
1628 struct cnode
*cp
= VTOC(vp
);
1630 if (ATTR_CMN_SCRIPT
& attr
) {
1631 cp
->c_encoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
1632 hfs_setencodingbits(VTOHFS(vp
), cp
->c_encoding
);
1634 if (ATTR_CMN_CRTIME
& attr
) {
1635 cp
->c_itime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1636 ++((struct timespec
*)attrbufptr
);
1638 if (ATTR_CMN_MODTIME
& attr
) {
1639 cp
->c_mtime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1640 cp
->c_mtime_nsec
= ((struct timespec
*)attrbufptr
)->tv_nsec
;
1641 ++((struct timespec
*)attrbufptr
);
1642 cp
->c_flag
&= ~C_UPDATE
;
1644 if (ATTR_CMN_CHGTIME
& attr
) {
1645 cp
->c_ctime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1646 ++((struct timespec
*)attrbufptr
);
1647 cp
->c_flag
&= ~C_CHANGE
;
1649 if (ATTR_CMN_ACCTIME
& attr
) {
1650 cp
->c_atime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1651 ++((struct timespec
*)attrbufptr
);
1652 cp
->c_flag
&= ~C_ACCESS
;
1654 if (ATTR_CMN_BKUPTIME
& attr
) {
1655 cp
->c_btime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1656 ++((struct timespec
*)attrbufptr
);
1658 if (ATTR_CMN_FNDRINFO
& attr
) {
1659 bcopy(attrbufptr
, &cp
->c_attr
.ca_finderinfo
,
1660 sizeof(cp
->c_attr
.ca_finderinfo
));
1661 (char *)attrbufptr
+= sizeof(cp
->c_attr
.ca_finderinfo
);
1663 if (ATTR_CMN_OWNERID
& attr
) {
1664 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1665 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
1666 if (uid
!= (uid_t
)VNOVAL
)
1669 ((uid_t
*)attrbufptr
)++;
1672 if (ATTR_CMN_GRPID
& attr
) {
1673 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
1674 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1675 if (gid
!= (gid_t
)VNOVAL
)
1679 if (ATTR_CMN_ACCESSMASK
& attr
) {
1680 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
1681 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1682 if (mode
!= (mode_t
)VNOVAL
) {
1683 cp
->c_mode
&= ~ALLPERMS
;
1684 cp
->c_mode
|= (mode
& ALLPERMS
);
1688 if (ATTR_CMN_FLAGS
& attr
) {
1689 u_long flags
= *((u_long
*)attrbufptr
)++;
1691 * Flags are settable only on HFS+ volumes. A special
1692 * exception is made for the IMMUTABLE flags
1693 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1694 * HFS volumes as well:
1696 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
1697 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) &&
1698 ((flags
& ~IMMUTABLE
) == 0))) {
1699 if (flags
!= (u_long
)VNOVAL
) {
1700 cp
->c_flags
= flags
;
1704 *abp
->ab_attrbufpp
= attrbufptr
;
1710 struct attrblock
*abp
,
1711 struct hfsmount
*hfsmp
,
1712 struct vnode
*rootvp
)
1714 void *attrbufptr
= *abp
->ab_attrbufpp
;
1715 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1718 attr
= abp
->ab_attrlist
->commonattr
;
1722 if (ATTR_CMN_SCRIPT
& attr
) {
1723 vcb
->volumeNameEncodingHint
=
1724 (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
1726 if (ATTR_CMN_CRTIME
& attr
) {
1727 vcb
->vcbCrDate
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1728 ++((struct timespec
*)attrbufptr
);
1730 /* The volume's create date comes from the root directory */
1731 VTOC(rootvp
)->c_itime
= vcb
->vcbCrDate
;
1732 VTOC(rootvp
)->c_flag
|= C_MODIFIED
;
1734 * XXX Should we also do a relative change to the
1735 * the volume header's create date in local time?
1738 if (ATTR_CMN_MODTIME
& attr
) {
1739 vcb
->vcbLsMod
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1740 ++((struct timespec
*)attrbufptr
);
1742 if (ATTR_CMN_BKUPTIME
& attr
) {
1743 vcb
->vcbVolBkUp
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1744 ++((struct timespec
*)attrbufptr
);
1746 if (ATTR_CMN_FNDRINFO
& attr
) {
1747 bcopy(attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
1748 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1752 attr
= abp
->ab_attrlist
->volattr
& ~ATTR_VOL_INFO
;
1754 * XXX - no validation is done on the name!
1755 * It could be empty or garbage (bad UTF-8).
1757 if (ATTR_VOL_NAME
& attr
) {
1758 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
),
1759 vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
1760 (char *)attrbufptr
+= sizeof(struct attrreference
);
1762 *abp
->ab_attrbufpp
= attrbufptr
;
1764 vcb
->vcbFlags
|= 0xFF00;
1768 * Calculate the total size of an attribute block.
1772 hfs_attrblksize(struct attrlist
*attrlist
)
1777 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1778 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \
1779 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \
1780 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \
1781 ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1782 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \
1783 ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \
1784 != ATTR_CMN_VALIDMASK)
1785 #error hfs_attrblksize: Missing bits in common mask computation!
1787 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1789 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \
1790 ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
1791 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1792 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \
1793 ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \
1794 ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \
1795 ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1796 != ATTR_VOL_VALIDMASK)
1797 #error hfs_attrblksize: Missing bits in volume mask computation!
1799 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1801 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \
1802 != ATTR_DIR_VALIDMASK)
1803 #error hfs_attrblksize: Missing bits in directory mask computation!
1805 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1807 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
1808 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \
1809 ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \
1810 ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1811 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \
1812 != ATTR_FILE_VALIDMASK)
1813 #error hfs_attrblksize: Missing bits in file mask computation!
1815 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1817 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1818 #error hfs_attrblksize: Missing bits in fork mask computation!
1820 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1824 if ((a
= attrlist
->commonattr
) != 0) {
1825 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1826 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1827 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1828 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1829 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1830 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1831 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1832 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1833 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1834 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1835 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1836 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1837 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1838 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1839 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(u_int8_t
);
1840 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1841 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1842 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1843 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1844 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1845 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1846 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1848 if ((a
= attrlist
->volattr
) != 0) {
1849 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1850 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1851 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1852 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1853 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1854 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1855 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1856 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1857 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1858 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1859 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1860 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1861 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1862 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1863 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1864 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1865 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1866 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1867 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1869 if ((a
= attrlist
->dirattr
) != 0) {
1870 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1871 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1872 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1874 if ((a
= attrlist
->fileattr
) != 0) {
1875 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1876 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1877 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1878 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1879 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1880 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1881 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1882 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1883 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1884 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1885 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1886 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1887 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1888 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1889 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1891 if ((a
= attrlist
->forkattr
) != 0) {
1892 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1893 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1902 DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
,
1903 struct mount
*mp
, struct ucred
*cred
, struct proc
*p
)
1906 unsigned long permissions
;
1909 if (obj_uid
== UNKNOWNUID
)
1910 obj_uid
= p
->p_ucred
->cr_uid
;
1912 /* User id 0 (root) always gets access. */
1913 if (cred
->cr_uid
== 0) {
1914 permissions
= R_OK
| W_OK
| X_OK
;
1918 /* Otherwise, check the owner. */
1919 if (hfs_owner_rights(VFSTOHFS(mp
), obj_uid
, cred
, p
, false) == 0) {
1920 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1924 /* Otherwise, check the groups. */
1925 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1926 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1927 if (obj_gid
== *gp
) {
1928 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1934 /* Otherwise, settle for 'others' access. */
1935 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1938 return (permissions
);