BSDAttrList.c
/* |
File: BSDAttrList.c |
Contains: BSD attribute list command processing (getattrlist and so on). |
Written by: DTS |
Copyright: Copyright (c) 2008 Apple Inc. All Rights Reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. |
("Apple") in consideration of your agreement to the following |
terms, and your use, installation, modification or |
redistribution of this Apple software constitutes acceptance of |
these terms. If you do not agree with these terms, please do |
not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following |
terms, and subject to these terms, Apple grants you a personal, |
non-exclusive license, under Apple's copyrights in this |
original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or |
without modifications, in source and/or binary forms; provided |
that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the |
following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks |
or logos of Apple Inc. may be used to endorse or promote |
products derived from the Apple Software without specific prior |
written permission from Apple. Except as expressly stated in |
this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any |
patent rights that may be infringed by your derivative works or |
by other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. |
APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING |
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, |
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING |
THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, |
INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY |
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY |
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR |
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF |
SUCH DAMAGE. |
*/ |
#include "BSD.h" |
#include <sys/stat.h> |
#include <sys/mount.h> |
#include <sys/vnode.h> |
#include <stdint.h> |
#include <inttypes.h> |
#include <unistd.h> |
#include "FieldPrinter.h" |
#include "Command.h" |
///////////////////////////////////////////////////////////////// |
#pragma mark * getattrlist |
// Some useful getattrlist-related declarations. |
typedef struct attrlist attrlist_t; |
enum { |
kAttrRefSize = sizeof(attrreference_t) |
}; |
// FPFlagDesc versions of kCommonAttrDesc and kVolumeAttrDesc. |
// See InitAllAttrFlags for a discussion of why these are |
// necessary. |
static FPFlagDesc * gCommonAttrFlags; |
static FPFlagDesc * gVolumeAttrFlags; |
static FPFlagDesc * gDirAttrFlags; |
static FPFlagDesc * gFileAttrFlags; |
static FPFlagDesc * gForkAttrFlags; |
// AttrDesc describes an attribute, including info like its mask value, its identifier, |
// its size, and a pointer to the routine to print it. |
struct AttrDesc { |
attrgroup_t attrMask; |
const char * attrName; |
size_t attrSize; |
FPPrinter attrPrinter; |
const void * attrInfo; |
}; |
typedef struct AttrDesc AttrDesc; |
static void StringAttrPrinter( |
const char * fieldName, |
size_t fieldSize, |
const void * fieldPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
const void * info |
) |
// Prints a string attribute, as referenced by an attrreference_t structure |
// in the buffer returned by getattrlist. The encoding is assumed to be UTF-8. |
// |
// See definition of FPPrinter for a parameter description. |
{ |
attrreference_t * attrRef; |
#pragma unused(fieldSize) |
#pragma unused(verbose) |
#pragma unused(info) |
assert( FPStandardPreCondition() ); |
assert(fieldSize == sizeof(attrreference_t)); |
attrRef = ( (attrreference_t *) fieldPtr ); |
fprintf(stdout, "%*s%-*s = '%.*s'\n", (int) indent, "", (int) nameWidth, fieldName, (int) attrRef->attr_length, ((char *) attrRef) + attrRef->attr_dataoffset); |
} |
static void FPFSObjID( |
const char * fieldName, |
size_t fieldSize, |
const void * fieldPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
const void * info |
) |
// Prints an fsobj_id_t field. |
// |
// See definition of FPPrinter for a parameter description. |
{ |
const fsobj_id_t * fsobjPtr; |
#pragma unused(fieldSize) |
#pragma unused(verbose) |
#pragma unused(info) |
assert( FPStandardPreCondition() ); |
assert(fieldSize == sizeof(fsobj_id_t)); |
fsobjPtr = (const fsobj_id_t *) fieldPtr; |
fprintf(stdout, "%*s%-*s = (objno = 0x%08" PRIx32 ", generation = 0x%08" PRIx32 ")\n", (int) indent, "", (int) nameWidth, fieldName, fsobjPtr->fid_objno, fsobjPtr->fid_generation); |
} |
static void FPFSID( |
const char * fieldName, |
size_t fieldSize, |
const void * fieldPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
const void * info |
) |
// Prints an fsid_t field. |
// |
// See definition of FPPrinter for a parameter description. |
{ |
const fsid_t * fsidPtr; |
#pragma unused(fieldSize) |
#pragma unused(verbose) |
#pragma unused(info) |
assert( FPStandardPreCondition() ); |
assert(fieldSize == sizeof(fsid_t)); |
fsidPtr = (const fsid_t *) fieldPtr; |
fprintf(stdout, "%*s%-*s = [0x%08" PRIx32 ", 0x%08" PRIx32 "]\n", (int) indent, "", (int) nameWidth, fieldName, fsidPtr->val[0], fsidPtr->val[1]); |
} |
// Flags describing volume format capabilities. |
static const char kVolCapFlagSpacer[] = "VOL_CAP_FMT_PERSISTENTOBJECTIDS"; |
static const FPFlagDesc kVolCapFormatFlags[] = { |
{ VOL_CAP_FMT_PERSISTENTOBJECTIDS, "VOL_CAP_FMT_PERSISTENTOBJECTIDS" }, |
{ VOL_CAP_FMT_SYMBOLICLINKS, "VOL_CAP_FMT_SYMBOLICLINKS" }, |
{ VOL_CAP_FMT_HARDLINKS, "VOL_CAP_FMT_HARDLINKS" }, |
{ VOL_CAP_FMT_JOURNAL, "VOL_CAP_FMT_JOURNAL" }, |
{ VOL_CAP_FMT_JOURNAL_ACTIVE, "VOL_CAP_FMT_JOURNAL_ACTIVE" }, |
{ VOL_CAP_FMT_NO_ROOT_TIMES, "VOL_CAP_FMT_NO_ROOT_TIMES" }, |
{ VOL_CAP_FMT_SPARSE_FILES, "VOL_CAP_FMT_SPARSE_FILES" }, |
{ VOL_CAP_FMT_ZERO_RUNS, "VOL_CAP_FMT_ZERO_RUNS" }, |
{ VOL_CAP_FMT_CASE_SENSITIVE, "VOL_CAP_FMT_CASE_SENSITIVE" }, |
{ VOL_CAP_FMT_CASE_PRESERVING, "VOL_CAP_FMT_CASE_PRESERVING" }, |
{ VOL_CAP_FMT_FAST_STATFS, "VOL_CAP_FMT_FAST_STATFS" }, |
{ VOL_CAP_FMT_2TB_FILESIZE, "VOL_CAP_FMT_2TB_FILESIZE" }, |
{ VOL_CAP_FMT_OPENDENYMODES, "VOL_CAP_FMT_OPENDENYMODES" }, |
{ VOL_CAP_FMT_HIDDEN_FILES, "VOL_CAP_FMT_HIDDEN_FILES" }, |
{ VOL_CAP_FMT_PATH_FROM_ID, "VOL_CAP_FMT_PATH_FROM_ID" }, |
{ 0, NULL } |
}; |
// Flags describing volume API capabilities. |
static const FPFlagDesc kVolCapInterfacesFlags[] = { |
{ VOL_CAP_INT_SEARCHFS, "VOL_CAP_INT_SEARCHFS" }, |
{ VOL_CAP_INT_ATTRLIST, "VOL_CAP_INT_ATTRLIST" }, |
{ VOL_CAP_INT_NFSEXPORT, "VOL_CAP_INT_NFSEXPORT" }, |
{ VOL_CAP_INT_READDIRATTR, "VOL_CAP_INT_READDIRATTR" }, |
{ VOL_CAP_INT_EXCHANGEDATA, "VOL_CAP_INT_EXCHANGEDATA" }, |
{ VOL_CAP_INT_COPYFILE, "VOL_CAP_INT_COPYFILE" }, |
{ VOL_CAP_INT_ALLOCATE, "VOL_CAP_INT_ALLOCATE" }, |
{ VOL_CAP_INT_VOL_RENAME, "VOL_CAP_INT_VOL_RENAME" }, |
{ VOL_CAP_INT_ADVLOCK, "VOL_CAP_INT_ADVLOCK" }, |
{ VOL_CAP_INT_FLOCK, "VOL_CAP_INT_FLOCK" }, |
{ VOL_CAP_INT_EXTENDED_SECURITY, "VOL_CAP_INT_EXTENDED_SECURITY" }, |
{ VOL_CAP_INT_USERACCESS, "VOL_CAP_INT_USERACCESS" }, |
{ VOL_CAP_INT_MANLOCK, "VOL_CAP_INT_MANLOCK" }, |
{ VOL_CAP_INT_NAMEDSTREAMS, "VOL_CAP_INT_NAMEDSTREAMS" }, |
{ VOL_CAP_INT_EXTENDED_ATTR, "VOL_CAP_INT_EXTENDED_ATTR" }, |
{ 0, NULL } |
}; |
static void PrintVolCap(const u_int32_t *capList, uint32_t indent, uint32_t verbose) |
// Prints a vol_capabilities_set_t array which is made up of 5 u_int32_t |
// elements). Only two of the elements are currently used |
// (with indexes VOL_CAPABILITIES_FORMAT and VOL_CAPABILITIES_INTERFACES) |
// and, for those, we print all the flags. The remainder are just printed |
// in hex. |
{ |
assert(capList != NULL); |
fprintf(stdout, "%*sVOL_CAPABILITIES_FORMAT = 0x%08" PRIx32 "\n", (int) indent, "", capList[VOL_CAPABILITIES_FORMAT]); |
if (verbose > 0) { |
FPPrintFlags(capList[VOL_CAPABILITIES_FORMAT], kVolCapFormatFlags, strlen(kVolCapFlagSpacer), indent + kStdIndent); |
} |
fprintf(stdout, "%*sVOL_CAPABILITIES_INTERFACES = 0x%08" PRIx32 "\n", (int) indent, "", capList[VOL_CAPABILITIES_INTERFACES]); |
if (verbose > 0) { |
FPPrintFlags(capList[VOL_CAPABILITIES_INTERFACES], kVolCapInterfacesFlags, strlen(kVolCapFlagSpacer), indent + kStdIndent); |
} |
fprintf(stdout, "%*sVOL_CAPABILITIES_RESERVED1 = 0x%08" PRIx32 "\n", (int) indent, "", capList[VOL_CAPABILITIES_RESERVED1]); |
fprintf(stdout, "%*sVOL_CAPABILITIES_RESERVED1 = 0x%08" PRIx32 "\n", (int) indent, "", capList[VOL_CAPABILITIES_RESERVED2]); |
} |
static void FPVolCap( |
const char * fieldName, |
size_t fieldSize, |
const void * fieldPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
const void * info |
) |
// Prints a vol_capabilities_attr_t field. |
// |
// See definition of FPPrinter for a parameter description. |
{ |
const vol_capabilities_attr_t * volCap; |
#pragma unused(fieldSize) |
#pragma unused(nameWidth) |
#pragma unused(info) |
assert( FPStandardPreCondition() ); |
assert(fieldSize == sizeof(vol_capabilities_attr_t)); |
volCap = (const vol_capabilities_attr_t *) fieldPtr; |
fprintf(stdout, "%*s%s\n", (int) indent, "", fieldName); |
fprintf(stdout, "%*scapabilities\n", (int) (indent + kStdIndent), ""); |
PrintVolCap(volCap->capabilities, (int) (indent + 2 * kStdIndent), verbose); |
if (verbose > 1) { |
fprintf(stdout, "%*svalid\n", (int) (indent + kStdIndent), ""); |
PrintVolCap(volCap->valid, (int) (indent + 2 * kStdIndent), verbose); |
} |
} |
static void PrintAttrSet(const attribute_set_t *attrSet, uint32_t indent, uint32_t verbose) |
// Prints an attribute_set_t structure. If emulated is true, |
// this just prints the first two elements because those are the |
// only ones that we calculated as part of the emulation. |
// |
// indent and verbose are as per the comments for FPPrinter. |
{ |
static const char kVolAttrFlagSpacer[] = "ATTR_VOL_ALLOCATIONCLUMP"; |
assert(attrSet != NULL); |
// Using strlen(kVolAttrFlagSpacer) for the nameWidth ensures that all of |
// the flags are printed with a consistent name width. |
fprintf(stdout, "%*scommonattr = 0x%08" PRIx32 "\n", (int) indent, "", attrSet->commonattr); |
if (verbose > 0) { |
FPPrintFlags(attrSet->commonattr, gCommonAttrFlags, strlen(kVolAttrFlagSpacer), indent + kStdIndent); |
} |
fprintf(stdout, "%*svolattr = 0x%08" PRIx32 "\n", (int) indent, "", attrSet->volattr); |
if (verbose > 0) { |
FPPrintFlags(attrSet->volattr, gVolumeAttrFlags, strlen(kVolAttrFlagSpacer), indent + kStdIndent); |
} |
fprintf(stdout, "%*sdirattr = 0x%08" PRIx32 "\n", (int) indent, "", attrSet->dirattr); |
if (verbose > 0) { |
FPPrintFlags(attrSet->dirattr, gDirAttrFlags, strlen(kVolAttrFlagSpacer), indent + kStdIndent); |
} |
fprintf(stdout, "%*sfileattr = 0x%08" PRIx32 "\n", (int) indent, "", attrSet->fileattr); |
if (verbose > 0) { |
FPPrintFlags(attrSet->fileattr, gFileAttrFlags, strlen(kVolAttrFlagSpacer), indent + kStdIndent); |
} |
fprintf(stdout, "%*sforkattr = 0x%08" PRIx32 "\n", (int) indent, "", attrSet->forkattr); |
if (verbose > 0) { |
FPPrintFlags(attrSet->forkattr, gForkAttrFlags, strlen(kVolAttrFlagSpacer), indent + kStdIndent); |
} |
} |
static void FPVolAttr( |
const char * fieldName, |
size_t fieldSize, |
const void * fieldPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
const void * info |
) |
// Prints a vol_attributes_attr_t field. |
// |
// See definition of FPPrinter for a parameter description. |
{ |
const vol_attributes_attr_t * volAttr; |
#pragma unused(fieldSize) |
#pragma unused(nameWidth) |
#pragma unused(info) |
assert( FPStandardPreCondition() ); |
assert(fieldSize == sizeof(vol_attributes_attr_t)); |
volAttr = (const vol_attributes_attr_t *) fieldPtr; |
fprintf(stdout, "%*s%s\n", (int) indent, "", fieldName); |
fprintf(stdout, "%*svalidattr\n", (int) (indent + kStdIndent), ""); |
PrintAttrSet(&volAttr->validattr, indent + 2 * kStdIndent, ((verbose > 0) ? verbose - 1 : 0) ); |
fprintf(stdout, "%*snativeattr\n", (int) (indent + kStdIndent), ""); |
PrintAttrSet(&volAttr->nativeattr, indent + 2 * kStdIndent, ((verbose > 0) ? verbose - 1 : 0) ); |
} |
static const FPFlagDesc kACLFlags[] = { |
{ KAUTH_ACL_DEFER_INHERIT, "KAUTH_ACL_DEFER_INHERIT" }, |
{ KAUTH_ACL_NO_INHERIT, "KAUTH_ACL_NO_INHERIT" }, |
{ 0, NULL } |
}; |
static const FPEnumDesc kACEKinds[] = { |
{ KAUTH_ACE_PERMIT, "KAUTH_ACE_PERMIT" }, |
{ KAUTH_ACE_DENY, "KAUTH_ACE_DENY" }, |
{ KAUTH_ACE_AUDIT, "KAUTH_ACE_AUDIT" }, |
{ KAUTH_ACE_ALARM, "KAUTH_ACE_ALARM" }, |
{ 0, NULL } |
}; |
static const char kACEFlagsRightsSpacer[] = "KAUTH_VNODE_WRITE_EXTATTRIBUTES"; |
static const FPFlagDesc kACEFlags[] = { |
{ KAUTH_ACE_INHERITED, "KAUTH_ACE_INHERITED" }, |
{ KAUTH_ACE_FILE_INHERIT, "KAUTH_ACE_FILE_INHERIT" }, |
{ KAUTH_ACE_DIRECTORY_INHERIT, "KAUTH_ACE_DIRECTORY_INHERIT" }, |
{ KAUTH_ACE_LIMIT_INHERIT, "KAUTH_ACE_LIMIT_INHERIT" }, |
{ KAUTH_ACE_ONLY_INHERIT, "KAUTH_ACE_ONLY_INHERIT" }, |
{ KAUTH_ACE_SUCCESS, "KAUTH_ACE_SUCCESS" }, |
{ KAUTH_ACE_FAILURE, "KAUTH_ACE_FAILURE" }, |
{ 0, NULL } |
}; |
static const FPFlagDesc kACERights[] = { |
{ KAUTH_VNODE_LIST_DIRECTORY, "KAUTH_VNODE_LIST_DIRECTORY" }, |
{ KAUTH_VNODE_ADD_FILE, "KAUTH_VNODE_ADD_FILE" }, |
{ KAUTH_VNODE_SEARCH, "KAUTH_VNODE_SEARCH" }, |
{ KAUTH_VNODE_DELETE, "KAUTH_VNODE_DELETE" }, |
{ KAUTH_VNODE_ADD_SUBDIRECTORY, "KAUTH_VNODE_ADD_SUBDIRECTORY" }, |
{ KAUTH_VNODE_DELETE_CHILD, "KAUTH_VNODE_DELETE_CHILD" }, |
{ KAUTH_VNODE_READ_ATTRIBUTES, "KAUTH_VNODE_READ_ATTRIBUTES" }, |
{ KAUTH_VNODE_WRITE_ATTRIBUTES, "KAUTH_VNODE_WRITE_ATTRIBUTES" }, |
{ KAUTH_VNODE_READ_EXTATTRIBUTES, "KAUTH_VNODE_READ_EXTATTRIBUTES" }, |
{ KAUTH_VNODE_WRITE_EXTATTRIBUTES, "KAUTH_VNODE_WRITE_EXTATTRIBUTES" }, |
{ KAUTH_VNODE_READ_SECURITY, "KAUTH_VNODE_READ_SECURITY" }, |
{ KAUTH_VNODE_WRITE_SECURITY, "KAUTH_VNODE_WRITE_SECURITY" }, |
{ KAUTH_VNODE_TAKE_OWNERSHIP, "KAUTH_VNODE_TAKE_OWNERSHIP" }, |
{ KAUTH_VNODE_SYNCHRONIZE, "KAUTH_VNODE_SYNCHRONIZE" }, |
{ KAUTH_ACE_GENERIC_ALL, "KAUTH_ACE_GENERIC_ALL" }, |
{ KAUTH_ACE_GENERIC_EXECUTE, "KAUTH_ACE_GENERIC_EXECUTE" }, |
{ KAUTH_ACE_GENERIC_WRITE, "KAUTH_ACE_GENERIC_WRITE" }, |
{ KAUTH_ACE_GENERIC_READ, "KAUTH_ACE_GENERIC_READ" }, |
{ 0, NULL } |
}; |
extern void FPKauthFileSec( |
const char * fieldName, |
size_t fieldSize, |
const void * fieldPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
const void * info |
) |
// Prints a kauth_filesec_t field. This routine is exported for the benefit |
// of the File Manager module. |
// |
// See definition of FPPrinter for a parameter description. |
{ |
#pragma unused(fieldSize) |
#pragma unused(info) |
kauth_filesec_t fileSec; |
u_int32_t aceIndex; |
u_int32_t aceKind; |
static const char kFSecFieldNameSpacer[] = "fsec_magic"; |
static const char kACLFieldNameSpacer[] = "acl_entrycount"; |
static const char kACEFieldNameSpacer[] = "ace_applicable"; |
#pragma unused(fieldSize) |
#pragma unused(info) |
assert( FPStandardPreCondition() ); |
assert(fieldSize >= offsetof(struct kauth_filesec, fsec_acl)); |
assert(fieldSize <= KAUTH_FILESEC_SIZE(KAUTH_ACL_MAX_ENTRIES)); |
// Grab the attribute data and cast it to a kauth_filesec_t. |
fileSec = (kauth_filesec_t) fieldPtr; |
assert(fileSec->fsec_magic == KAUTH_FILESEC_MAGIC); |
fprintf(stdout, "%*s%s:\n", (int) indent, "", fieldName); |
// Originally I printed the ACL contents by calling acl_to_text, but I didn't like |
// the output format so now I do it manually. |
FPHex( "fsec_magic", sizeof(fileSec->fsec_magic), &fileSec->fsec_magic, indent + kStdIndent, strlen(kFSecFieldNameSpacer), verbose, NULL); |
FPGUID("fsec_owner", sizeof(fileSec->fsec_owner), &fileSec->fsec_owner, indent + kStdIndent, strlen(kFSecFieldNameSpacer), verbose, NULL); |
FPGUID("fsec_group", sizeof(fileSec->fsec_group), &fileSec->fsec_group, indent + kStdIndent, strlen(kFSecFieldNameSpacer), verbose, NULL); |
fprintf(stdout, "%*s%-*s\n", (int) (indent + kStdIndent), "", (int) nameWidth, "fsec_acl:"); |
FPUDec("acl_entrycount", sizeof(fileSec->fsec_acl.acl_entrycount), &fileSec->fsec_acl.acl_entrycount, indent + 2 * kStdIndent, strlen(kACLFieldNameSpacer), verbose, NULL); |
FPHex( "acl_flags", sizeof(fileSec->fsec_acl.acl_flags), &fileSec->fsec_acl.acl_flags, indent + 2 * kStdIndent, strlen(kACLFieldNameSpacer), verbose, NULL); |
if (verbose > 0) { |
FPPrintFlags(fileSec->fsec_acl.acl_flags, kACLFlags, 0, indent + 3 * kStdIndent); |
} |
if (fileSec->fsec_acl.acl_entrycount != KAUTH_FILESEC_NOACL) { |
// The attribute must be big enough to contain the number of ACL entries. |
assert(fieldSize >= KAUTH_FILESEC_SIZE(fileSec->fsec_acl.acl_entrycount)); |
for (aceIndex = 0; aceIndex < fileSec->fsec_acl.acl_entrycount; aceIndex++) { |
kauth_ace_t thisACE; |
thisACE = &fileSec->fsec_acl.acl_ace[aceIndex]; |
fprintf(stdout, "%*sacl_ace[%" PRIu32 "]\n", (int) (indent + 2 * kStdIndent), "", aceIndex); |
FPGUID("ace_applicable", sizeof(thisACE->ace_applicable), &thisACE->ace_applicable, indent + 3 * kStdIndent, strlen(kACEFieldNameSpacer), verbose, NULL); |
FPHex( "ace_flags", sizeof(thisACE->ace_flags), &thisACE->ace_flags, indent + 3 * kStdIndent, strlen(kACEFieldNameSpacer), verbose, NULL); |
if (verbose > 0) { |
aceKind = thisACE->ace_flags & KAUTH_ACE_KINDMASK; |
FPEnum("kind", sizeof(aceKind), &aceKind, indent + 4 * kStdIndent, strlen(kACEFlagsRightsSpacer), verbose, &kACEKinds); |
FPPrintFlags(thisACE->ace_flags & ~KAUTH_ACE_KINDMASK, kACEFlags, strlen(kACEFlagsRightsSpacer), indent + 4 * kStdIndent); |
} |
FPHex( "ace_rights", sizeof(thisACE->ace_rights), &thisACE->ace_rights, indent + 3 * kStdIndent, strlen(kACEFieldNameSpacer), verbose, NULL); |
if (verbose > 0) { |
FPPrintFlags(thisACE->ace_rights, kACERights, 0, indent + 4 * kStdIndent); |
} |
} |
} |
} |
static void ACLAttrPrinter( |
const char * fieldName, |
size_t fieldSize, |
const void * fieldPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
const void * info |
) |
// Prints an ACL attribute, as referenced by an attrreference_t structure |
// in the buffer returned by getattrlist. |
// |
// See definition of FPPrinter for a parameter description. |
{ |
attrreference_t * attrRef; |
#pragma unused(fieldSize) |
#pragma unused(verbose) |
#pragma unused(info) |
assert( FPStandardPreCondition() ); |
assert(fieldSize == sizeof(attrreference_t)); |
attrRef = ( (attrreference_t *) fieldPtr ); |
if (attrRef->attr_length != 0) { |
FPKauthFileSec(fieldName, attrRef->attr_length, ((char *) attrRef) + attrRef->attr_dataoffset, (int) indent, (int) nameWidth, verbose, NULL); |
} |
} |
// An array of AttrDesc is used to hold information about a set of attributes |
// as returned by getattrlist. The array is terminated by an entry with a NULL |
// name. |
static void PrintAttributes( |
const AttrDesc attrs[], |
attrgroup_t attrMask, |
const char ** cursorPtr, |
uint32_t indent, |
size_t nameWidth, |
uint32_t verbose, |
FinderInfoFlavour finderFlavour |
) |
// Prints an attribute buffer as returned by getattrlist. |
// attrs is a pointer to an array of AttrDesc that describe |
// all of the supported attributes. attrMask is a bitmap |
// describing which of those attributes are present in the buffer. |
// cursorPtr is a pointer a cursor pointer, which in turn points |
// to a buffer containing the attribute data. *cursorPtr points |
// to the current place in the buffer. When the routine is done |
// it updates *cursorPtr to point to just after the last attribute |
// that it has printed. indent, nameWidth and verbose are as |
// per the comments for FPPrinter. finderFlavour controls how |
// Finder info should be printed; it's necessary because Finder |
// info is object type dependent. |
{ |
size_t attrIndex; |
const char * cursor; |
assert(attrs != NULL); |
assert( cursorPtr != NULL); |
assert(*cursorPtr != NULL); |
cursor = *cursorPtr; |
attrIndex = 0; |
while (attrs[attrIndex].attrName != NULL) { |
if (attrMask & attrs[attrIndex].attrMask) { |
FPPrinter printer; |
printer = attrs[attrIndex].attrPrinter; |
if (printer == FPFinderInfoBE) { |
printer(attrs[attrIndex].attrName, attrs[attrIndex].attrSize, cursor, indent, nameWidth, verbose, (const void *) (uintptr_t) finderFlavour); |
} else { |
printer(attrs[attrIndex].attrName, attrs[attrIndex].attrSize, cursor, indent, nameWidth, verbose, attrs[attrIndex].attrInfo); |
} |
cursor += attrs[attrIndex].attrSize; |
} |
attrIndex += 1; |
} |
*cursorPtr = cursor; |
} |
// The known constants for fsobj_type_t attributes. |
static const FPEnumDesc kFSObjTypeEnums[] = { |
{ VNON, "VNON" }, |
{ VREG, "VREG" }, |
{ VDIR, "VDIR" }, |
{ VBLK, "VBLK" }, |
{ VCHR, "VCHR" }, |
{ VLNK, "VLNK" }, |
{ VSOCK, "VSOCK" }, |
{ VFIFO, "VFIFO" }, |
{ VBAD, "VBAD" }, |
{ VSTR, "VSTR" }, |
{ VCPLX, "VCPLX" }, |
{ 0, NULL } |
}; |
// The known constants for fsobj_tag_t attributes. |
static const FPEnumDesc kFSObjTagEnums[] = { |
{ VT_NON, "VT_NON" }, |
{ VT_UFS, "VT_UFS" }, |
{ VT_NFS, "VT_NFS" }, |
{ VT_MFS, "VT_MFS" }, |
{ VT_MSDOSFS, "VT_MSDOSFS" }, |
{ VT_LFS, "VT_LFS" }, |
{ VT_LOFS, "VT_LOFS" }, |
{ VT_FDESC, "VT_FDESC" }, |
{ VT_PORTAL, "VT_PORTAL" }, |
{ VT_NULL, "VT_NULL" }, |
{ VT_UMAP, "VT_UMAP" }, |
{ VT_KERNFS, "VT_KERNFS" }, |
{ VT_PROCFS, "VT_PROCFS" }, |
{ VT_AFS, "VT_AFS" }, |
{ VT_ISOFS, "VT_ISOFS" }, |
{ VT_UNION, "VT_UNION" }, |
{ VT_HFS, "VT_HFS" }, |
{ VT_ZFS, "VT_ZFS" }, // was VT_VOLFS prior to 10.5 |
{ VT_DEVFS, "VT_DEVFS" }, |
{ VT_WEBDAV, "VT_WEBDAV" }, |
{ VT_UDF, "VT_UDF" }, |
{ VT_AFP, "VT_AFP" }, |
{ VT_CDDA, "VT_CDDA" }, |
{ VT_CIFS, "VT_CIFS" }, |
{ VT_OTHER, "VT_OTHER" }, |
{ 0, NULL } |
}; |
// Some well known values for the text_encoding_t type |
// (equivalent to the Carbon TextEncoding type). Note that this |
// doesn't cover all possible values, just those that you're |
// likely to encounter in a file system. |
const FPEnumDesc kTextEncodingEnums[] = { |
{ kTextEncodingMacRoman, "kTextEncodingMacRoman" }, |
{ kTextEncodingMacJapanese, "kTextEncodingMacJapanese" }, |
{ kTextEncodingMacChineseTrad, "kTextEncodingMacChineseTrad" }, |
{ kTextEncodingMacKorean, "kTextEncodingMacKorean" }, |
{ kTextEncodingMacArabic, "kTextEncodingMacArabic" }, |
{ kTextEncodingMacHebrew, "kTextEncodingMacHebrew" }, |
{ kTextEncodingMacGreek, "kTextEncodingMacGreek" }, |
{ kTextEncodingMacCyrillic, "kTextEncodingMacCyrillic" }, |
{ kTextEncodingMacDevanagari, "kTextEncodingMacDevanagari" }, |
{ kTextEncodingMacGurmukhi, "kTextEncodingMacGurmukhi" }, |
{ kTextEncodingMacGujarati, "kTextEncodingMacGujarati" }, |
{ kTextEncodingMacOriya, "kTextEncodingMacOriya" }, |
{ kTextEncodingMacBengali, "kTextEncodingMacBengali" }, |
{ kTextEncodingMacTamil, "kTextEncodingMacTamil" }, |
{ kTextEncodingMacTelugu, "kTextEncodingMacTelugu" }, |
{ kTextEncodingMacKannada, "kTextEncodingMacKannada" }, |
{ kTextEncodingMacMalayalam, "kTextEncodingMacMalayalam" }, |
{ kTextEncodingMacSinhalese, "kTextEncodingMacSinhalese" }, |
{ kTextEncodingMacBurmese, "kTextEncodingMacBurmese" }, |
{ kTextEncodingMacKhmer, "kTextEncodingMacKhmer" }, |
{ kTextEncodingMacThai, "kTextEncodingMacThai" }, |
{ kTextEncodingMacLaotian, "kTextEncodingMacLaotian" }, |
{ kTextEncodingMacGeorgian, "kTextEncodingMacGeorgian" }, |
{ kTextEncodingMacArmenian, "kTextEncodingMacArmenian" }, |
{ kTextEncodingMacChineseSimp, "kTextEncodingMacChineseSimp" }, |
{ kTextEncodingMacTibetan, "kTextEncodingMacTibetan" }, |
{ kTextEncodingMacMongolian, "kTextEncodingMacMongolian" }, |
{ kTextEncodingMacEthiopic, "kTextEncodingMacEthiopic" }, |
{ kTextEncodingMacCentralEurRoman, "kTextEncodingMacCentralEurRoman" }, |
{ kTextEncodingMacVietnamese, "kTextEncodingMacVietnamese" }, |
{ kTextEncodingMacExtArabic, "kTextEncodingMacExtArabic" }, |
{ kTextEncodingMacSymbol, "kTextEncodingMacSymbol" }, |
{ kTextEncodingMacDingbats, "kTextEncodingMacDingbats" }, |
{ kTextEncodingMacTurkish, "kTextEncodingMacTurkish" }, |
{ kTextEncodingMacCroatian, "kTextEncodingMacCroatian" }, |
{ kTextEncodingMacIcelandic, "kTextEncodingMacIcelandic" }, |
{ kTextEncodingMacRomanian, "kTextEncodingMacRomanian" }, |
{ kTextEncodingMacCeltic, "kTextEncodingMacCeltic" }, |
{ kTextEncodingMacGaelic, "kTextEncodingMacGaelic" }, |
{ kTextEncodingMacKeyboardGlyphs, "kTextEncodingMacKeyboardGlyphs" }, |
{ kTextEncodingMacRSymbol, "kTextEncodingMacRSymbol" }, |
{ kTextEncodingMacUninterp, "kTextEncodingMacUninterp" }, |
{ kTextEncodingMacUnicode, "kTextEncodingMacUnicode" }, |
{ kTextEncodingMacFarsi, "kTextEncodingMacFarsi" }, |
{ kTextEncodingMacUkrainian, "kTextEncodingMacUkrainian" }, |
{ kTextEncodingMacInuit, "kTextEncodingMacInuit" }, |
{ kTextEncodingMacVT100, "kTextEncodingMacVT100" }, |
{ 0, NULL }, |
}; |
// Flags for the ATTR_CMN_USERACCESS attribute. |
static const FPFlagDesc kUserAccessFlags[] = { |
{ R_OK, "R_OK" }, |
{ W_OK, "W_OK" }, |
{ X_OK, "X_OK" }, |
{ 0, NULL } |
}; |
// Flags for the ATTR_VOL_ENCODINGSUSED attribute. |
// Note the weird values for the last two entries. |
static const FPFlagDesc kEncodingsUsedFlags[] = { |
{ 1LL << kTextEncodingMacRoman, "kTextEncodingMacRoman" }, |
{ 1LL << kTextEncodingMacRoman, "kTextEncodingMacRoman" }, |
{ 1LL << kTextEncodingMacJapanese, "kTextEncodingMacJapanese" }, |
{ 1LL << kTextEncodingMacChineseTrad, "kTextEncodingMacChineseTrad" }, |
{ 1LL << kTextEncodingMacKorean, "kTextEncodingMacKorean" }, |
{ 1LL << kTextEncodingMacArabic, "kTextEncodingMacArabic" }, |
{ 1LL << kTextEncodingMacHebrew, "kTextEncodingMacHebrew" }, |
{ 1LL << kTextEncodingMacGreek, "kTextEncodingMacGreek" }, |
{ 1LL << kTextEncodingMacCyrillic, "kTextEncodingMacCyrillic" }, |
{ 1LL << kTextEncodingMacRSymbol, "kTextEncodingMacRSymbol" }, |
{ 1LL << kTextEncodingMacDevanagari, "kTextEncodingMacDevanagari" }, |
{ 1LL << kTextEncodingMacGurmukhi, "kTextEncodingMacGurmukhi" }, |
{ 1LL << kTextEncodingMacGujarati, "kTextEncodingMacGujarati" }, |
{ 1LL << kTextEncodingMacOriya, "kTextEncodingMacOriya" }, |
{ 1LL << kTextEncodingMacBengali, "kTextEncodingMacBengali" }, |
{ 1LL << kTextEncodingMacTamil, "kTextEncodingMacTamil" }, |
{ 1LL << kTextEncodingMacTelugu, "kTextEncodingMacTelugu" }, |
{ 1LL << kTextEncodingMacKannada, "kTextEncodingMacKannada" }, |
{ 1LL << kTextEncodingMacMalayalam, "kTextEncodingMacMalayalam" }, |
{ 1LL << kTextEncodingMacSinhalese, "kTextEncodingMacSinhalese" }, |
{ 1LL << kTextEncodingMacBurmese, "kTextEncodingMacBurmese" }, |
{ 1LL << kTextEncodingMacKhmer, "kTextEncodingMacKhmer" }, |
{ 1LL << kTextEncodingMacThai, "kTextEncodingMacThai" }, |
{ 1LL << kTextEncodingMacLaotian, "kTextEncodingMacLaotian" }, |
{ 1LL << kTextEncodingMacGeorgian, "kTextEncodingMacGeorgian" }, |
{ 1LL << kTextEncodingMacArmenian, "kTextEncodingMacArmenian" }, |
{ 1LL << kTextEncodingMacChineseSimp, "kTextEncodingMacChineseSimp" }, |
{ 1LL << kTextEncodingMacTibetan, "kTextEncodingMacTibetan" }, |
{ 1LL << kTextEncodingMacMongolian, "kTextEncodingMacMongolian" }, |
{ 1LL << kTextEncodingMacEthiopic, "kTextEncodingMacEthiopic" }, |
{ 1LL << kTextEncodingMacCentralEurRoman, "kTextEncodingMacCentralEurRoman" }, |
{ 1LL << kTextEncodingMacVietnamese, "kTextEncodingMacVietnamese" }, |
{ 1LL << kTextEncodingMacExtArabic, "kTextEncodingMacExtArabic" }, |
{ 1LL << kTextEncodingMacUninterp, "kTextEncodingMacUninterp" }, |
{ 1LL << kTextEncodingMacSymbol, "kTextEncodingMacSymbol" }, |
{ 1LL << kTextEncodingMacDingbats, "kTextEncodingMacDingbats" }, |
{ 1LL << kTextEncodingMacTurkish, "kTextEncodingMacTurkish" }, |
{ 1LL << kTextEncodingMacCroatian, "kTextEncodingMacCroatian" }, |
{ 1LL << kTextEncodingMacIcelandic, "kTextEncodingMacIcelandic" }, |
{ 1LL << kTextEncodingMacRomanian, "kTextEncodingMacRomanian" }, |
{ 1LL << kTextEncodingMacCeltic, "kTextEncodingMacCeltic" }, |
{ 1LL << kTextEncodingMacGaelic, "kTextEncodingMacGaelic" }, |
{ 1LL << kTextEncodingMacKeyboardGlyphs, "kTextEncodingMacKeyboardGlyphs" }, |
{ 1LL << 49, "kTextEncodingMacFarsi" }, // note the special case |
{ 1LL << 48, "kTextEncodingMacUkrainian" }, // note the special case |
{ 0, NULL } |
}; |
// Common attributes, that is, those that are valid for all file system objects. |
static const AttrDesc kCommonAttrDesc[] = { |
{ATTR_CMN_NAME, "ATTR_CMN_NAME", kAttrRefSize, StringAttrPrinter, NULL}, |
{ATTR_CMN_DEVID, "ATTR_CMN_DEVID", sizeof(dev_t), FPDevT, NULL}, |
{ATTR_CMN_FSID, "ATTR_CMN_FSID", sizeof(fsid_t), FPFSID, NULL}, |
{ATTR_CMN_OBJTYPE, "ATTR_CMN_OBJTYPE", sizeof(fsobj_type_t), FPEnum, kFSObjTypeEnums}, |
{ATTR_CMN_OBJTAG, "ATTR_CMN_OBJTAG", sizeof(fsobj_tag_t), FPEnum, kFSObjTagEnums}, |
{ATTR_CMN_OBJID, "ATTR_CMN_OBJID", sizeof(fsobj_id_t), FPFSObjID, NULL}, |
{ATTR_CMN_OBJPERMANENTID, "ATTR_CMN_OBJPERMANENTID", sizeof(fsobj_id_t), FPFSObjID, NULL}, |
{ATTR_CMN_PAROBJID, "ATTR_CMN_PAROBJID", sizeof(fsobj_id_t), FPFSObjID, NULL}, |
{ATTR_CMN_SCRIPT, "ATTR_CMN_SCRIPT", sizeof(text_encoding_t), FPEnum, kTextEncodingEnums}, |
{ATTR_CMN_CRTIME, "ATTR_CMN_CRTIME", sizeof(struct timespec), FPTimeSpec, NULL}, |
{ATTR_CMN_MODTIME, "ATTR_CMN_MODTIME", sizeof(struct timespec), FPTimeSpec, NULL}, |
{ATTR_CMN_CHGTIME, "ATTR_CMN_CHGTIME", sizeof(struct timespec), FPTimeSpec, NULL}, |
{ATTR_CMN_ACCTIME, "ATTR_CMN_ACCTIME", sizeof(struct timespec), FPTimeSpec, NULL}, |
{ATTR_CMN_BKUPTIME, "ATTR_CMN_BKUPTIME", sizeof(struct timespec), FPTimeSpec, NULL}, |
{ATTR_CMN_FNDRINFO, "ATTR_CMN_FNDRINFO", 32, FPFinderInfoBE, NULL}, |
{ATTR_CMN_OWNERID, "ATTR_CMN_OWNERID", sizeof(uid_t), FPUID, NULL}, |
{ATTR_CMN_GRPID, "ATTR_CMN_GRPID", sizeof(gid_t), FPGID, NULL}, |
{ATTR_CMN_ACCESSMASK, "ATTR_CMN_ACCESSMASK", sizeof(uint32_t), FPModeT, NULL}, |
{ATTR_CMN_NAMEDATTRCOUNT, "ATTR_CMN_NAMEDATTRCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_CMN_NAMEDATTRLIST, "ATTR_CMN_NAMEDATTRLIST", kAttrRefSize, FPNull, NULL}, |
{ATTR_CMN_FLAGS, "ATTR_CMN_FLAGS", sizeof(uint32_t), FPFlags, kChFlagsFlags}, |
{ATTR_CMN_USERACCESS, "ATTR_CMN_USERACCESS", sizeof(uint32_t), FPFlags, kUserAccessFlags}, |
{ATTR_CMN_EXTENDED_SECURITY,"ATTR_CMN_EXTENDED_SECURITY", kAttrRefSize, ACLAttrPrinter, NULL}, |
{ATTR_CMN_UUID, "ATTR_CMN_UUID", sizeof(guid_t), FPGUID, NULL}, |
{ATTR_CMN_GRPUUID, "ATTR_CMN_GRPUUID", sizeof(guid_t), FPGUID, NULL}, |
{ATTR_CMN_FILEID, "ATTR_CMN_FILEID", sizeof(uint64_t), FPUDec, NULL}, |
{ATTR_CMN_PARENTID, "ATTR_CMN_PARENTID", sizeof(uint64_t), FPUDec, NULL}, |
{0, NULL, 0, NULL, NULL} |
}; |
// Volume attributes, valid only for volumes. |
static const AttrDesc kVolumeAttrDesc[] = { |
{ATTR_VOL_INFO, "ATTR_VOL_INFO", 0, FPNull, NULL}, |
{ATTR_VOL_FSTYPE, "ATTR_VOL_FSTYPE", sizeof(uint32_t), FPEnum, kFSTypeEnums}, |
{ATTR_VOL_SIGNATURE, "ATTR_VOL_SIGNATURE", sizeof(uint32_t), FPSignature, (const void *) (uintptr_t) kFPValueHostEndian}, |
{ATTR_VOL_SIZE, "ATTR_VOL_SIZE", sizeof(off_t), FPSize, NULL}, |
{ATTR_VOL_SPACEFREE, "ATTR_VOL_SPACEFREE", sizeof(off_t), FPSize, NULL}, |
{ATTR_VOL_SPACEAVAIL, "ATTR_VOL_SPACEAVAIL", sizeof(off_t), FPSize, NULL}, |
{ATTR_VOL_MINALLOCATION, "ATTR_VOL_MINALLOCATION", sizeof(off_t), FPSize, NULL}, |
{ATTR_VOL_ALLOCATIONCLUMP, "ATTR_VOL_ALLOCATIONCLUMP", sizeof(off_t), FPSize, NULL}, |
{ATTR_VOL_IOBLOCKSIZE, "ATTR_VOL_IOBLOCKSIZE", sizeof(uint32_t), FPSize, NULL}, |
{ATTR_VOL_OBJCOUNT, "ATTR_VOL_OBJCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_VOL_FILECOUNT, "ATTR_VOL_FILECOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_VOL_DIRCOUNT, "ATTR_VOL_DIRCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_VOL_MAXOBJCOUNT, "ATTR_VOL_MAXOBJCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_VOL_MOUNTPOINT, "ATTR_VOL_MOUNTPOINT", kAttrRefSize, StringAttrPrinter, NULL}, |
{ATTR_VOL_NAME, "ATTR_VOL_NAME", kAttrRefSize, StringAttrPrinter, NULL}, |
{ATTR_VOL_MOUNTFLAGS, "ATTR_VOL_MOUNTFLAGS", sizeof(uint32_t), FPFlags, kMountFlags}, |
{ATTR_VOL_MOUNTEDDEVICE, "ATTR_VOL_MOUNTEDDEVICE", kAttrRefSize, StringAttrPrinter, NULL}, |
{ATTR_VOL_ENCODINGSUSED, "ATTR_VOL_ENCODINGSUSED", sizeof(unsigned long long), FPVerboseFlags, kEncodingsUsedFlags}, |
{ATTR_VOL_CAPABILITIES, "ATTR_VOL_CAPABILITIES", sizeof(vol_capabilities_attr_t),FPVolCap, NULL}, |
{ATTR_VOL_ATTRIBUTES, "ATTR_VOL_ATTRIBUTES", sizeof(vol_attributes_attr_t), FPVolAttr, NULL}, |
{0, NULL, 0, NULL, NULL} |
}; |
// Directory attributes, valid only for directories. |
static const FPFlagDesc kMountStatusFlags[] = { |
{DIR_MNTSTATUS_MNTPOINT, "DIR_MNTSTATUS_MNTPOINT"}, |
{0, NULL} |
}; |
static const AttrDesc kDirAttrDesc[] = { |
{ATTR_DIR_LINKCOUNT, "ATTR_DIR_LINKCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_DIR_ENTRYCOUNT, "ATTR_DIR_ENTRYCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_DIR_MOUNTSTATUS, "ATTR_DIR_MOUNTSTATUS", sizeof(uint32_t), FPFlags, kMountStatusFlags}, |
{0, NULL, 0, NULL, NULL} |
}; |
// File attributes, valid only for files. |
static const AttrDesc kFileAttrDesc[] = { |
{ATTR_FILE_LINKCOUNT, "ATTR_FILE_LINKCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_FILE_TOTALSIZE, "ATTR_FILE_TOTALSIZE", sizeof(off_t), FPSize, NULL}, |
{ATTR_FILE_ALLOCSIZE, "ATTR_FILE_ALLOCSIZE", sizeof(off_t), FPSize, NULL}, |
{ATTR_FILE_IOBLOCKSIZE, "ATTR_FILE_IOBLOCKSIZE", sizeof(uint32_t), FPSize, NULL}, |
{ATTR_FILE_CLUMPSIZE, "ATTR_FILE_CLUMPSIZE", sizeof(uint32_t), FPSize, NULL}, |
{ATTR_FILE_DEVTYPE, "ATTR_FILE_DEVTYPE", sizeof(uint32_t), FPDevT, NULL}, // *** why does ATTR_FILE_DEVTYPE come back 0 on Tiger |
{ATTR_FILE_FILETYPE, "ATTR_FILE_FILETYPE", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_FILE_FORKCOUNT, "ATTR_FILE_FORKCOUNT", sizeof(uint32_t), FPUDec, NULL}, |
{ATTR_FILE_FORKLIST, "ATTR_FILE_FORKLIST", kAttrRefSize, FPNull, NULL}, |
{ATTR_FILE_DATALENGTH, "ATTR_FILE_DATALENGTH", sizeof(off_t), FPSize, NULL}, |
{ATTR_FILE_DATAALLOCSIZE, "ATTR_FILE_DATAALLOCSIZE", sizeof(off_t), FPSize, NULL}, |
{ATTR_FILE_DATAEXTENTS, "ATTR_FILE_DATAEXTENTS", sizeof(extentrecord), FPHex, NULL}, |
{ATTR_FILE_RSRCLENGTH, "ATTR_FILE_RSRCLENGTH", sizeof(off_t), FPSize, NULL}, |
{ATTR_FILE_RSRCALLOCSIZE, "ATTR_FILE_RSRCALLOCSIZE", sizeof(off_t), FPSize, NULL}, |
{ATTR_FILE_RSRCEXTENTS, "ATTR_FILE_RSRCEXTENTS", sizeof(extentrecord), FPHex, NULL}, |
{0, NULL, 0, NULL, NULL} |
}; |
// Fork attributes, valid only for forks. The whole concept of |
// fork attributes is kinda bogus, but we report them anyway. |
static const AttrDesc kForkAttrDesc[] = { |
{ATTR_FORK_TOTALSIZE, "ATTR_FORK_TOTALSIZE", sizeof(off_t), FPUDec, NULL}, |
{ATTR_FORK_ALLOCSIZE, "ATTR_FORK_ALLOCSIZE", sizeof(off_t), FPUDec, NULL}, |
{0, NULL, 0, NULL, NULL} |
}; |
static void InitAttrFlag(const AttrDesc attrs[], FPFlagDesc ** flagsPtr) |
// Given an AttrDesc array, create the corresponding FPFlagDesc array. |
// See InitAllAttrFlags for a discussion of why this is necessary. |
{ |
size_t attrCount; |
size_t attrIndex; |
FPFlagDesc * flags; |
assert( attrs != NULL); |
assert( flagsPtr != NULL); |
// Count the attributes. Make sure to include the trailing null entry |
// in that count. |
attrCount = 0; |
while (attrs[attrCount].attrName != NULL) { |
attrCount += 1; |
} |
attrCount += 1; |
// Allocate space for the flags. |
flags = (FPFlagDesc *) (malloc(attrCount * sizeof(FPFlagDesc))); |
assert(flags != NULL); |
// Create a flag for each attribute. |
for (attrIndex = 0; attrIndex < attrCount; attrIndex++) { |
flags[attrIndex].flagMask = attrs[attrIndex].attrMask; |
flags[attrIndex].flagName = attrs[attrIndex].attrName; |
} |
*flagsPtr = flags; |
} |
static void InitAllAttrFlags(void) |
// We need to have both an AttrDesc array (for printing the attributes in |
// a buffer) and a FPFlagDesc array (parsing our command line arguments). |
// Declaring these independently would be a maintenance nightmare, so we |
// derive the less generic one (FPFlagDesc) from the more generic one |
// (AttrDesc). |
{ |
if (gCommonAttrFlags == NULL) { |
InitAttrFlag(kCommonAttrDesc, &gCommonAttrFlags); |
InitAttrFlag(kVolumeAttrDesc, &gVolumeAttrFlags); |
InitAttrFlag(kDirAttrDesc, &gDirAttrFlags); |
InitAttrFlag(kFileAttrDesc, &gFileAttrFlags); |
InitAttrFlag(kForkAttrDesc, &gForkAttrFlags); |
} |
} |
static void CalculateAttrInfo( |
const AttrDesc attrs[], |
attrgroup_t attrMask, |
size_t * attrSizePtr, |
size_t * nameWidthPtr, |
attrgroup_t * supportedAttrPtr |
) |
// Calculates three pieces of useful information for an attribute set. |
// |
// o The size of the attributes. |
// |
// o The maximum width of the name of the attributes. |
// |
// o The attributes that we know about. |
// |
// You can ask for any combination of this information by setting the |
// appropriate parameters to a non-NULL value. |
// |
// IMPORTANT: |
// If you ask for a size (attrSizePtr), this routine increments the |
// existing value of *attrSizePtr by the size. You must initialise |
// the variable pointed to by attrSizePtr to an appropriate value. |
// |
// IMPORTANT: |
// If you ask for the maximum name length (nameWidthPtr), you must in |
// initialise *nameWidthPtr to a useful number (typically 0) before |
// calling this routine. |
// |
// The available attributes are described by the attrs array. The |
// attributes we're specifically concerned about are described by the |
// attrMask flags word. |
{ |
size_t attrIndex; |
size_t nameLen; |
attrgroup_t attrRemaining; |
assert(attrs != NULL); |
assert( (attrSizePtr != NULL) || (nameWidthPtr != NULL) || (supportedAttrPtr != NULL) ); // must ask us to do something! |
// For each possible attribute. |
attrRemaining = attrMask; |
attrIndex = 0; |
while (attrs[attrIndex].attrName != NULL) { |
if (attrRemaining & attrs[attrIndex].attrMask) { |
// If the attribute is selector, process its size and name. |
if (attrSizePtr != NULL) { |
*attrSizePtr += attrs[attrIndex].attrSize; |
if (attrs[attrIndex].attrPrinter == StringAttrPrinter) { |
*attrSizePtr += MAXPATHLEN; |
} else if (attrs[attrIndex].attrPrinter == ACLAttrPrinter) { |
*attrSizePtr += KAUTH_FILESEC_SIZE(KAUTH_ACL_MAX_ENTRIES); |
} |
} |
if (nameWidthPtr != NULL) { |
nameLen = strlen(attrs[attrIndex].attrName); |
if ( nameLen > *nameWidthPtr ) { |
*nameWidthPtr = nameLen; |
} |
} |
// Clear this attr from attrRemaining, so by the end of this loop |
// attrRemaining represents any unknown attrs. |
attrRemaining &= ~attrs[attrIndex].attrMask; |
} |
attrIndex += 1; |
} |
if (supportedAttrPtr != NULL) { |
*supportedAttrPtr = attrMask & ~attrRemaining; |
} |
} |
static int DoGetAttrListCommand(const char *itemPath, const attrlist_t *attrList, unsigned int opts, uint32_t indent, uint32_t verbose) |
// The core of the "getattrlist" command. Our caller has already got and parsed |
// all the necessary arguments; we just need to do the work. |
{ |
int err; |
attrlist_t attrListSupported; |
size_t attrBufSize; |
size_t attrNameWidth; |
char * attrBuf; |
const char * cursor; |
assert(itemPath != NULL); |
assert(attrList != NULL); |
// Work out which attributes we support, and also calculate some information |
// about those attributes, such as the total size of the required attribute |
// buffer and the maximum name width. |
attrBufSize = sizeof(uint32_t); |
attrNameWidth = 0; |
memset(&attrListSupported, 0, sizeof(attrListSupported)); |
attrListSupported.bitmapcount = ATTR_BIT_MAP_COUNT; |
CalculateAttrInfo(kCommonAttrDesc, attrList->commonattr, &attrBufSize, &attrNameWidth, &attrListSupported.commonattr); |
CalculateAttrInfo(kVolumeAttrDesc, attrList->volattr, &attrBufSize, &attrNameWidth, &attrListSupported.volattr); |
CalculateAttrInfo(kDirAttrDesc, attrList->dirattr, &attrBufSize, &attrNameWidth, &attrListSupported.dirattr); |
CalculateAttrInfo(kFileAttrDesc, attrList->fileattr, &attrBufSize, &attrNameWidth, &attrListSupported.fileattr); |
CalculateAttrInfo(kForkAttrDesc, attrList->forkattr, &attrBufSize, &attrNameWidth, &attrListSupported.forkattr); |
// Tell the user if we're ignoring certain attributes. |
if (attrListSupported.commonattr != attrList->commonattr) { |
fprintf(stderr, "*** Encountered unknown common attribute (0x%08" PRIx32 ").\n", attrList->commonattr & ~attrListSupported.commonattr ); |
} |
if (attrListSupported.volattr != attrList->volattr) { |
fprintf(stderr, "*** Encountered unknown volume attribute (0x%08" PRIx32 ").\n", attrList->volattr & ~attrListSupported.volattr ); |
} |
if (attrListSupported.dirattr != attrList->dirattr) { |
fprintf(stderr, "*** Encountered unknown directory attribute (0x%08" PRIx32 ").\n", attrList->dirattr & ~attrListSupported.dirattr ); |
} |
if (attrListSupported.fileattr != attrList->fileattr) { |
fprintf(stderr, "*** Encountered unknown file attribute (0x%08" PRIx32 ").\n", attrList->fileattr & ~attrListSupported.fileattr ); |
} |
if (attrListSupported.forkattr != attrList->forkattr) { |
fprintf(stderr, "*** Encountered unknown fork attribute (0x%08" PRIx32 ").\n", attrList->forkattr & ~attrListSupported.forkattr ); |
} |
// Add the ATTR_CMN_OBJTYPE attribute if we need it internally and the user hasn't |
// already requested it. |
if ( ( (attrListSupported.commonattr & ATTR_CMN_FNDRINFO) || (attrListSupported.dirattr != 0) || (attrListSupported.fileattr != 0) ) && ((attrListSupported.commonattr & ATTR_CMN_OBJTYPE) == 0) ) { |
attrListSupported.commonattr |= ATTR_CMN_OBJTYPE; |
attrBufSize += sizeof(fsobj_type_t); |
fprintf(stderr, "*** Added ATTR_CMN_OBJTYPE to allow us to print attributes that vary by file system object type.\n"); |
} |
// Allocate an attribute buffer. |
err = 0; |
attrBuf = (char *) malloc(attrBufSize); |
if (attrBuf == NULL) { |
err = ENOMEM; |
} |
// Call getattrlist to fill it in. |
if (err == 0) { |
err = getattrlist(itemPath, &attrListSupported, attrBuf, attrBufSize, opts); |
if (err < 0) { |
err = errno; |
} |
} |
// Print all of the attributes in the buffer. |
if (err == 0) { |
fsobj_type_t objType; |
size_t attrIndex; |
FinderInfoFlavour finderFlavour; |
// If we asked for the object type, work out what that type is. We need |
// this to a) determine how to print the Finder info, and b) work out |
// which attribute group to print. |
objType = VNON; |
if (attrListSupported.commonattr & ATTR_CMN_OBJTYPE) { |
cursor = attrBuf + sizeof(uint32_t); |
for (attrIndex = 0; (1 << attrIndex) <= ATTR_CMN_OBJTYPE; attrIndex++) { |
if (attrListSupported.commonattr & kCommonAttrDesc[attrIndex].attrMask) { |
if (kCommonAttrDesc[attrIndex].attrMask == ATTR_CMN_OBJTYPE) { |
objType = * (const fsobj_type_t *) cursor; |
} |
cursor += kCommonAttrDesc[attrIndex].attrSize; |
} |
} |
} |
// Work out the Finder info flavour. |
finderFlavour = kVolumeInfo; |
if ( (attrListSupported.commonattr & ATTR_CMN_FNDRINFO) && ! (attrListSupported.volattr & ATTR_VOL_INFO) ) { |
if (objType == VDIR) { |
finderFlavour = kFolderInfoCombined; |
} else { |
finderFlavour = kFileInfoCombined; |
} |
} |
// Print the returned attributes. |
cursor = attrBuf + sizeof(uint32_t); |
PrintAttributes(kCommonAttrDesc, attrListSupported.commonattr, &cursor, indent, attrNameWidth, verbose, finderFlavour); |
PrintAttributes(kVolumeAttrDesc, attrListSupported.volattr, &cursor, indent, attrNameWidth, verbose, finderFlavour); |
if (objType == VDIR) { |
PrintAttributes(kDirAttrDesc, attrListSupported.dirattr, &cursor, indent, attrNameWidth, verbose, finderFlavour); |
} else { |
PrintAttributes(kFileAttrDesc, attrListSupported.fileattr, &cursor, indent, attrNameWidth, verbose, finderFlavour); |
} |
PrintAttributes(kForkAttrDesc, attrListSupported.forkattr, &cursor, indent, attrNameWidth, verbose, finderFlavour); |
} |
// Clean up. |
free(attrBuf); |
return err; |
} |
static int AttrParseItemTester(const char *item, void *refCon) |
// A callback for CommandParseItemString that a) verifies that the attribute |
// is one that we support, and b) adds the bit for that attribute to the |
// attrlist_t pointed to be refCon. |
{ |
int err; |
attrlist_t * attrListPtr; |
size_t flagIndex; |
assert(item != NULL); |
attrListPtr = (attrlist_t *) refCon; |
assert(attrListPtr != NULL); |
assert(attrListPtr->bitmapcount == ATTR_BIT_MAP_COUNT); |
err = 0; |
flagIndex = FPFindFlagByName(gCommonAttrFlags, item); |
if (flagIndex != kFPNotFound) { |
attrListPtr->commonattr |= (attrgroup_t) gCommonAttrFlags[flagIndex].flagMask; |
} else { |
flagIndex = FPFindFlagByName(gVolumeAttrFlags, item); |
if (flagIndex != kFPNotFound) { |
attrListPtr->volattr |= (attrgroup_t) gVolumeAttrFlags[flagIndex].flagMask; |
} else { |
flagIndex = FPFindFlagByName(gDirAttrFlags, item); |
if (flagIndex != kFPNotFound) { |
attrListPtr->dirattr |= (attrgroup_t) gDirAttrFlags[flagIndex].flagMask; |
} else { |
flagIndex = FPFindFlagByName(gFileAttrFlags, item); |
if (flagIndex != kFPNotFound) { |
attrListPtr->fileattr |= (attrgroup_t) gFileAttrFlags[flagIndex].flagMask; |
} else { |
flagIndex = FPFindFlagByName(gForkAttrFlags, item); |
if (flagIndex != kFPNotFound) { |
attrListPtr->forkattr |= (attrgroup_t) gForkAttrFlags[flagIndex].flagMask; |
} else { |
err = EUSAGE; |
} |
} |
} |
} |
} |
return err; |
} |
static CommandError PrintGetAttrListInfo(CommandArgsRef args, uint32_t indent, uint32_t verbose) |
// Implements the "getattrlist" command. |
// |
// indent and verbose are as per the comments for FPPrinter. |
{ |
int err; |
unsigned int opts; |
const char * attrListStr; |
const char * itemPath; |
attrlist_t attrList; |
assert( CommandArgsValid(args) ); |
InitAllAttrFlags(); |
// Collect the arguments. |
opts = 0; |
if ( CommandArgsGetOptionalConstantString(args, "-FSOPT_NOFOLLOW") ) { |
opts |= FSOPT_NOFOLLOW; |
} |
if ( CommandArgsGetOptionString(args, &attrListStr) ) { |
// Use attrlist specified by user. |
} else { |
// Use default attrlist, which is just prints the list of supported attributes. |
attrListStr = "-ATTR_VOL_ATTRIBUTES"; |
} |
err = CommandArgsGetString(args, &itemPath); |
// Check that the attrListStr is valid and derive the attrlist_t from it. |
if (err == 0) { |
memset(&attrList, 0, sizeof(attrList)); |
attrList.bitmapcount = ATTR_BIT_MAP_COUNT; |
assert(attrListStr[0] == '-'); |
err = CommandParseItemString(&attrListStr[1], ',', AttrParseItemTester, &attrList); |
} |
// Do it! |
if (err == 0) { |
fprintf(stdout, "%*sgetattrlist %s%s %s\n", (int) indent, "", ((opts & FSOPT_NOFOLLOW) ? "-FSOPT_NOFOLLOW " : ""), ((attrListStr == NULL ) ? "<default>" : attrListStr), itemPath); |
err = DoGetAttrListCommand(itemPath, &attrList, opts, indent + kStdIndent, verbose); |
} |
return CommandErrorMakeWithErrno(err); |
} |
static void AttrDescHelpPrinter(uint32_t indent, uint32_t verbose, const void *param) |
// A CommandHelpProc to print help for a group of attributes. |
{ |
#pragma unused(verbose) |
const AttrDesc * attrs; |
size_t attrIndex; |
attrs = (const AttrDesc *) param; |
assert(attrs != NULL); |
// The convoluted logic below is because we print the attributes in two columns, |
// so as to reduce the amount of vertical space consumed. |
attrIndex = 0; |
while (attrs[attrIndex].attrName != NULL) { |
if (attrs[attrIndex + 1].attrName == NULL) { |
fprintf(stderr, "%*s%s\n", (int) (indent + strlen("-attrList") + 1), "", attrs[attrIndex].attrName); |
attrIndex += 1; |
} else { |
fprintf(stderr, "%*s%-30s %-30s\n", (int) (indent + strlen("-attrList") + 1), "", attrs[attrIndex].attrName, attrs[attrIndex + 1].attrName); |
attrIndex += 2; |
} |
} |
} |
static void AttrListHelpPrinter(uint32_t indent, uint32_t verbose, const void *param) |
// A CommandHelpProc to print all of the supportedd attributes. |
{ |
#pragma unused(param) |
if (verbose == 0) { |
fprintf(stderr, "%*s Add another -v flag to see a list\n", (int) indent, ""); |
} else { |
AttrDescHelpPrinter(indent, verbose, kCommonAttrDesc); |
fprintf(stderr, "\n"); |
AttrDescHelpPrinter(indent, verbose, kVolumeAttrDesc); |
fprintf(stderr, "\n"); |
AttrDescHelpPrinter(indent, verbose, kDirAttrDesc); |
fprintf(stderr, "\n"); |
AttrDescHelpPrinter(indent, verbose, kFileAttrDesc); |
fprintf(stderr, "\n"); |
AttrDescHelpPrinter(indent, verbose, kForkAttrDesc); |
} |
} |
static const CommandHelpEntry kGetAttrListCommandHelp[] = { |
{CommandHelpString, "-attrList Comma separated attributes; defaults to all ATTR_VOL_ATTRIBUTES"}, |
{AttrListHelpPrinter, NULL}, |
{NULL, NULL} |
}; |
const CommandInfo kGetAttrListCommand = { |
PrintGetAttrListInfo, |
"getattrlist", |
"[ -FSOPT_NOFOLLOW ] [ -attrList ] itemPath", |
"Print information from getattrlist.", |
kGetAttrListCommandHelp |
}; |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-02-25