2 * Copyright (c) 2000-2003 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 /* Routines that are shared by hfs_setattr: */
46 extern int hfs_write_access(struct vnode
*vp
, struct ucred
*cred
,
47 struct proc
*p
, Boolean considerFlags
);
49 extern int hfs_chflags(struct vnode
*vp
, u_long flags
, struct ucred
*cred
,
52 extern int hfs_chmod(struct vnode
*vp
, int mode
, struct ucred
*cred
,
55 extern int hfs_chown(struct vnode
*vp
, uid_t uid
, gid_t gid
, struct ucred
*cred
,
58 extern char * hfs_getnamehint(struct cnode
*dcp
, int index
);
60 extern void hfs_savenamehint(struct cnode
*dcp
, int index
, const char * namehint
);
62 extern void hfs_relnamehint(struct cnode
*dcp
, int index
);
64 /* Packing routines: */
67 static void packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
68 struct vnode
*vp
, struct proc
*p
);
70 static void packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
71 struct vnode
*vp
, struct proc
*p
);
73 static void packcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
74 struct vnode
*vp
, struct cat_desc
* cdp
,
75 struct cat_attr
* cap
, struct proc
*p
);
77 static void packfileattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
78 struct cat_attr
*cattrp
, struct cat_fork
*datafork
,
79 struct cat_fork
*rsrcfork
, struct proc
*p
);
81 static void packdirattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
82 struct vnode
*vp
, struct cat_desc
* descp
,
83 struct cat_attr
* cattrp
, struct proc
*p
);
85 static void unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
);
87 static void unpackcommonattr(struct attrblock
*abp
, struct vnode
*vp
);
89 static void unpackvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
,
90 struct vnode
*rootvp
);
96 #% getattrlist vp = = =
100 IN struct attrlist *alist;
101 INOUT struct uio *uio;
102 IN struct ucred *cred;
110 struct vop_getattrlist_args
/* {
112 struct attrlist *a_alist
114 struct ucred *a_cred;
118 struct vnode
*vp
= ap
->a_vp
;
119 struct cnode
*cp
= VTOC(vp
);
120 struct hfsmount
*hfsmp
= VTOHFS(vp
);
121 struct attrlist
*alist
= ap
->a_alist
;
129 struct attrblock attrblk
;
130 struct cat_fork
*datafp
= NULL
;
131 struct cat_fork
*rsrcfp
= NULL
;
132 struct cat_fork rsrcfork
= {0};
135 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
136 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
137 ((alist
->volattr
& ~ATTR_VOL_VALIDMASK
) != 0) ||
138 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
139 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0)) {
144 * Requesting volume information requires setting the
145 * ATTR_VOL_INFO bit. Also, volume info requests are
146 * mutually exclusive with all other info requests.
148 if ((alist
->volattr
!= 0) &&
149 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
150 (alist
->dirattr
!= 0) || (alist
->fileattr
!= 0))) {
154 /* Reject requests for unsupported options for now: */
155 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
)) ||
156 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
| ATTR_FILE_FORKLIST
))) {
160 /* Requesting volume information requires root vnode */
161 if ((alist
->volattr
) && cp
->c_fileid
!= kRootDirID
)
164 /* Asking for data fork attributes from the rsrc fork is not supported */
165 if (VNODE_IS_RSRC(vp
) && (alist
->fileattr
& ATTR_DATAFORK_MASK
))
168 /* This file no longer exists! */
169 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
172 /* This file doesn't have a name! */
173 if ((cp
->c_desc
.cd_namelen
== 0) && (alist
->commonattr
& ATTR_CMN_NAME
))
176 /* Update cnode times if needed */
178 CTIMES(cp
, &tv
, &tv
);
181 * If a File ID (ATTR_CMN_OBJPERMANENTID) is requested on
182 * an HFS volume we must be sure to create the thread
183 * record before returning it. (yikes)
185 if ((vp
->v_type
== VREG
) &&
186 (alist
->commonattr
& ATTR_CMN_OBJPERMANENTID
) &&
187 (VTOVCB(vp
)->vcbSigWord
!= kHFSPlusSigWord
)) {
189 cat_cookie_t cookie
= {0};
191 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
)
193 if ((error
= hfs_write_access(vp
, ap
->a_cred
, ap
->a_p
, false)) != 0)
197 * Reserve some space in the Catalog file.
199 error
= cat_preflight(hfsmp
, CAT_CREATE
, &cookie
, ap
->a_p
);
203 /* Lock catalog b-tree */
204 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
,
205 LK_EXCLUSIVE
, ap
->a_p
);
207 cat_postflight(hfsmp
, &cookie
, ap
->a_p
);
211 error
= cat_insertfilethread(hfsmp
, &cp
->c_desc
);
213 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
,
216 cat_postflight(hfsmp
, &cookie
, ap
->a_p
);
222 /* Establish known fork data */
223 if (cp
->c_datafork
!= NULL
) {
224 datafp
= &cp
->c_datafork
->ff_data
;
225 if ((cp
->c_rsrcfork
== NULL
) &&
226 (cp
->c_blocks
== datafp
->cf_blocks
))
227 rsrcfp
= &rsrcfork
; /* rsrc fork is empty */
229 if (cp
->c_rsrcfork
!= NULL
)
230 rsrcfp
= &cp
->c_rsrcfork
->ff_data
;
233 * When resource fork data is requested and its not available
234 * in the cnode and the fork is not empty then it needs to be
235 * fetched from the catalog.
237 if ((alist
->fileattr
& ATTR_RSRCFORK_MASK
) && (rsrcfp
== NULL
)) {
238 /* Lock catalog b-tree */
239 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, ap
->a_p
);
243 /* Get resource fork data */
244 error
= cat_lookup(hfsmp
, &cp
->c_desc
, 1,
245 (struct cat_desc
*)0, (struct cat_attr
*)0, &rsrcfork
);
247 /* Unlock the Catalog */
248 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, ap
->a_p
);
255 fixedblocksize
= hfs_attrblksize(alist
);
256 attrblocksize
= fixedblocksize
+ (sizeof(u_long
)); /* u_long for length longword */
257 if (alist
->commonattr
& ATTR_CMN_NAME
)
258 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
259 if (alist
->volattr
& ATTR_VOL_MOUNTPOINT
)
260 attrblocksize
+= PATH_MAX
;
261 if (alist
->volattr
& ATTR_VOL_NAME
)
262 attrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
264 if (alist
->commonattr
& ATTR_CMN_NAMEDATTRLIST
)
266 if (alist
->fileattr
& ATTR_FILE_FORKLIST
)
269 attrbufsize
= MIN(ap
->a_uio
->uio_resid
, attrblocksize
);
270 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
271 attrptr
= attrbufptr
;
272 *((u_long
*)attrptr
) = 0; /* Set buffer length in case of errors */
273 ++((u_long
*)attrptr
); /* Reserve space for length field */
274 varptr
= ((char *)attrptr
) + fixedblocksize
;
276 attrblk
.ab_attrlist
= alist
;
277 attrblk
.ab_attrbufpp
= &attrptr
;
278 attrblk
.ab_varbufpp
= &varptr
;
279 attrblk
.ab_flags
= 0;
280 attrblk
.ab_blocksize
= attrblocksize
;
282 hfs_packattrblk(&attrblk
, hfsmp
, vp
, &cp
->c_desc
, &cp
->c_attr
,
283 datafp
, rsrcfp
, ap
->a_p
);
285 /* Don't copy out more data than was generated */
286 attrbufsize
= MIN(attrbufsize
, (u_int
)varptr
- (u_int
)attrbufptr
);
287 /* Set actual buffer length for return to caller */
288 *((u_long
*)attrbufptr
) = attrbufsize
;
289 error
= uiomove((caddr_t
)attrbufptr
, attrbufsize
, ap
->a_uio
);
291 FREE(attrbufptr
, M_TEMP
);
299 #% setattrlist vp L L L
303 IN struct attrlist *alist;
304 INOUT struct uio *uio;
305 IN struct ucred *cred;
313 struct vop_setattrlist_args
/* {
315 struct attrlist *a_alist
317 struct ucred *a_cred;
321 struct vnode
*vp
= ap
->a_vp
;
322 struct cnode
*cp
= VTOC(vp
);
323 struct hfsmount
* hfsmp
= VTOHFS(vp
);
324 struct attrlist
*alist
= ap
->a_alist
;
325 struct ucred
*cred
= ap
->a_cred
;
326 struct proc
*p
= ap
->a_p
;
328 void *attrbufptr
= NULL
;
331 struct attrblock attrblk
;
338 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
)
340 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
341 ((alist
->commonattr
& ~ATTR_CMN_SETMASK
) != 0) ||
342 ((alist
->volattr
& ~ATTR_VOL_SETMASK
) != 0) ||
343 ((alist
->dirattr
& ~ATTR_DIR_SETMASK
) != 0) ||
344 ((alist
->fileattr
& ~ATTR_FILE_SETMASK
) != 0)) {
348 * When setting volume attributes make sure
349 * that ATTR_VOL_INFO is set and that all
350 * the attributes are valid.
352 if ((alist
->volattr
!= 0) &&
353 (((alist
->volattr
& ATTR_VOL_INFO
) == 0) ||
354 (alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
) ||
355 (cp
->c_fileid
!= kRootDirID
))) {
356 if ((alist
->volattr
& ATTR_VOL_INFO
) == 0)
357 printf("hfs_setattrlist: you forgot to set ATTR_VOL_INFO bit!\n");
359 printf("hfs_setattrlist: you cannot set bits 0x%08X!\n",
360 alist
->commonattr
& ~ATTR_CMN_VOLSETMASK
);
363 if (cp
->c_flag
& (C_NOEXISTS
| C_DELETED
))
366 // XXXdbg - don't allow modifying the journal or journal_info_block
367 if (hfsmp
->jnl
&& cp
->c_datafork
) {
368 struct HFSPlusExtentDescriptor
*extd
;
370 extd
= &cp
->c_datafork
->ff_extents
[0];
371 if (extd
->startBlock
== HFSTOVCB(hfsmp
)->vcbJinfoBlock
|| extd
->startBlock
== hfsmp
->jnl_start
) {
377 * Ownership of a file is required in one of two classes of calls:
379 * (a) When setting any ownership-requiring attribute other
380 * than ATTR_CMN_FLAGS, or
381 * (b) When setting ATTR_CMN_FLAGS on a volume that's not
382 * plain HFS (for which no real per-object ownership
383 * information is stored)
385 if ((alist
->commonattr
& (ATTR_OWNERSHIP_SETMASK
& ~ATTR_CMN_FLAGS
)) ||
386 ((alist
->commonattr
& ATTR_CMN_FLAGS
) &&
387 (VTOVCB(vp
)->vcbSigWord
!= kHFSSigWord
))) {
389 * NOTE: The following isn't ENTIRELY complete: even if
390 * you're the superuser you cannot change the flags as
391 * long as SF_IMMUTABLE or SF_APPEND is set and the
392 * securelevel > 0. This is verified in hfs_chflags
393 * which gets invoked to do the actual flags field
394 * change so this check is sufficient for now.
396 if ((error
= hfs_owner_rights(hfsmp
, cp
->c_uid
, cred
, p
, true)) != 0)
400 * For any other attributes, check to see if the user has
401 * write access to the cnode in question [unlike VOP_ACCESS,
402 * ignore IMMUTABLE here]:
404 if (((alist
->commonattr
& ~ATTR_OWNERSHIP_SETMASK
) != 0) ||
405 (alist
->volattr
!= 0) || (alist
->dirattr
!= 0) ||
406 (alist
->fileattr
!= 0)) {
407 if ((error
= hfs_write_access(vp
, cred
, p
, false)) != 0)
412 * Allocate the buffer now to minimize the time we might
413 * be blocked holding the catalog lock.
415 attrblocksize
= ap
->a_uio
->uio_resid
;
416 if (attrblocksize
< hfs_attrblksize(alist
))
419 MALLOC(attrbufptr
, void *, attrblocksize
, M_TEMP
, M_WAITOK
);
421 error
= uiomove((caddr_t
)attrbufptr
, attrblocksize
, ap
->a_uio
);
425 /* Save original state so changes can be detected. */
426 saved_uid
= cp
->c_uid
;
427 saved_gid
= cp
->c_gid
;
428 saved_mode
= cp
->c_mode
;
429 saved_flags
= cp
->c_flags
;
431 attrptr
= attrbufptr
;
432 attrblk
.ab_attrlist
= alist
;
433 attrblk
.ab_attrbufpp
= &attrptr
;
434 attrblk
.ab_varbufpp
= &varptr
;
435 attrblk
.ab_flags
= 0;
436 attrblk
.ab_blocksize
= attrblocksize
;
437 unpackattrblk(&attrblk
, vp
);
439 /* If unpacking changed the owner/group then call hfs_chown() */
440 if ((saved_uid
!= cp
->c_uid
) || (saved_gid
!= cp
->c_gid
)) {
445 cp
->c_uid
= saved_uid
;
447 cp
->c_gid
= saved_gid
;
448 if ((error
= hfs_chown(vp
, uid
, gid
, cred
, p
)))
451 /* If unpacking changed the mode then call hfs_chmod() */
452 if (saved_mode
!= cp
->c_mode
) {
456 cp
->c_mode
= saved_mode
;
457 if ((error
= hfs_chmod(vp
, mode
, cred
, p
)))
460 /* If unpacking changed the flags then call hfs_chflags() */
461 if (saved_flags
!=cp
->c_flags
) {
465 cp
->c_flags
= saved_flags
;
466 if ((error
= hfs_chflags(vp
, flags
, cred
, p
)))
470 * If any cnode attributes changed then do an update.
472 if (alist
->volattr
== 0) {
475 cp
->c_flag
|= C_MODIFIED
;
477 CTIMES(cp
, &tv
, &tv
);
478 if ((error
= VOP_UPDATE(vp
, &tv
, &tv
, 1)))
482 if (alist
->volattr
& ATTR_VOL_NAME
) {
483 ExtendedVCB
*vcb
= VTOVCB(vp
);
485 if (vcb
->vcbVN
[0] == 0) {
487 * Ignore attempts to rename a volume to a zero-length name:
488 * restore the original name from the cnode.
490 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
492 struct cat_desc to_desc
= {0};
493 struct cat_desc todir_desc
= {0};
494 struct cat_desc new_desc
= {0};
495 cat_cookie_t cookie
= {0};
500 todir_desc
.cd_parentcnid
= kRootParID
;
501 todir_desc
.cd_cnid
= kRootParID
;
502 todir_desc
.cd_flags
= CD_ISDIR
;
504 to_desc
.cd_nameptr
= vcb
->vcbVN
;
505 to_desc
.cd_namelen
= strlen(vcb
->vcbVN
);
506 to_desc
.cd_parentcnid
= kRootParID
;
507 to_desc
.cd_cnid
= cp
->c_cnid
;
508 to_desc
.cd_flags
= CD_ISDIR
;
511 hfs_global_shared_lock_acquire(hfsmp
);
513 if ((error
= journal_start_transaction(hfsmp
->jnl
) != 0)) {
520 * Reserve some space in the Catalog file.
522 error
= cat_preflight(hfsmp
, CAT_RENAME
, &cookie
, p
);
528 /* Lock catalog b-tree */
529 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
535 error
= cat_rename(hfsmp
, &cp
->c_desc
, &todir_desc
, &to_desc
, &new_desc
);
538 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
541 cat_postflight(hfsmp
, &cookie
, p
);
544 journal_end_transaction(hfsmp
->jnl
);
546 hfs_global_shared_lock_release(hfsmp
);
549 /* Restore the old name in the VCB */
550 copystr(cp
->c_desc
.cd_nameptr
, vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
551 vcb
->vcbFlags
|= 0xFF00;
554 /* Release old allocated name buffer */
555 if (cp
->c_desc
.cd_flags
& CD_HASBUF
) {
556 char *name
= cp
->c_desc
.cd_nameptr
;
558 cp
->c_desc
.cd_nameptr
= 0;
559 cp
->c_desc
.cd_namelen
= 0;
560 cp
->c_desc
.cd_flags
&= ~CD_HASBUF
;
563 /* Update cnode's catalog descriptor */
564 replace_desc(cp
, &new_desc
);
565 vcb
->volumeNameEncodingHint
= new_desc
.cd_encoding
;
566 cp
->c_flag
|= C_CHANGE
;
571 * When the volume name changes or the volume's finder info
572 * changes then force them to disk immediately.
574 if ((alist
->volattr
& ATTR_VOL_INFO
) &&
575 ((alist
->volattr
& ATTR_VOL_NAME
) ||
576 (alist
->commonattr
& ATTR_CMN_FNDRINFO
))) {
577 (void) hfs_flushvolumeheader(hfsmp
, MNT_WAIT
, 0);
581 FREE(attrbufptr
, M_TEMP
);
588 * readdirattr operation will return attributes for the items in the
589 * directory specified.
591 * It does not do . and .. entries. The problem is if you are at the root of the
592 * hfs directory and go to .. you could be crossing a mountpoint into a
593 * different (ufs) file system. The attributes that apply for it may not
594 * apply for the file system you are doing the readdirattr on. To make life
595 * simpler, this call will only return entries in its directory, hfs like.
597 * 1. more than one for uiovcnt support.
598 * 2. put knohint (hints) in state for next call in
599 * 3. credentials checking when rest of hfs does it.
600 * 4. Do return permissions concatenation ???
605 #% readdirattr vp L L L
609 IN struct attrlist *alist;
610 INOUT struct uio *uio;
613 OUT u_long *newstate;
615 OUT u_long *actualCount;
616 OUT u_long **cookies;
617 IN struct ucred *cred;
623 struct vop_readdirattr_args
/* {
625 struct attrlist *a_alist;
631 u_long *a_actualcount;
633 struct ucred *a_cred;
636 struct vnode
*dvp
= ap
->a_vp
;
637 struct cnode
*dcp
= VTOC(dvp
);
638 struct hfsmount
* hfsmp
= VTOHFS(dvp
);
639 struct attrlist
*alist
= ap
->a_alist
;
640 struct uio
*uio
= ap
->a_uio
;
641 int maxcount
= ap
->a_maxcount
;
642 struct proc
*p
= current_proc();
643 u_long fixedblocksize
;
644 u_long maxattrblocksize
;
645 u_long currattrbufsize
;
646 void *attrbufptr
= NULL
;
649 struct attrblock attrblk
;
652 int index
, startindex
;
654 struct cat_desc
*lastdescp
= NULL
;
655 struct cat_desc prevdesc
;
656 char * prevnamebuf
= NULL
;
657 struct cat_entrylist
*ce_list
= NULL
;
659 dir_entries
= dcp
->c_entries
;
660 if (dcp
->c_attr
.ca_fileid
== kHFSRootFolderID
&& hfsmp
->jnl
) {
664 *(ap
->a_actualcount
) = 0;
665 *(ap
->a_eofflag
) = 0;
667 if (ap
->a_cookies
!= NULL
) {
668 printf("readdirattr: no cookies!\n");
672 /* Check for invalid options and buffer space. */
673 if (((ap
->a_options
& ~(FSOPT_NOINMEMUPDATE
| FSOPT_NOFOLLOW
)) != 0)
674 || (uio
->uio_resid
<= 0) || (uio
->uio_iovcnt
> 1) || (maxcount
<= 0))
677 /* This call doesn't take volume attributes. */
678 if ((alist
->bitmapcount
!= ATTR_BIT_MAP_COUNT
) ||
679 ((alist
->commonattr
& ~ATTR_CMN_VALIDMASK
) != 0) ||
680 (alist
->volattr
!= 0) ||
681 ((alist
->dirattr
& ~ATTR_DIR_VALIDMASK
) != 0) ||
682 ((alist
->fileattr
& ~ATTR_FILE_VALIDMASK
) != 0))
685 /* Reject requests for unsupported options. */
686 if ((alist
->commonattr
& (ATTR_CMN_NAMEDATTRCOUNT
| ATTR_CMN_NAMEDATTRLIST
|
687 ATTR_CMN_OBJPERMANENTID
)) ||
688 (alist
->fileattr
& (ATTR_FILE_FILETYPE
| ATTR_FILE_FORKCOUNT
|
689 ATTR_FILE_FORKLIST
| ATTR_FILE_DATAEXTENTS
| ATTR_FILE_RSRCEXTENTS
))) {
690 printf("readdirattr: unsupported attributes! (%s)\n", dcp
->c_desc
.cd_nameptr
);
694 /* Convert uio_offset into a directory index. */
695 startindex
= index
= uio
->uio_offset
/ sizeof(struct dirent
);
696 if ((index
+ 1) > dir_entries
) {
697 *(ap
->a_eofflag
) = 1;
702 /* Get a buffer to hold packed attributes. */
703 fixedblocksize
= (sizeof(u_long
) + hfs_attrblksize(alist
)); /* u_long for length */
704 maxattrblocksize
= fixedblocksize
;
705 if (alist
->commonattr
& ATTR_CMN_NAME
)
706 maxattrblocksize
+= kHFSPlusMaxFileNameBytes
+ 1;
707 MALLOC(attrbufptr
, void *, maxattrblocksize
, M_TEMP
, M_WAITOK
);
708 attrptr
= attrbufptr
;
709 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
711 /* Initialize a catalog entry list. */
712 MALLOC(ce_list
, struct cat_entrylist
*, sizeof(*ce_list
), M_TEMP
, M_WAITOK
);
713 bzero(ce_list
, sizeof(*ce_list
));
714 ce_list
->maxentries
= MAXCATENTRIES
;
716 /* Initialize a starting descriptor. */
717 bzero(&prevdesc
, sizeof(prevdesc
));
718 prevdesc
.cd_flags
= CD_DECOMPOSED
;
719 prevdesc
.cd_hint
= dcp
->c_childhint
;
720 prevdesc
.cd_parentcnid
= dcp
->c_cnid
;
721 prevdesc
.cd_nameptr
= hfs_getnamehint(dcp
, index
);
722 prevdesc
.cd_namelen
= prevdesc
.cd_nameptr
? strlen(prevdesc
.cd_nameptr
) : 0;
725 * Obtain a list of catalog entries and pack their attributes until
726 * the output buffer is full or maxcount entries have been packed.
731 /* Constrain our list size. */
732 maxentries
= uio
->uio_resid
/ (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
);
733 maxentries
= min(maxentries
, dcp
->c_entries
- index
);
734 maxentries
= min(maxentries
, maxcount
);
735 ce_list
->maxentries
= min(maxentries
, ce_list
->maxentries
);
738 /* Lock catalog b-tree. */
739 error
= hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_SHARED
, p
);
743 error
= cat_getentriesattr(hfsmp
, &prevdesc
, index
, ce_list
);
744 /* Don't forget to release the descriptors later! */
746 /* Unlock catalog b-tree. */
747 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_RELEASE
, p
);
749 if (error
== ENOENT
) {
750 *(ap
->a_eofflag
) = TRUE
;
757 /* Process the catalog entries. */
758 for (i
= 0; i
< ce_list
->realentries
; ++i
) {
759 struct cnode
*cp
= NULL
;
760 struct vnode
*vp
= NULL
;
761 struct vnode
*rvp
= NULL
;
762 struct cat_desc
* cdescp
;
763 struct cat_attr
* cattrp
;
764 struct cat_fork c_datafork
= {0};
765 struct cat_fork c_rsrcfork
= {0};
767 cdescp
= &ce_list
->entry
[i
].ce_desc
;
768 cattrp
= &ce_list
->entry
[i
].ce_attr
;
769 c_datafork
.cf_size
= ce_list
->entry
[i
].ce_datasize
;
770 c_datafork
.cf_blocks
= ce_list
->entry
[i
].ce_datablks
;
771 c_rsrcfork
.cf_size
= ce_list
->entry
[i
].ce_rsrcsize
;
772 c_rsrcfork
.cf_blocks
= ce_list
->entry
[i
].ce_rsrcblks
;
774 * Get in memory cnode data (if any).
776 if (!(ap
->a_options
& FSOPT_NOINMEMUPDATE
)) {
777 cp
= hfs_chashget(dcp
->c_dev
, cattrp
->ca_fileid
, 0, &vp
, &rvp
);
779 /* Only use cnode's decriptor for non-hardlinks */
780 if (!(cp
->c_flag
& C_HARDLINK
))
781 cdescp
= &cp
->c_desc
;
782 cattrp
= &cp
->c_attr
;
783 if (cp
->c_datafork
) {
784 c_datafork
.cf_size
= cp
->c_datafork
->ff_size
;
785 c_datafork
.cf_blocks
= cp
->c_datafork
->ff_blocks
;
787 if (cp
->c_rsrcfork
) {
788 c_rsrcfork
.cf_size
= cp
->c_rsrcfork
->ff_size
;
789 c_rsrcfork
.cf_blocks
= cp
->c_rsrcfork
->ff_blocks
;
793 *((u_long
*)attrptr
)++ = 0; /* move it past length */
794 attrblk
.ab_attrlist
= alist
;
795 attrblk
.ab_attrbufpp
= &attrptr
;
796 attrblk
.ab_varbufpp
= &varptr
;
797 attrblk
.ab_flags
= 0;
798 attrblk
.ab_blocksize
= maxattrblocksize
;
800 /* Pack catalog entries into attribute buffer. */
801 hfs_packattrblk(&attrblk
, hfsmp
, vp
, cdescp
, cattrp
,
802 &c_datafork
, &c_rsrcfork
, p
);
803 currattrbufsize
= ((char *)varptr
- (char *)attrbufptr
);
805 /* All done with cnode. */
815 /* Make sure there's enough buffer space remaining. */
816 if (currattrbufsize
> uio
->uio_resid
) {
820 *((u_long
*)attrbufptr
) = currattrbufsize
;
821 error
= uiomove((caddr_t
)attrbufptr
, currattrbufsize
, ap
->a_uio
);
822 if (error
!= E_NONE
) {
826 attrptr
= attrbufptr
;
827 varptr
= (char *)attrbufptr
+ fixedblocksize
; /* Point to variable-length storage */
828 /* Save the last valid catalog entry */
829 lastdescp
= &ce_list
->entry
[i
].ce_desc
;
831 *ap
->a_actualcount
+= 1;
833 /* Termination checks */
834 if ((--maxcount
<= 0) ||
835 (uio
->uio_resid
< (fixedblocksize
+ HFS_AVERAGE_NAME_SIZE
)) ||
836 (index
>= dir_entries
)) {
841 } /* for each catalog entry */
843 /* If there are more entries then save the last name. */
844 if (index
< dir_entries
845 && !(*(ap
->a_eofflag
))
846 && lastdescp
!= NULL
) {
847 if (prevnamebuf
== NULL
)
848 MALLOC(prevnamebuf
, char *, kHFSPlusMaxFileNameBytes
+ 1, M_TEMP
, M_WAITOK
);
849 bcopy(lastdescp
->cd_nameptr
, prevnamebuf
, lastdescp
->cd_namelen
+ 1);
851 prevdesc
.cd_hint
= lastdescp
->cd_hint
;
852 prevdesc
.cd_nameptr
= prevnamebuf
;
853 prevdesc
.cd_namelen
= lastdescp
->cd_namelen
+ 1;
857 /* All done with the catalog descriptors. */
858 for (i
= 0; i
< ce_list
->realentries
; ++i
)
859 cat_releasedesc(&ce_list
->entry
[i
].ce_desc
);
860 ce_list
->realentries
= 0;
862 } /* while not depleted */
864 *ap
->a_newstate
= dcp
->c_mtime
;
866 /* All done with last name hint */
867 hfs_relnamehint(dcp
, startindex
);
870 /* Convert directory index into uio_offset. */
871 uio
->uio_offset
= index
* sizeof(struct dirent
);
873 /* Save a name hint if there are more entries */
874 if ((error
== 0) && prevnamebuf
&& (index
+ 1) < dcp
->c_entries
)
875 hfs_savenamehint(dcp
, index
, prevnamebuf
);
878 hfs_relnamehint(dcp
, startindex
);
881 FREE(attrbufptr
, M_TEMP
);
883 FREE(ce_list
, M_TEMP
);
885 FREE(prevnamebuf
, M_TEMP
);
891 /*==================== Attribute list support routines ====================*/
894 * Pack cnode attributes into an attribute block.
898 hfs_packattrblk(struct attrblock
*abp
,
899 struct hfsmount
*hfsmp
,
901 struct cat_desc
*descp
,
902 struct cat_attr
*attrp
,
903 struct cat_fork
*datafork
,
904 struct cat_fork
*rsrcfork
,
907 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
909 if (attrlistp
->volattr
) {
910 if (attrlistp
->commonattr
)
911 packvolcommonattr(abp
, hfsmp
, vp
, p
);
913 if (attrlistp
->volattr
& ~ATTR_VOL_INFO
)
914 packvolattr(abp
, hfsmp
, vp
, p
);
916 if (attrlistp
->commonattr
)
917 packcommonattr(abp
, hfsmp
, vp
, descp
, attrp
, p
);
919 if (attrlistp
->dirattr
&& S_ISDIR(attrp
->ca_mode
))
920 packdirattr(abp
, hfsmp
, vp
, descp
,attrp
, p
);
922 if (attrlistp
->fileattr
&& !S_ISDIR(attrp
->ca_mode
))
923 packfileattr(abp
, hfsmp
, attrp
, datafork
, rsrcfork
, p
);
929 mountpointname(struct mount
*mp
)
931 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
939 * Look backwards through the name string, looking for
940 * the first slash encountered (which must precede the
941 * last part of the pathname).
943 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1;
944 namelength
> 0; --c
, --namelength
) {
947 } else if (foundchars
) {
952 return (mp
->mnt_stat
.f_mntonname
);
958 struct attrblock
*abp
,
965 struct attrreference
* attr_refptr
;
971 /* A cnode's name may be incorrect for the root of a mounted
972 * filesystem (it can be mounted on a different directory name
973 * than the name of the volume, such as "blah-1"). So for the
974 * root directory, it's best to return the last element of the
975 location where the volume's mounted:
977 if ((vp
!= NULL
) && (vp
->v_flag
& VROOT
) &&
978 (mpname
= mountpointname(vp
->v_mount
))) {
979 mpnamelen
= strlen(mpname
);
981 /* Trim off any trailing slashes: */
982 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/'))
985 /* If there's anything left, use it instead of the volume's name */
996 varbufptr
= *abp
->ab_varbufpp
;
997 attr_refptr
= (struct attrreference
*)(*abp
->ab_attrbufpp
);
999 attrlength
= namelen
+ 1;
1000 attr_refptr
->attr_dataoffset
= (char *)varbufptr
- (char *)attr_refptr
;
1001 attr_refptr
->attr_length
= attrlength
;
1002 (void) strncpy((unsigned char *)varbufptr
, name
, attrlength
);
1004 * Advance beyond the space just allocated and
1005 * round up to the next 4-byte boundary:
1007 (char *)(varbufptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1010 *abp
->ab_attrbufpp
= attr_refptr
;
1011 *abp
->ab_varbufpp
= varbufptr
;
1015 * Pack common volume attributes.
1018 packvolcommonattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
, struct proc
*p
)
1021 void *attrbufptr
= *abp
->ab_attrbufpp
;
1022 void *varbufptr
= *abp
->ab_varbufpp
;
1023 struct cnode
*cp
= VTOC(vp
);
1024 struct mount
*mp
= VTOVFS(vp
);
1025 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1028 attr
= abp
->ab_attrlist
->commonattr
;
1030 if (ATTR_CMN_NAME
& attr
) {
1031 packnameattr(abp
, vp
, cp
->c_desc
.cd_nameptr
, cp
->c_desc
.cd_namelen
, p
);
1032 attrbufptr
= *abp
->ab_attrbufpp
;
1033 varbufptr
= *abp
->ab_varbufpp
;
1035 if (ATTR_CMN_DEVID
& attr
) {
1036 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1038 if (ATTR_CMN_FSID
& attr
) {
1039 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1040 ++((fsid_t
*)attrbufptr
);
1042 if (ATTR_CMN_OBJTYPE
& attr
) {
1043 *((fsobj_type_t
*)attrbufptr
)++ = 0;
1045 if (ATTR_CMN_OBJTAG
& attr
) {
1046 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1048 if (ATTR_CMN_OBJID
& attr
) {
1049 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1050 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1051 ++((fsobj_id_t
*)attrbufptr
);
1053 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1054 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1055 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1056 ++((fsobj_id_t
*)attrbufptr
);
1058 if (ATTR_CMN_PAROBJID
& attr
) {
1059 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1060 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1061 ++((fsobj_id_t
*)attrbufptr
);
1063 if (ATTR_CMN_SCRIPT
& attr
) {
1066 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1067 encoding
= vcb
->volumeNameEncodingHint
;
1069 encoding
= hfsmp
->hfs_encoding
;
1070 *((text_encoding_t
*)attrbufptr
)++ = encoding
;
1072 if (ATTR_CMN_CRTIME
& attr
) {
1073 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbCrDate
;
1074 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1075 ++((struct timespec
*)attrbufptr
);
1077 if (ATTR_CMN_MODTIME
& attr
) {
1078 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1079 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1080 ++((struct timespec
*)attrbufptr
);
1082 if (ATTR_CMN_CHGTIME
& attr
) {
1083 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1084 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1085 ++((struct timespec
*)attrbufptr
);
1087 if (ATTR_CMN_ACCTIME
& attr
) {
1088 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbLsMod
;
1089 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1090 ++((struct timespec
*)attrbufptr
);
1092 if (ATTR_CMN_BKUPTIME
& attr
) {
1093 ((struct timespec
*)attrbufptr
)->tv_sec
= vcb
->vcbVolBkUp
;
1094 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1095 ++((struct timespec
*)attrbufptr
);
1097 if (ATTR_CMN_FNDRINFO
& attr
) {
1098 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1099 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1101 if (ATTR_CMN_OWNERID
& attr
) {
1102 if (cp
->c_uid
== UNKNOWNUID
)
1103 *((uid_t
*)attrbufptr
)++ = p
->p_ucred
->cr_uid
;
1105 *((uid_t
*)attrbufptr
)++ = cp
->c_uid
;
1107 if (ATTR_CMN_GRPID
& attr
) {
1108 *((gid_t
*)attrbufptr
)++ = cp
->c_gid
;
1110 if (ATTR_CMN_ACCESSMASK
& attr
) {
1112 * [2856576] Since we are dynamically changing the owner, also
1113 * effectively turn off the set-user-id and set-group-id bits,
1114 * just like chmod(2) would when changing ownership. This prevents
1115 * a security hole where set-user-id programs run as whoever is
1116 * logged on (or root if nobody is logged in yet!)
1118 *((u_long
*)attrbufptr
)++ =
1119 (cp
->c_uid
== UNKNOWNUID
) ? cp
->c_mode
& ~(S_ISUID
| S_ISGID
) : cp
->c_mode
;
1121 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1122 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1124 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1126 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1127 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1129 * Advance beyond the space just allocated and
1130 * round up to the next 4-byte boundary:
1132 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1133 ++((struct attrreference
*)attrbufptr
);
1135 if (ATTR_CMN_FLAGS
& attr
) {
1136 *((u_long
*)attrbufptr
)++ = cp
->c_flags
;
1138 if (ATTR_CMN_USERACCESS
& attr
) {
1139 *((u_long
*)attrbufptr
)++ =
1140 DerivePermissionSummary(cp
->c_uid
, cp
->c_gid
, cp
->c_mode
,
1141 VTOVFS(vp
), current_proc()->p_ucred
, current_proc());
1144 *abp
->ab_attrbufpp
= attrbufptr
;
1145 *abp
->ab_varbufpp
= varbufptr
;
1150 packvolattr(struct attrblock
*abp
, struct hfsmount
*hfsmp
, struct vnode
*vp
, struct proc
*p
)
1153 void *attrbufptr
= *abp
->ab_attrbufpp
;
1154 void *varbufptr
= *abp
->ab_varbufpp
;
1155 struct cnode
*cp
= VTOC(vp
);
1156 struct mount
*mp
= VTOVFS(vp
);
1157 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1160 attr
= abp
->ab_attrlist
->volattr
;
1162 if (ATTR_VOL_FSTYPE
& attr
) {
1163 *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1165 if (ATTR_VOL_SIGNATURE
& attr
) {
1166 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1168 if (ATTR_VOL_SIZE
& attr
) {
1169 *((off_t
*)attrbufptr
)++ =
1170 (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1172 if (ATTR_VOL_SPACEFREE
& attr
) {
1173 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 0) *
1174 (off_t
)vcb
->blockSize
;
1176 if (ATTR_VOL_SPACEAVAIL
& attr
) {
1177 *((off_t
*)attrbufptr
)++ = (off_t
)hfs_freeblks(hfsmp
, 1) *
1178 (off_t
)vcb
->blockSize
;
1180 if (ATTR_VOL_MINALLOCATION
& attr
) {
1181 *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1183 if (ATTR_VOL_ALLOCATIONCLUMP
& attr
) {
1184 *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1186 if (ATTR_VOL_IOBLOCKSIZE
& attr
) {
1187 *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1189 if (ATTR_VOL_OBJCOUNT
& attr
) {
1190 *((u_long
*)attrbufptr
)++ =
1191 (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1193 if (ATTR_VOL_FILECOUNT
& attr
) {
1194 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1196 if (ATTR_VOL_DIRCOUNT
& attr
) {
1197 *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1199 if (ATTR_VOL_MAXOBJCOUNT
& attr
) {
1200 *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1202 if (ATTR_VOL_MOUNTPOINT
& attr
) {
1203 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1204 (char *)varbufptr
- (char *)attrbufptr
;
1205 ((struct attrreference
*)attrbufptr
)->attr_length
=
1206 strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1207 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1208 /* round up to the next 4-byte boundary: */
1209 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1210 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1212 /* Advance beyond the space just allocated: */
1213 (char *)varbufptr
+= attrlength
;
1214 ++((struct attrreference
*)attrbufptr
);
1216 if (ATTR_VOL_NAME
& attr
) {
1217 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1218 (char *)varbufptr
- (char *)attrbufptr
;
1219 ((struct attrreference
*)attrbufptr
)->attr_length
=
1220 cp
->c_desc
.cd_namelen
+ 1;
1221 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1222 /* round up to the next 4-byte boundary: */
1223 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1224 /* XXX this could read off the end of cd_nameptr! */
1225 bcopy(cp
->c_desc
.cd_nameptr
, varbufptr
, attrlength
);
1227 /* Advance beyond the space just allocated: */
1228 (char *)varbufptr
+= attrlength
;
1229 ++((struct attrreference
*)attrbufptr
);
1231 if (ATTR_VOL_MOUNTFLAGS
& attr
) {
1232 *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
1234 if (ATTR_VOL_MOUNTEDDEVICE
& attr
) {
1235 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
=
1236 (char *)varbufptr
- (char *)attrbufptr
;
1237 ((struct attrreference
*)attrbufptr
)->attr_length
=
1238 strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
1239 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1240 /* round up to the next 4-byte boundary: */
1241 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1242 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
1244 /* Advance beyond the space just allocated: */
1245 (char *)varbufptr
+= attrlength
;
1246 ++((struct attrreference
*)attrbufptr
);
1248 if (ATTR_VOL_ENCODINGSUSED
& attr
) {
1249 *((unsigned long long *)attrbufptr
)++ =
1250 (unsigned long long)vcb
->encodingsBitmap
;
1252 if (ATTR_VOL_CAPABILITIES
& attr
) {
1253 vol_capabilities_attr_t
*vcapattrptr
;
1255 vcapattrptr
= (vol_capabilities_attr_t
*)attrbufptr
;
1257 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1258 u_int32_t journal_active
;
1259 u_int32_t case_sensitive
;
1262 journal_active
= VOL_CAP_FMT_JOURNAL_ACTIVE
;
1266 if (hfsmp
->hfs_flags
& HFS_CASE_SENSITIVE
)
1267 case_sensitive
= VOL_CAP_FMT_CASE_SENSITIVE
;
1271 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1272 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1273 VOL_CAP_FMT_SYMBOLICLINKS
|
1274 VOL_CAP_FMT_HARDLINKS
|
1275 VOL_CAP_FMT_JOURNAL
|
1278 VOL_CAP_FMT_CASE_PRESERVING
|
1279 VOL_CAP_FMT_FAST_STATFS
;
1280 } else { /* Plain HFS */
1281 vcapattrptr
->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1282 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1283 VOL_CAP_FMT_CASE_PRESERVING
|
1284 VOL_CAP_FMT_FAST_STATFS
;
1286 vcapattrptr
->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1287 VOL_CAP_INT_SEARCHFS
|
1288 VOL_CAP_INT_ATTRLIST
|
1289 VOL_CAP_INT_NFSEXPORT
|
1290 VOL_CAP_INT_READDIRATTR
|
1291 VOL_CAP_INT_EXCHANGEDATA
|
1292 VOL_CAP_INT_ALLOCATE
|
1293 VOL_CAP_INT_VOL_RENAME
|
1294 VOL_CAP_INT_ADVLOCK
|
1296 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1297 vcapattrptr
->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1299 vcapattrptr
->valid
[VOL_CAPABILITIES_FORMAT
] =
1300 VOL_CAP_FMT_PERSISTENTOBJECTIDS
|
1301 VOL_CAP_FMT_SYMBOLICLINKS
|
1302 VOL_CAP_FMT_HARDLINKS
|
1303 VOL_CAP_FMT_JOURNAL
|
1304 VOL_CAP_FMT_JOURNAL_ACTIVE
|
1305 VOL_CAP_FMT_NO_ROOT_TIMES
|
1306 VOL_CAP_FMT_SPARSE_FILES
|
1307 VOL_CAP_FMT_ZERO_RUNS
|
1308 VOL_CAP_FMT_CASE_SENSITIVE
|
1309 VOL_CAP_FMT_CASE_PRESERVING
|
1310 VOL_CAP_FMT_FAST_STATFS
;
1311 vcapattrptr
->valid
[VOL_CAPABILITIES_INTERFACES
] =
1312 VOL_CAP_INT_SEARCHFS
|
1313 VOL_CAP_INT_ATTRLIST
|
1314 VOL_CAP_INT_NFSEXPORT
|
1315 VOL_CAP_INT_READDIRATTR
|
1316 VOL_CAP_INT_EXCHANGEDATA
|
1317 VOL_CAP_INT_COPYFILE
|
1318 VOL_CAP_INT_ALLOCATE
|
1319 VOL_CAP_INT_VOL_RENAME
|
1320 VOL_CAP_INT_ADVLOCK
|
1322 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1323 vcapattrptr
->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1325 ++((vol_capabilities_attr_t
*)attrbufptr
);
1327 if (ATTR_VOL_ATTRIBUTES
& attr
) {
1328 vol_attributes_attr_t
*volattrattrp
;
1330 volattrattrp
= (vol_attributes_attr_t
*)attrbufptr
;
1331 volattrattrp
->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1332 volattrattrp
->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
1333 volattrattrp
->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1334 volattrattrp
->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1335 volattrattrp
->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1337 volattrattrp
->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1338 volattrattrp
->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
1339 volattrattrp
->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1340 volattrattrp
->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1341 volattrattrp
->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1342 ++((vol_attributes_attr_t
*)attrbufptr
);
1345 *abp
->ab_attrbufpp
= attrbufptr
;
1346 *abp
->ab_varbufpp
= varbufptr
;
1352 struct attrblock
*abp
,
1353 struct hfsmount
*hfsmp
,
1355 struct cat_desc
* cdp
,
1356 struct cat_attr
* cap
,
1359 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1360 struct mount
*mp
= HFSTOVFS(hfsmp
);
1361 void *attrbufptr
= *abp
->ab_attrbufpp
;
1362 void *varbufptr
= *abp
->ab_varbufpp
;
1363 u_long attrlength
= 0;
1365 if (ATTR_CMN_NAME
& attr
) {
1366 packnameattr(abp
, vp
, cdp
->cd_nameptr
, cdp
->cd_namelen
, p
);
1367 attrbufptr
= *abp
->ab_attrbufpp
;
1368 varbufptr
= *abp
->ab_varbufpp
;
1370 if (ATTR_CMN_DEVID
& attr
) {
1371 *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1373 if (ATTR_CMN_FSID
& attr
) {
1374 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1375 ++((fsid_t
*)attrbufptr
);
1377 if (ATTR_CMN_OBJTYPE
& attr
) {
1378 *((fsobj_type_t
*)attrbufptr
)++ = IFTOVT(cap
->ca_mode
);
1380 if (ATTR_CMN_OBJTAG
& attr
) {
1381 *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1384 * Exporting file IDs from HFS Plus:
1386 * For "normal" files the c_fileid is the same value as the
1387 * c_cnid. But for hard link files, they are different - the
1388 * c_cnid belongs to the active directory entry (ie the link)
1389 * and the c_fileid is for the actual inode (ie the data file).
1391 * The stat call (getattr) will always return the c_fileid
1392 * and Carbon APIs, which are hardlink-ignorant, will always
1393 * receive the c_cnid (from getattrlist).
1395 if (ATTR_CMN_OBJID
& attr
) {
1396 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1397 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1398 ++((fsobj_id_t
*)attrbufptr
);
1400 if (ATTR_CMN_OBJPERMANENTID
& attr
) {
1401 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_cnid
;
1402 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1403 ++((fsobj_id_t
*)attrbufptr
);
1405 if (ATTR_CMN_PAROBJID
& attr
) {
1406 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cdp
->cd_parentcnid
;
1407 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1408 ++((fsobj_id_t
*)attrbufptr
);
1410 if (ATTR_CMN_SCRIPT
& attr
) {
1411 *((text_encoding_t
*)attrbufptr
)++ = cdp
->cd_encoding
;
1413 if (ATTR_CMN_CRTIME
& attr
) {
1414 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_itime
;
1415 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1416 ++((struct timespec
*)attrbufptr
);
1418 if (ATTR_CMN_MODTIME
& attr
) {
1419 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_mtime
;
1420 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1421 ++((struct timespec
*)attrbufptr
);
1423 if (ATTR_CMN_CHGTIME
& attr
) {
1424 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_ctime
;
1425 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1426 ++((struct timespec
*)attrbufptr
);
1428 if (ATTR_CMN_ACCTIME
& attr
) {
1429 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_atime
;
1430 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1431 ++((struct timespec
*)attrbufptr
);
1433 if (ATTR_CMN_BKUPTIME
& attr
) {
1434 ((struct timespec
*)attrbufptr
)->tv_sec
= cap
->ca_btime
;
1435 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1436 ++((struct timespec
*)attrbufptr
);
1438 if (ATTR_CMN_FNDRINFO
& attr
) {
1439 bcopy(&cap
->ca_finderinfo
, attrbufptr
, sizeof(u_int8_t
) * 32);
1440 (char *)attrbufptr
+= sizeof(u_int8_t
) * 32;
1442 if (ATTR_CMN_OWNERID
& attr
) {
1443 *((uid_t
*)attrbufptr
)++ =
1444 (cap
->ca_uid
== UNKNOWNUID
) ? p
->p_ucred
->cr_uid
: cap
->ca_uid
;
1446 if (ATTR_CMN_GRPID
& attr
) {
1447 *((gid_t
*)attrbufptr
)++ = cap
->ca_gid
;
1449 if (ATTR_CMN_ACCESSMASK
& attr
) {
1451 * [2856576] Since we are dynamically changing the owner, also
1452 * effectively turn off the set-user-id and set-group-id bits,
1453 * just like chmod(2) would when changing ownership. This prevents
1454 * a security hole where set-user-id programs run as whoever is
1455 * logged on (or root if nobody is logged in yet!)
1457 *((u_long
*)attrbufptr
)++ =
1458 (cap
->ca_uid
== UNKNOWNUID
) ? cap
->ca_mode
& ~(S_ISUID
| S_ISGID
) : cap
->ca_mode
;
1460 if (ATTR_CMN_NAMEDATTRCOUNT
& attr
) {
1461 *((u_long
*)attrbufptr
)++ = 0;
1463 if (ATTR_CMN_NAMEDATTRLIST
& attr
) {
1465 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1466 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1468 * Advance beyond the space just allocated and
1469 * round up to the next 4-byte boundary:
1471 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1472 ++((struct attrreference
*)attrbufptr
);
1474 if (ATTR_CMN_FLAGS
& attr
) {
1475 *((u_long
*)attrbufptr
)++ = cap
->ca_flags
;
1477 if (ATTR_CMN_USERACCESS
& attr
) {
1478 *((u_long
*)attrbufptr
)++ =
1479 DerivePermissionSummary(cap
->ca_uid
, cap
->ca_gid
,
1480 cap
->ca_mode
, mp
, current_proc()->p_ucred
,
1484 *abp
->ab_attrbufpp
= attrbufptr
;
1485 *abp
->ab_varbufpp
= varbufptr
;
1490 struct attrblock
*abp
,
1491 struct hfsmount
*hfsmp
,
1493 struct cat_desc
* descp
,
1494 struct cat_attr
* cattrp
,
1497 attrgroup_t attr
= abp
->ab_attrlist
->dirattr
;
1498 void *attrbufptr
= *abp
->ab_attrbufpp
;
1500 if (ATTR_DIR_LINKCOUNT
& attr
)
1501 *((u_long
*)attrbufptr
)++ = cattrp
->ca_nlink
;
1502 if (ATTR_DIR_ENTRYCOUNT
& attr
) {
1503 u_long entries
= cattrp
->ca_entries
;
1505 if (descp
->cd_parentcnid
== kRootParID
) {
1506 if (hfsmp
->hfs_privdir_desc
.cd_cnid
!= 0)
1507 --entries
; /* hide private dir */
1509 entries
-= 2; /* hide the journal files */
1512 *((u_long
*)attrbufptr
)++ = entries
;
1514 if (ATTR_DIR_MOUNTSTATUS
& attr
) {
1515 if (vp
!= NULL
&& vp
->v_mountedhere
!= NULL
)
1516 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
1518 *((u_long
*)attrbufptr
)++ = 0;
1520 *abp
->ab_attrbufpp
= attrbufptr
;
1525 struct attrblock
*abp
,
1526 struct hfsmount
*hfsmp
,
1527 struct cat_attr
*cattrp
,
1528 struct cat_fork
*datafork
,
1529 struct cat_fork
*rsrcfork
,
1532 attrgroup_t attr
= abp
->ab_attrlist
->fileattr
;
1533 void *attrbufptr
= *abp
->ab_attrbufpp
;
1534 void *varbufptr
= *abp
->ab_varbufpp
;
1536 u_long allocblksize
;
1538 allocblksize
= HFSTOVCB(hfsmp
)->blockSize
;
1540 if (ATTR_FILE_LINKCOUNT
& attr
) {
1541 *((u_long
*)attrbufptr
)++ = cattrp
->ca_nlink
;
1543 if (ATTR_FILE_TOTALSIZE
& attr
) {
1544 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
+ rsrcfork
->cf_size
;
1546 if (ATTR_FILE_ALLOCSIZE
& attr
) {
1547 *((off_t
*)attrbufptr
)++ =
1548 (off_t
)cattrp
->ca_blocks
* (off_t
)allocblksize
;
1550 if (ATTR_FILE_IOBLOCKSIZE
& attr
) {
1551 *((u_long
*)attrbufptr
)++ = hfsmp
->hfs_logBlockSize
;
1553 if (ATTR_FILE_CLUMPSIZE
& attr
) {
1554 *((u_long
*)attrbufptr
)++ = HFSTOVCB(hfsmp
)->vcbClpSiz
;
1556 if (ATTR_FILE_DEVTYPE
& attr
) {
1557 if (S_ISBLK(cattrp
->ca_mode
) || S_ISCHR(cattrp
->ca_mode
))
1558 *((u_long
*)attrbufptr
)++ = (u_long
)cattrp
->ca_rdev
;
1560 *((u_long
*)attrbufptr
)++ = 0;
1562 if (ATTR_FILE_FILETYPE
& attr
) {
1563 *((u_long
*)attrbufptr
)++ = 0;
1565 if (ATTR_FILE_FORKCOUNT
& attr
) {
1566 *((u_long
*)attrbufptr
)++ = 2;
1568 if (ATTR_FILE_FORKLIST
& attr
) {
1570 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1571 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1573 * Advance beyond the space just allocated and
1574 * round up to the next 4-byte boundary:
1576 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1577 ++((struct attrreference
*)attrbufptr
);
1579 if (ATTR_FILE_DATALENGTH
& attr
) {
1580 *((off_t
*)attrbufptr
)++ = datafork
->cf_size
;
1582 if (ATTR_FILE_DATAALLOCSIZE
& attr
) {
1583 *((off_t
*)attrbufptr
)++ =
1584 (off_t
)datafork
->cf_blocks
* (off_t
)allocblksize
;
1586 if (ATTR_FILE_DATAEXTENTS
& attr
) {
1587 bcopy(&datafork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1588 (char *)attrbufptr
+= sizeof(extentrecord
);
1590 if (ATTR_FILE_RSRCLENGTH
& attr
) {
1591 *((off_t
*)attrbufptr
)++ = rsrcfork
->cf_size
;
1593 if (ATTR_FILE_RSRCALLOCSIZE
& attr
) {
1594 *((off_t
*)attrbufptr
)++ =
1595 (off_t
)rsrcfork
->cf_blocks
* (off_t
)allocblksize
;
1597 if (ATTR_FILE_RSRCEXTENTS
& attr
) {
1598 bcopy(&rsrcfork
->cf_extents
, attrbufptr
, sizeof(extentrecord
));
1599 (char *)attrbufptr
+= sizeof(extentrecord
);
1601 *abp
->ab_attrbufpp
= attrbufptr
;
1602 *abp
->ab_varbufpp
= varbufptr
;
1607 unpackattrblk(struct attrblock
*abp
, struct vnode
*vp
)
1609 struct attrlist
*attrlistp
= abp
->ab_attrlist
;
1611 if (attrlistp
->volattr
)
1612 unpackvolattr(abp
, VTOHFS(vp
), vp
);
1613 else if (attrlistp
->commonattr
)
1614 unpackcommonattr(abp
, vp
);
1620 struct attrblock
*abp
,
1623 attrgroup_t attr
= abp
->ab_attrlist
->commonattr
;
1624 void *attrbufptr
= *abp
->ab_attrbufpp
;
1625 struct cnode
*cp
= VTOC(vp
);
1627 if (ATTR_CMN_SCRIPT
& attr
) {
1628 cp
->c_encoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
1629 hfs_setencodingbits(VTOHFS(vp
), cp
->c_encoding
);
1631 if (ATTR_CMN_CRTIME
& attr
) {
1632 cp
->c_itime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1633 ++((struct timespec
*)attrbufptr
);
1635 if (ATTR_CMN_MODTIME
& attr
) {
1636 cp
->c_mtime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1637 cp
->c_mtime_nsec
= ((struct timespec
*)attrbufptr
)->tv_nsec
;
1638 ++((struct timespec
*)attrbufptr
);
1639 cp
->c_flag
&= ~C_UPDATE
;
1641 if (ATTR_CMN_CHGTIME
& attr
) {
1642 cp
->c_ctime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1643 ++((struct timespec
*)attrbufptr
);
1644 cp
->c_flag
&= ~C_CHANGE
;
1646 if (ATTR_CMN_ACCTIME
& attr
) {
1647 cp
->c_atime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1648 ++((struct timespec
*)attrbufptr
);
1649 cp
->c_flag
&= ~C_ACCESS
;
1651 if (ATTR_CMN_BKUPTIME
& attr
) {
1652 cp
->c_btime
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1653 ++((struct timespec
*)attrbufptr
);
1655 if (ATTR_CMN_FNDRINFO
& attr
) {
1656 bcopy(attrbufptr
, &cp
->c_attr
.ca_finderinfo
,
1657 sizeof(cp
->c_attr
.ca_finderinfo
));
1658 (char *)attrbufptr
+= sizeof(cp
->c_attr
.ca_finderinfo
);
1660 if (ATTR_CMN_OWNERID
& attr
) {
1661 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1662 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
1663 if (uid
!= (uid_t
)VNOVAL
)
1666 ((uid_t
*)attrbufptr
)++;
1669 if (ATTR_CMN_GRPID
& attr
) {
1670 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
1671 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1672 if (gid
!= (gid_t
)VNOVAL
)
1676 if (ATTR_CMN_ACCESSMASK
& attr
) {
1677 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
1678 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
1679 if (mode
!= (mode_t
)VNOVAL
) {
1680 cp
->c_mode
&= ~ALLPERMS
;
1681 cp
->c_mode
|= (mode
& ALLPERMS
);
1685 if (ATTR_CMN_FLAGS
& attr
) {
1686 u_long flags
= *((u_long
*)attrbufptr
)++;
1688 * Flags are settable only on HFS+ volumes. A special
1689 * exception is made for the IMMUTABLE flags
1690 * (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on
1691 * HFS volumes as well:
1693 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
1694 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) &&
1695 ((flags
& ~IMMUTABLE
) == 0))) {
1696 if (flags
!= (u_long
)VNOVAL
) {
1697 cp
->c_flags
= flags
;
1701 *abp
->ab_attrbufpp
= attrbufptr
;
1707 struct attrblock
*abp
,
1708 struct hfsmount
*hfsmp
,
1709 struct vnode
*rootvp
)
1711 void *attrbufptr
= *abp
->ab_attrbufpp
;
1712 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1715 attr
= abp
->ab_attrlist
->commonattr
;
1719 if (ATTR_CMN_SCRIPT
& attr
) {
1720 vcb
->volumeNameEncodingHint
=
1721 (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
1723 if (ATTR_CMN_CRTIME
& attr
) {
1724 vcb
->vcbCrDate
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1725 ++((struct timespec
*)attrbufptr
);
1727 /* The volume's create date comes from the root directory */
1728 VTOC(rootvp
)->c_itime
= vcb
->vcbCrDate
;
1729 VTOC(rootvp
)->c_flag
|= C_MODIFIED
;
1731 * XXX Should we also do a relative change to the
1732 * the volume header's create date in local time?
1735 if (ATTR_CMN_MODTIME
& attr
) {
1736 vcb
->vcbLsMod
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1737 ++((struct timespec
*)attrbufptr
);
1739 if (ATTR_CMN_BKUPTIME
& attr
) {
1740 vcb
->vcbVolBkUp
= ((struct timespec
*)attrbufptr
)->tv_sec
;
1741 ++((struct timespec
*)attrbufptr
);
1743 if (ATTR_CMN_FNDRINFO
& attr
) {
1744 bcopy(attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
1745 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1749 attr
= abp
->ab_attrlist
->volattr
& ~ATTR_VOL_INFO
;
1751 * XXX - no validation is done on the name!
1752 * It could be empty or garbage (bad UTF-8).
1754 if (ATTR_VOL_NAME
& attr
) {
1755 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
),
1756 vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
1757 (char *)attrbufptr
+= sizeof(struct attrreference
);
1759 *abp
->ab_attrbufpp
= attrbufptr
;
1761 vcb
->vcbFlags
|= 0xFF00;
1765 * Calculate the total size of an attribute block.
1769 hfs_attrblksize(struct attrlist
*attrlist
)
1774 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1775 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | \
1776 ATTR_CMN_PAROBJID | ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | \
1777 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | \
1778 ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1779 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | \
1780 ATTR_CMN_NAMEDATTRLIST | ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) \
1781 != ATTR_CMN_VALIDMASK)
1782 #error hfs_attrblksize: Missing bits in common mask computation!
1784 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1786 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | \
1787 ATTR_VOL_SPACEFREE | ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | \
1788 ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1789 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | \
1790 ATTR_VOL_MAXOBJCOUNT | ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | \
1791 ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | ATTR_VOL_MOUNTEDDEVICE | \
1792 ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) \
1793 != ATTR_VOL_VALIDMASK)
1794 #error hfs_attrblksize: Missing bits in volume mask computation!
1796 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1798 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) \
1799 != ATTR_DIR_VALIDMASK)
1800 #error hfs_attrblksize: Missing bits in directory mask computation!
1802 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1804 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | \
1805 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | \
1806 ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST | \
1807 ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1808 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) \
1809 != ATTR_FILE_VALIDMASK)
1810 #error hfs_attrblksize: Missing bits in file mask computation!
1812 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1814 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1815 #error hfs_attrblksize: Missing bits in fork mask computation!
1817 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1821 if ((a
= attrlist
->commonattr
) != 0) {
1822 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1823 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1824 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1825 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1826 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1827 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1828 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1829 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1830 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1831 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1832 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1833 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1834 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1835 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1836 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(u_int8_t
);
1837 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1838 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1839 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1840 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1841 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1842 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1843 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1845 if ((a
= attrlist
->volattr
) != 0) {
1846 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1847 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1848 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1849 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1850 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1851 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1852 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1853 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1854 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1855 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1856 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1857 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1858 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1859 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1860 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1861 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1862 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1863 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1864 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1866 if ((a
= attrlist
->dirattr
) != 0) {
1867 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1868 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1869 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1871 if ((a
= attrlist
->fileattr
) != 0) {
1872 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1873 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1874 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1875 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1876 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1877 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1878 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1879 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1880 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1881 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1882 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1883 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1884 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1885 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1886 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1888 if ((a
= attrlist
->forkattr
) != 0) {
1889 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1890 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1899 DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
,
1900 struct mount
*mp
, struct ucred
*cred
, struct proc
*p
)
1903 unsigned long permissions
;
1906 if (obj_uid
== UNKNOWNUID
)
1907 obj_uid
= p
->p_ucred
->cr_uid
;
1909 /* User id 0 (root) always gets access. */
1910 if (cred
->cr_uid
== 0) {
1911 permissions
= R_OK
| W_OK
| X_OK
;
1915 /* Otherwise, check the owner. */
1916 if (hfs_owner_rights(VFSTOHFS(mp
), obj_uid
, cred
, p
, false) == 0) {
1917 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1921 /* Otherwise, check the groups. */
1922 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1923 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1924 if (obj_gid
== *gp
) {
1925 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1931 /* Otherwise, settle for 'others' access. */
1932 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1935 return (permissions
);