#include <netinet/in.h>
#include <netdb.h>
#include <stdint.h>
#include <unistd.h>
#include <inttypes.h>
#include "FieldPrinter.h"
#include "Command.h"
#include "BSD.h" // for kTextEncodingEnums
/////////////////////////////////////////////////////////////////
#pragma mark ***** Utilities Routines
static void FPAFPString(
const char * fieldName,
size_t fieldSize,
const void * fieldPtr,
uint32_t indent,
size_t nameWidth,
uint32_t verbose,
const void * info
)
// Prints an AFP-style Pascal string field, where the field holds
// the offset from the start of the record to the Pascal string data.
// info supplies the offset from fieldPtr to the base of the record.
// The string is assumed to be MacRoman (not my favourite design
// decision, but offset is already being used and it was too painful
// to add an extra parameter, or break it out into a record).
//
// See definition of FPPrinter for a parameter description.
{
short fieldValue;
const UInt8 * pstrPtr;
char * strBuf;
#pragma unused(fieldSize)
#pragma unused(verbose)
assert( FPStandardPreCondition() );
fieldValue = *((const short *) fieldPtr);
pstrPtr = ((const UInt8 *) fieldPtr) - ((size_t) info) + fieldValue;
strBuf = FPPStringToUTFCString(pstrPtr, kCFStringEncodingMacRoman);
assert(strBuf != NULL);
if (strBuf != NULL) {
fprintf(stdout, "%*s%-*s = %hd ('%s')\n", (int) indent, "", (int) nameWidth, fieldName, fieldValue, strBuf);
}
free(strBuf);
}
static void FPFSFileSecurityRef(
const char * fieldName,
size_t fieldSize,
const void * fieldPtr,
uint32_t indent,
size_t nameWidth,
uint32_t verbose,
const void * info
)
{
#pragma unused(fieldSize)
#pragma unused(info)
OSStatus err;
int junk;
FSFileSecurityRef fileSec;
CFUUIDBytes uuid;
UInt32 id;
UInt16 mode;
assert( FPStandardPreCondition() );
assert(fieldSize == sizeof(FSFileSecurityRef));
fileSec = *((FSFileSecurityRef *) fieldPtr);
if (fileSec == NULL) {
fprintf(stdout, "%*s%-*s = NULL\n", (int) indent, "", (int) nameWidth, fieldName);
} else {
acl_t acl;
void * aclBuf;
size_t aclBufSize;
ssize_t aclActualSize;
aclBufSize = 0; // quieten warning
aclActualSize = 0; // quieten warning
acl = NULL;
aclBuf = NULL;
fprintf(stdout, "%*s%s:\n", (int) indent, "", fieldName);
err = FSFileSecurityGetOwnerUUID(fileSec, &uuid);
if (err == noErr) {
FPGUID("owner UUID", sizeof(uuid), &uuid, indent + kStdIndent, strlen("owner UUID"), verbose, NULL);
}
err = FSFileSecurityGetOwner(fileSec, &id);
if (err == noErr) {
FPUID("owner UID", sizeof(id), &id, indent + kStdIndent, strlen("owner UUID"), verbose, NULL);
}
err = FSFileSecurityGetGroupUUID(fileSec, &uuid);
if (err == noErr) {
FPGUID("group UUID", sizeof(uuid), &uuid, indent + kStdIndent, strlen("owner UUID"), verbose, NULL);
}
err = FSFileSecurityGetGroup(fileSec, &id);
if (err == noErr) {
FPGID("owning GID", sizeof(id), &id, indent + kStdIndent, strlen("owner UUID"), verbose, NULL);
}
err = FSFileSecurityGetMode(fileSec, &mode);
if (err == noErr) {
FPModeT("mode", sizeof(mode), &mode, indent + kStdIndent, strlen("owner UUID"), verbose, NULL);
}
err = FSFileSecurityCopyAccessControlList(fileSec, &acl);
if (err == noErr) {
aclBufSize = acl_size(acl);
aclBuf = malloc(aclBufSize);
if (aclBuf == NULL) {
err = memFullErr;
}
}
if (err == noErr) {
aclActualSize = acl_copy_ext_native(aclBuf, acl, aclBufSize);
if (aclActualSize < 0) {
err = errno;
} else {
assert( ((size_t) aclActualSize) <= aclBufSize );
}
}
if (err == noErr) {
FPKauthFileSec("acl", aclActualSize, aclBuf, indent + kStdIndent, strlen("owner UUID"), verbose, NULL);
}
free(aclBuf);
if (acl != NULL) {
junk = acl_free(acl);
assert(junk == 0);
}
}
}
#pragma mark * FSGetVolumeInfo
// FSVolumeInfoBitmap
static const FPFlagDesc kFSGetVolumeInfoOptions[] = {
{kFSVolInfoCreateDate, "kFSVolInfoCreateDate"},
{kFSVolInfoModDate, "kFSVolInfoModDate"},
{kFSVolInfoBackupDate, "kFSVolInfoBackupDate"},
{kFSVolInfoCheckedDate, "kFSVolInfoCheckedDate"},
{kFSVolInfoFileCount, "kFSVolInfoFileCount"},
{kFSVolInfoDirCount, "kFSVolInfoDirCount"},
{kFSVolInfoSizes, "kFSVolInfoSizes"},
{kFSVolInfoBlocks, "kFSVolInfoBlocks"},
{kFSVolInfoNextAlloc, "kFSVolInfoNextAlloc"},
{kFSVolInfoRsrcClump, "kFSVolInfoRsrcClump"},
{kFSVolInfoDataClump, "kFSVolInfoDataClump"},
{kFSVolInfoNextID, "kFSVolInfoNextID"},
{kFSVolInfoFinderInfo, "kFSVolInfoFinderInfo"},
{kFSVolInfoFlags, "kFSVolInfoFlags"},
{kFSVolInfoFSInfo, "kFSVolInfoFSInfo"},
{kFSVolInfoDriveInfo, "kFSVolInfoDriveInfo"},
{0, NULL}
};
// Flags in the flags field of FSVolumeInfo.
static const FPFlagDesc kVolAttrFlags[] = {
{kFSVolFlagDefaultVolumeMask, "kFSVolFlagDefaultVolumeMask" },
{kFSVolFlagFilesOpenMask, "kFSVolFlagFilesOpenMask" },
{kFSVolFlagHardwareLockedMask, "kFSVolFlagHardwareLockedMask" },
{kFSVolFlagJournalingActiveMask, "kFSVolFlagJournalingActiveMask"},
{kFSVolFlagSoftwareLockedMask, "kFSVolFlagSoftwareLockedMask" },
{0, NULL}
};
// Size multipliers for fields in the FSVolumeInfo structure. See
// FPSize for a description of what this is about.
static const FPSizeMultiplier kFSGetVolumeInfoTotalBlocksMultiplier = {
offsetof(FSVolumeInfo, blockSize) - offsetof(FSVolumeInfo, totalBlocks),
sizeof(UInt32)
};
static const FPSizeMultiplier kFSGetVolumeInfoFreeBlocksMultiplier = {
offsetof(FSVolumeInfo, blockSize) - offsetof(FSVolumeInfo, freeBlocks),
sizeof(UInt32)
};
static void PrintVolumeInfo(
const HFSUniStr255 * volName,
FSVolumeInfoBitmap options,
const FSVolumeInfo * volInfo,
uint32_t indent,
uint32_t verbose
)
// The core of the FSGetVolumeInfo command.
{
const size_t kNameSpacer = strlen("nextAllocation");
assert(volName != NULL);
assert(volInfo != NULL);
HFSUniStr255FieldPrinter("volumeName", sizeof(*volName), volName, indent, kNameSpacer, verbose, NULL);
if (options & kFSVolInfoCreateDate) {
FPUTCDateTime("createDate", sizeof(volInfo->createDate), &volInfo->createDate, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoModDate) {
FPUTCDateTime("modifyDate", sizeof(volInfo->modifyDate), &volInfo->modifyDate, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoBackupDate) {
FPUTCDateTime("backupDate", sizeof(volInfo->backupDate), &volInfo->backupDate, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoCheckedDate) {
FPUTCDateTime("checkedDate", sizeof(volInfo->checkedDate), &volInfo->checkedDate, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoFileCount) {
FPUDec("fileCount", sizeof(volInfo->fileCount), &volInfo->fileCount, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoDirCount) {
FPUDec("folderCount", sizeof(volInfo->folderCount), &volInfo->folderCount, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoSizes) {
FPSize("totalBytes", sizeof(volInfo->totalBytes), &volInfo->totalBytes, indent, kNameSpacer, verbose, NULL);
FPSize("freeBytes", sizeof(volInfo->freeBytes), &volInfo->freeBytes, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoBlocks) {
FPSize("blockSize", sizeof(volInfo->blockSize), &volInfo->blockSize, indent, kNameSpacer, verbose, NULL);
FPSize("totalBlocks", sizeof(volInfo->totalBlocks), &volInfo->totalBlocks, indent, kNameSpacer, verbose, &kFSGetVolumeInfoTotalBlocksMultiplier);
FPSize("freeBlocks", sizeof(volInfo->freeBlocks), &volInfo->freeBlocks, indent, kNameSpacer, verbose, &kFSGetVolumeInfoFreeBlocksMultiplier);
}
if (options & kFSVolInfoNextAlloc) {
FPUDec("nextAllocation", sizeof(volInfo->nextAllocation), &volInfo->nextAllocation, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoRsrcClump) {
FPSize("rsrcClumpSize", sizeof(volInfo->rsrcClumpSize), &volInfo->rsrcClumpSize, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoDataClump) {
FPSize("dataClumpSize", sizeof(volInfo->dataClumpSize), &volInfo->dataClumpSize, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoNextID) {
FPUDec("nextCatalogID", sizeof(volInfo->nextCatalogID), &volInfo->nextCatalogID, indent, kNameSpacer, verbose, NULL);
}
if (options & kFSVolInfoFinderInfo) {
FPFinderInfo("finderInfo", sizeof(volInfo->finderInfo), &volInfo->finderInfo, indent, kNameSpacer, verbose, (void *) (uintptr_t) kVolumeInfo);
}
if (options & kFSVolInfoFlags) {
FPFlags("flags", sizeof(volInfo->flags), &volInfo->flags, indent, kNameSpacer, verbose, kVolAttrFlags);
}
if (options & kFSVolInfoFSInfo) {
FPSignature("filesystemID", sizeof(volInfo->filesystemID), &volInfo->filesystemID, indent, kNameSpacer, verbose, (const void *) (uintptr_t) kFPValueHostEndian);
FPSignature("signature", sizeof(volInfo->signature), &volInfo->signature, indent, kNameSpacer, verbose, (const void *) (uintptr_t) kFPValueHostEndian);
}
if (options & kFSVolInfoDriveInfo) {
FPUDec("driveNumber", sizeof(volInfo->driveNumber), &volInfo->driveNumber, indent, kNameSpacer, verbose, NULL);
FPUDec("driverRefNum", sizeof(volInfo->driverRefNum), &volInfo->driverRefNum, indent, kNameSpacer, verbose, NULL);
}
}
static CommandError PrintFSGetVolumeInfo(CommandArgsRef args, uint32_t indent, uint32_t verbose)
// Uses FSGetVolumeInfo to get information about the specified volume and
// prints the result.
//
// indent and verbose are as per the comments for FPPrinter.
{
OSStatus err;
int options;
ItemCount volIndex;
FSVolumeRefNum volRefNum;
FSVolumeInfo volInfo;
HFSUniStr255 volName;
assert( CommandArgsValid(args) );
volIndex = 0; // quieten warning
if (CommandArgsIsOption(args)) {
err = CommandArgsGetFlagListInt(args, kFSGetVolumeInfoOptions, &options);
} else {
options = kFSVolInfoGettableInfo;
err = noErr;
}
if (err == noErr) {
if ( CommandArgsGetOptionalConstantString(args, "all") ) {
volIndex = 1;
volRefNum = 0;
} else {
volIndex = 0;
err = CommandArgsGetVRefNum(args, &volRefNum);
}
}
if (err == noErr) {
do {
FSVolumeRefNum realVolRefNum;
err = FSGetVolumeInfo(volRefNum, volIndex, &realVolRefNum, options, &volInfo, &volName, NULL);
if (err == noErr) {
if (volIndex > 0) {
// We're printing all volumes
if ( (volIndex > 1) && (options != 0) ) {
fprintf(stdout, "\n");
}
fprintf(stdout, "%*svRefNum = %d\n", (int) indent, "", (int) realVolRefNum);
PrintVolumeInfo(&volName, options, &volInfo, indent + kStdIndent, verbose);
} else {
// We're printing just one volume
PrintVolumeInfo(&volName, options, &volInfo, indent, verbose);
}
}
volIndex += 1;
} while ( (err == noErr) && (volIndex > 1) );
if ( (volIndex > 1) && (err == nsvErr) ) {
err = noErr;
}
}
return CommandErrorMakeWithOSStatus(err);
}
static const CommandHelpEntry kFSGetVolumeInfoCommandHelp[] = {
{CommandHelpString, "-options Volume information to get; default is kFSVolInfoGettableInfo"},
{CommandHelpFlags, kFSGetVolumeInfoOptions},
{NULL, NULL}
};
const CommandInfo kFSGetVolumeInfoCommand = {
PrintFSGetVolumeInfo,
"FSGetVolumeInfo",
"[ -options ] ( all | itemPath )",
"Print information from FSGetVolumeInfo.",
kFSGetVolumeInfoCommandHelp
};
#pragma mark * PBHGetVolParmsSync
// Flags for the vMAttrib field of the GetVolParmsInfoBuffer structure.
static const FPFlagDesc kVolParmsFlags[] = {
{1L << bLimitFCBs, "bLimitFCBs"},
{1L << bLocalWList, "bLocalWList"},
{1L << bNoMiniFndr, "bNoMiniFndr"},
{1L << bNoVNEdit, "bNoVNEdit"},
{1L << bNoLclSync, "bNoLclSync"},
{1L << bTrshOffLine, "bTrshOffLine"},
{1L << bNoSwitchTo, "bNoSwitchTo"},
{1L << bNoDeskItems, "bNoDeskItems"},
{1L << bNoBootBlks, "bNoBootBlks"},
{1L << bAccessCntl, "bAccessCntl"},
{1L << bNoSysDir, "bNoSysDir"},
{1L << bHasExtFSVol, "bHasExtFSVol"},
{1L << bHasOpenDeny, "bHasOpenDeny"},
{1L << bHasCopyFile, "bHasCopyFile"},
{1L << bHasMoveRename, "bHasMoveRename"},
{1L << bHasDesktopMgr, "bHasDesktopMgr"},
{1L << bHasShortName, "bHasShortName"},
{1L << bHasFolderLock, "bHasFolderLock"},
{1L << bHasPersonalAccessPrivileges, "bHasPersonalAccessPrivileges"},
{1L << bHasUserGroupList, "bHasUserGroupList"},
{1L << bHasCatSearch, "bHasCatSearch"},
{1L << bHasFileIDs, "bHasFileIDs"},
{1L << bHasBTreeMgr, "bHasBTreeMgr"},
{1L << bHasBlankAccessPrivileges, "bHasBlankAccessPrivileges"},
{1L << bSupportsAsyncRequests, "bSupportsAsyncRequests"},
{1L << bSupportsTrashVolumeCache, "bSupportsTrashVolumeCache"},
{1L << bHasDirectIO, "bHasDirectIO"},
{0, NULL}
};
// Flags for the vMExtendedAttributes field of the GetVolParmsInfoBuffer structure.
static const FPFlagDesc kVolParmsExtendedFlags[] = {
{1L << bSupportsExtendedFileSecurity, "bSupportsExtendedFileSecurity"},
{1L << bIsOnExternalBus, "bIsOnExternalBus"},
{1L << bNoRootTimes, "bNoRootTimes"},
{1L << bIsRemovable, "bIsRemovable"},
{1L << bDoNotDisplay, "bDoNotDisplay"},
{1L << bIsCasePreserving, "bIsCasePreserving"},
{1L << bIsCaseSensitive, "bIsCaseSensitive"},
{1L << bIsOnInternalBus, "bIsOnInternalBus"},
{1L << bNoVolumeSizes, "bNoVolumeSizes"},
{1L << bSupportsJournaling, "bSupportsJournaling"},
{1L << bSupportsExclusiveLocks, "bSupportsExclusiveLocks"},
{1L << bAllowCDiDataHandler, "bAllowCDiDataHandler"},
{1L << bIsAutoMounted, "bIsAutoMounted"},
{1L << bSupportsSymbolicLinks, "bSupportsSymbolicLinks"},
{1L << bAncestorModDateChanges, "bAncestorModDateChanges"},
{1L << bParentModDateChanges, "bParentModDateChanges"},
{1L << bL2PCanMapFileBlocks, "bL2PCanMapFileBlocks"},
{1L << bSupportsSubtreeIterators, "bSupportsSubtreeIterators"},
{1L << bSupportsNamedForks, "bSupportsNamedForks"},
{1L << bSupportsMultiScriptNames, "bSupportsMultiScriptNames"},
{1L << bSupportsLongNames, "bSupportsLongNames"},
{1L << bSupports2TBFiles, "bSupports2TBFiles"},
{1L << bSupportsFSExchangeObjects, "bSupportsFSExchangeObjects"},
{1L << bSupportsFSCatalogSearch, "bSupportsFSCatalogSearch"},
{1L << bSupportsHFSPlusAPIs, "bSupportsHFSPlusAPIs"},
{1L << bIsEjectable, "bIsEjectable"},
{0, NULL}
};
// Constants for the vMForeignPrivID field of the GetVolParmsInfoBuffer structure
static const FPEnumDesc kForeignPrivEnums[] = {
{0, "HFS"},
{fsUnixPriv, "fsUnixPriv"},
{0, NULL}
};
static const char kGetVolParmsInfoBufferFieldSpacer[32] = "vMExtendedAttributes";
// The fields of the GetVolParmsInfoBuffer structure. These are broken up into five
// groups to account for the various versions of the structure, which are in turn
// assembled into the kGetVolParmsInfoBufferFieldDescByVersion array for easy
// processing by the code.
// The only useful meaning of vMServerAdr in the modern world is a zero/non-zero test
// to see whether the volume is local or remote. I didn't feel that justified a custom
// printer routine.
static const FPFieldDesc kGetVolParmsInfoBufferFieldDescV1[] = {
{"vMVersion", offsetof(GetVolParmsInfoBuffer, vMVersion), sizeof(SInt16), FPSDec, NULL},
{"vMAttrib", offsetof(GetVolParmsInfoBuffer, vMAttrib), sizeof(SInt32), FPFlags, kVolParmsFlags},
{"vMLocalHand", offsetof(GetVolParmsInfoBuffer, vMLocalHand), sizeof(Handle), FPPtr, NULL},
{"vMServerAdr", offsetof(GetVolParmsInfoBuffer, vMServerAdr), sizeof(SInt32), FPHex, NULL},
{kGetVolParmsInfoBufferFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{NULL, 0, 0, NULL, NULL}
};
// While there is a definition for vMVolumeGrade (see DTS Technote 1121 "Mac OS 8.1"
// <http://developer.apple.com/technotes/tn/tn1121.html>), Core Services File Manager
// provides no way for a file system to return a value (it always returns 0), so there's
// no point providing a sophisticated interpretation.
static const FPFieldDesc kGetVolParmsInfoBufferFieldDescV2[] = {
{"vMVolumeGrade", offsetof(GetVolParmsInfoBuffer, vMVolumeGrade), sizeof(SInt32), FPSDec, NULL},
{"vMForeignPrivID", offsetof(GetVolParmsInfoBuffer, vMForeignPrivID), sizeof(SInt16), FPEnum, kForeignPrivEnums},
{kGetVolParmsInfoBufferFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{NULL, 0, 0, NULL, NULL}
};
static const FPFieldDesc kGetVolParmsInfoBufferFieldDescV3[] = {
{"vMExtendedAttributes", offsetof(GetVolParmsInfoBuffer, vMExtendedAttributes), sizeof(SInt32), FPFlags, kVolParmsExtendedFlags},
{NULL, 0, 0, NULL, NULL}
};
static const FPFieldDesc kGetVolParmsInfoBufferFieldDescV4[] = {
{"vMDeviceID", offsetof(GetVolParmsInfoBuffer, vMDeviceID), sizeof(void *), FPCStringPtr, NULL},
{kGetVolParmsInfoBufferFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{NULL, 0, 0, NULL, NULL}
};
static const FPFieldDesc kGetVolParmsInfoBufferFieldDescV5[] = {
{"vMMaxNameLength", offsetof(GetVolParmsInfoBuffer, vMMaxNameLength), sizeof(UniCharCount), FPUDec, NULL},
{kGetVolParmsInfoBufferFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{NULL, 0, 0, NULL, NULL}
};
static const FPFieldDesc * kGetVolParmsInfoBufferFieldDescByVersion[] = {
kGetVolParmsInfoBufferFieldDescV1,
kGetVolParmsInfoBufferFieldDescV2,
kGetVolParmsInfoBufferFieldDescV3,
kGetVolParmsInfoBufferFieldDescV4,
kGetVolParmsInfoBufferFieldDescV5
};
static void PrintVolumeParms(const GetVolParmsInfoBuffer *volParms, uint32_t indent, uint32_t verbose)
// Code to print a volume parms buffer, common to both the PBHGetVolParms
// and FSGetVolumeParms commands.
{
size_t versionIndex;
size_t versionLimit;
assert(volParms != NULL)
if (volParms->vMVersion < 1) {
fprintf(stdout, " vMVersion = %hd\n", volParms->vMVersion);
} else {
versionIndex = 0;
versionLimit = (sizeof(kGetVolParmsInfoBufferFieldDescByVersion) / sizeof(FPFieldDesc *));
if (versionLimit > (size_t) volParms->vMVersion) {
versionLimit = volParms->vMVersion;
}
while (versionIndex < versionLimit) {
FPPrintFields(kGetVolParmsInfoBufferFieldDescByVersion[versionIndex], volParms, sizeof(*volParms), indent, verbose);
versionIndex += 1;
}
}
}
#if ! TARGET_RT_64_BIT
static CommandError PrintPBHGetVolParms(CommandArgsRef args, uint32_t indent, uint32_t verbose)
// Uses PBHGetVolParmsSync to get information about the specified volume and
// prints the result.
//
// indent and verbose are as per the comments for FPPrinter.
{
OSStatus err;
FSVolumeRefNum volRefNum;
HParamBlockRec hpb;
GetVolParmsInfoBuffer volParms;
assert( CommandArgsValid(args) );
err = CommandArgsGetVRefNum(args, &volRefNum);
if (err == noErr) {
hpb.ioParam.ioNamePtr = NULL;
hpb.ioParam.ioVRefNum = volRefNum;
hpb.ioParam.ioBuffer = (Ptr) &volParms;
hpb.ioParam.ioReqCount = sizeof(volParms);
err = PBHGetVolParmsSync(&hpb);
}
if (err == noErr) {
PrintVolumeParms(&volParms, indent, verbose);
}
return CommandErrorMakeWithOSStatus(err);
}
const CommandInfo kPBHGetVolParmsCommand = {
PrintPBHGetVolParms,
"PBHGetVolParms",
"itemPath",
"Print information from PBHGetVolParms.",
NULL
};
#endif
static CommandError PrintFSGetVolumeParms(CommandArgsRef args, uint32_t indent, uint32_t verbose)
// Uses FSGetVolumeParms to get information about the specified volume and
// prints the result.
//
// indent and verbose are as per the comments for FPPrinter.
{
OSStatus err;
FSVolumeRefNum volRefNum;
GetVolParmsInfoBuffer volParms;
assert( CommandArgsValid(args) );
if ( FSGetVolumeParms == NULL ) {
return CommandErrorMakeWithCustom(kUnavailableCustomError);
}
err = CommandArgsGetVRefNum(args, &volRefNum);
if (err == noErr) {
err = FSGetVolumeParms(volRefNum, &volParms, sizeof(volParms));
}
if (err == noErr) {
PrintVolumeParms(&volParms, indent, verbose);
}
return CommandErrorMakeWithOSStatus(err);
}
const CommandInfo kFSGetVolumeParmsCommand = {
PrintFSGetVolumeParms,
"FSGetVolumeParms",
"itemPath",
"Print information from FSGetVolumeParms.",
NULL
};
#pragma mark * PBGetVolMountInfo
// Values for the uamType field of the AFPVolMountInfo.
static const FPEnumDesc kVolMountInfoUAMType[] = {
{ 1, "No User Authent" },
{ 2, "Cleartxt Passwrd" },
{ 3, "Randnum Exchange" },
{ 4, "Cleartxt Passwrd (variable length)" },
{ 5, "Randnum Exchange (variable length)" },
{ 6, "2-Way Randnum" },
{ 7, "DHCAST128" },
{ 8, "DHX2" },
{ 9, "Client Krb v2" },
{ 0, NULL }
};
// The following two enums document extra constants that should be in "Files.h" <rdar://problem/5439845>.
enum {
kAFPTagTypeIPv6 = 0x06,
kAFPTagTypeIPv6Port = 0x07
};
enum {
kAFPTagLengthIPv6 = 0x12,
kAFPTagLengthIPv6Port = 0x14
};
static void PrintAlternateAddresses(AFPXVolMountInfoPtr afpXVolInfoBuffer, short offset, uint32_t indent)
// Prints any alternative addresses embedded within the AFPXVolMountInfo structure.
//
// indent is per the comments for FPPrinter.
{
int junk;
AFPAlternateAddress * addrList;
AFPTagData * thisAddr;
int i;
UInt8 thisAddrType;
size_t addrIndex;
struct sockaddr_in addr;
struct sockaddr_in6 addr6;
Str255 dns;
char hostStr[NI_MAXHOST];
char servStr[NI_MAXSERV];
static const char *kAddrTypeNames[] = {
"unknown", "kAFPTagTypeIP", "kAFPTagTypeIPPort", "kAFPTagTypeDDP",
"kAFPTagTypeDNS", "unknown", "kAFPTagTypeIPv6", "kAFPTagTypeIPv6Port"
};
assert(offset >= 0);
addrList = (AFPAlternateAddress *) (((char *) afpXVolInfoBuffer) + offset);
assert(addrList->fVersion == 0);
thisAddr = (AFPTagData *) &addrList->fAddressList[0];
for (i = 0; i < addrList->fAddressCount; i++) {
Boolean understood;
thisAddrType = thisAddr->fType;
if (thisAddrType >= (sizeof(kAddrTypeNames) / sizeof(*kAddrTypeNames))) {
thisAddrType = 0;
}
fprintf(stdout, "%*saddr[%d].fType = %s (%" PRIu8 ")\n", (int) indent, "", i, kAddrTypeNames[thisAddrType], (uint8_t) thisAddr->fType);
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
memset(&addr6, 0, sizeof(addr6));
addr6.sin6_len = sizeof(addr6);
addr6.sin6_family = AF_INET6;
// Print the address data based on its type.
//
// IMPORTANT: This data is always big endian (because of the PowerPC
// heritage of this structure) but that's OK because the data in the
// struct sockaddr_in[6] is also big endian (because it is in network
// byte order).
understood = false;
switch (thisAddr->fType) {
case kAFPTagTypeIP:
if (thisAddr->fLength == kAFPTagLengthIP) {
memcpy(&addr.sin_addr, &thisAddr->fData[0], sizeof(addr.sin_addr));
junk = getnameinfo( (struct sockaddr *) &addr, (socklen_t) sizeof(addr), hostStr, (socklen_t) sizeof(hostStr), NULL, 0, NI_NUMERICHOST);
assert(junk == 0);
fprintf(stdout, "%*saddr[%d].fData = %s\n", (int) indent, "", i, hostStr);
understood = true;
}
break;
case kAFPTagTypeIPPort:
if (thisAddr->fLength == kAFPTagLengthIPPort) {
memcpy(&addr.sin_addr, &thisAddr->fData[0], sizeof(addr.sin_addr));
memcpy(&addr.sin_port, &thisAddr->fData[sizeof(addr.sin_addr)], sizeof(addr.sin_port));
junk = getnameinfo( (struct sockaddr *) &addr, (socklen_t) sizeof(addr), hostStr, (socklen_t) sizeof(hostStr), servStr, (socklen_t) sizeof(servStr), NI_NUMERICHOST | NI_NUMERICSERV);
assert(junk == 0);
fprintf(stdout, "%*saddr[%d].fData = %s:%s\n", (int) indent, "", i, hostStr, servStr);
understood = true;
}
break;
case kAFPTagTypeDNS:
if (thisAddr->fLength > offsetof(AFPTagData, fLength)) {
dns[0] = thisAddr->fLength - offsetof(AFPTagData, fData);
memcpy(&dns[1], &thisAddr->fData[0], dns[0]);
fprintf(stdout, "%*saddr[%d].fData = %.*s\n", (int) indent, "", i, (int) dns[0], (char *) &dns[1]);
understood = true;
}
break;
case kAFPTagTypeIPv6:
if (thisAddr->fLength == kAFPTagLengthIPv6) {
memcpy(&addr6.sin6_addr, &thisAddr->fData[0], sizeof(addr6.sin6_addr));
junk = getnameinfo( (struct sockaddr *) &addr6, (socklen_t) sizeof(addr6), hostStr, (socklen_t) sizeof(hostStr), NULL, 0, NI_NUMERICHOST);
assert(junk == 0);
fprintf(stdout, "%*saddr[%d].fData = %s\n", (int) indent, "", i, hostStr);
understood = true;
}
break;
case kAFPTagTypeIPv6Port:
if (thisAddr->fLength == kAFPTagLengthIPv6Port) {
memcpy(&addr6.sin6_addr, &thisAddr->fData[0], sizeof(addr6.sin6_addr));
memcpy(&addr6.sin6_port, &thisAddr->fData[sizeof(addr6.sin6_addr)], sizeof(addr6.sin6_port));
junk = getnameinfo( (struct sockaddr *) &addr6, (socklen_t) sizeof(addr6), hostStr, (socklen_t) sizeof(hostStr), NULL, 0, NI_NUMERICHOST);
assert(junk == 0);
fprintf(stdout, "%*saddr[%d].fData = %s\n", (int) indent, "", i, hostStr);
understood = true;
}
break;
default:
break;
}
// If we don't recognise the address type, just dump the hex.
if ( ! understood ) {
fprintf(stdout, "%*saddr[%d].fData =", (int) indent, "", i);
for (addrIndex = 0; addrIndex < ((size_t) thisAddr->fLength); addrIndex++) {
fprintf(stdout, " 0x%02x", thisAddr->fData[addrIndex]);
}
fprintf(stdout, "\n");
}
thisAddr = (AFPTagData *) ( ((char *) thisAddr) + thisAddr->fLength );
}
}
// Flags for the flags field of the VolumeMountInfoHeader.
static const FPFlagDesc kAFPFlags[] = {
{volMountExtendedFlagsMask, "volMountExtendedFlagsMask"},
{0, NULL}
};
// The fields of the VolumeMountInfoHeader structure.
static const char kVolMountInfoFieldSpacer[32] = "volInfoBuffer";
static const FPFieldDesc kVolMountInfoFieldDesc[] = {
{kVolMountInfoFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{"length", offsetof(VolumeMountInfoHeader, length), sizeof(short), FPSDec, NULL},
{"media", offsetof(VolumeMountInfoHeader, media), sizeof(VolumeType), FPSignature, (const void *) (uintptr_t) kFPValueHostEndian},
{"flags", offsetof(VolumeMountInfoHeader, flags), sizeof(short), FPFlags, kAFPFlags},
{NULL, 0, 0, NULL, NULL}
};
// The fields of the AFPVolMountInfo structure.
static const char kAFPVolMountInfoFieldSpacer[32] = "alternateAddressOffset";
static const FPFieldDesc kAFPVolMountInfoFieldDesc[] = {
{kAFPVolMountInfoFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{"nbpInterval", offsetof(AFPVolMountInfo, nbpInterval), sizeof(SInt8), FPSDec, NULL},
{"nbpCount", offsetof(AFPVolMountInfo, nbpCount), sizeof(SInt8), FPSDec, NULL},
{"uamType", offsetof(AFPVolMountInfo, uamType), sizeof(short), FPEnum, kVolMountInfoUAMType},
{"zoneNameOffset", offsetof(AFPVolMountInfo, zoneNameOffset), sizeof(short), FPAFPString, (void *) offsetof(AFPVolMountInfo, zoneNameOffset)},
{"serverNameOffset", offsetof(AFPVolMountInfo, serverNameOffset), sizeof(short), FPAFPString, (void *) offsetof(AFPVolMountInfo, serverNameOffset)},
{"volNameOffset", offsetof(AFPVolMountInfo, volNameOffset), sizeof(short), FPAFPString, (void *) offsetof(AFPVolMountInfo, volNameOffset)},
{"userNameOffset", offsetof(AFPVolMountInfo, userNameOffset), sizeof(short), FPAFPString, (void *) offsetof(AFPVolMountInfo, userNameOffset)},
{"userPasswordOffset", offsetof(AFPVolMountInfo, userPasswordOffset), sizeof(short), FPAFPString, (void *) offsetof(AFPVolMountInfo, userPasswordOffset)},
{"volPasswordOffset", offsetof(AFPVolMountInfo, volPasswordOffset), sizeof(short), FPAFPString, (void *) offsetof(AFPVolMountInfo, volPasswordOffset)},
{NULL, 0, 0, NULL, NULL}
};
// Flags for the extendedFlags field of the AFPXVolMountInfo.
static const FPFlagDesc kAFPExtendedFlags[] = {
{kAFPExtendedFlagsAlternateAddressMask, "kAFPExtendedFlagsAlternateAddressMask"},
{0, NULL}
};
// The fields of the AFPXVolMountInfo structure. These are broken up into
// two groups because the second group of fields is only present if
// kAFPExtendedFlagsAlternateAddressMask is set in extendedFlags.
static const FPFieldDesc kAFPXVolMountInfoFieldDesc[] = {
{kAFPVolMountInfoFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{"extendedFlags", offsetof(AFPXVolMountInfo, extendedFlags), sizeof(short), FPFlags, kAFPExtendedFlags},
{"uamNameOffset", offsetof(AFPXVolMountInfo, uamNameOffset), sizeof(short), FPAFPString, (void *) offsetof(AFPXVolMountInfo, uamNameOffset)},
{NULL, 0, 0, NULL, NULL}
};
static const FPFieldDesc kAFPXVolMountInfoFieldDesc2[] = {
{kAFPVolMountInfoFieldSpacer, 0, 0, FPNull, NULL}, // present to pad out field widths
{"alternateAddressOffset", offsetof(AFPXVolMountInfo, alternateAddressOffset), sizeof(short), FPSDec, NULL},
{NULL, 0, 0, NULL, NULL}
};
static void PrintVolumeMountInfo(size_t volInfoSize, VolumeMountInfoHeaderPtr volInfoBuffer, uint32_t indent, uint32_t verbose)
// Common code used to print a volume mount info buffer. Called by both
// the FSGetVolumeMountInfo and the PBGetVolMountInfo commands.
{
assert(volInfoBuffer != NULL);
assert(volInfoSize >= sizeof(*volInfoBuffer));
fprintf(stdout, "%*svolInfoSize = %zd\n", (int) indent, "", volInfoSize);
FPPrintFields(kVolMountInfoFieldDesc, volInfoBuffer, sizeof(*volInfoBuffer), indent, verbose);
// If this is an AFP volume, we know the structure of the mount info
// data, and thus we print it. Otherwise we just dump the data as hex.
if (volInfoBuffer->media == AppleShareMediaType) {
AFPVolMountInfoPtr afpVolInfoBuffer;
afpVolInfoBuffer = (AFPVolMountInfoPtr) volInfoBuffer;
fprintf(stdout, "%*sAppleShareMediaType\n", (int) indent, "");
FPPrintFields(kAFPVolMountInfoFieldDesc, afpVolInfoBuffer, sizeof(*afpVolInfoBuffer), indent + kStdIndent, verbose);
if (afpVolInfoBuffer->flags & volMountExtendedFlagsMask) {
AFPXVolMountInfoPtr afpXVolInfoBuffer;
afpXVolInfoBuffer = (AFPXVolMountInfoPtr) afpVolInfoBuffer;
FPPrintFields(kAFPXVolMountInfoFieldDesc, afpVolInfoBuffer, sizeof(*afpVolInfoBuffer), indent + kStdIndent, verbose);
if (afpXVolInfoBuffer->extendedFlags & kAFPExtendedFlagsAlternateAddressMask) {
FPPrintFields(kAFPXVolMountInfoFieldDesc2, afpVolInfoBuffer, sizeof(*afpVolInfoBuffer), indent + kStdIndent, verbose);
PrintAlternateAddresses(afpXVolInfoBuffer, afpXVolInfoBuffer->alternateAddressOffset, indent + 2 * kStdIndent);
}
}
} else {
if (verbose > 0) {
FPHex("volInfoBuffer", volInfoSize, volInfoBuffer, 4, strlen(kVolMountInfoFieldSpacer), false, NULL);
}
}
}
#if ! TARGET_RT_64_BIT
static CommandError PrintPBGetVolMountInfo(CommandArgsRef args, uint32_t indent, uint32_t verbose)
// Uses PBGetVolMountInfo to get information about the specified volume and
// prints the result.
//
// indent and verbose are as per the comments for FPPrinter.
{
OSStatus err;
FSVolumeRefNum volRefNum;
ParamBlockRec pb;
short volInfoSize;
VolumeMountInfoHeaderPtr volInfoBuffer;
assert( CommandArgsValid(args) );
volInfoBuffer = NULL;
// Get the mount info from the file system.
err = CommandArgsGetVRefNum(args, &volRefNum);
if (err == noErr) {
pb.ioParam.ioNamePtr = NULL;
pb.ioParam.ioVRefNum = volRefNum;
pb.ioParam.ioBuffer = (Ptr) &volInfoSize;
err = PBGetVolMountInfoSize(&pb);
}
if (err == noErr) {
assert(volInfoSize >= 0);
volInfoBuffer = malloc(volInfoSize);
if (volInfoBuffer == NULL) {
err = memFullErr;
}
}
if (err == noErr) {
pb.ioParam.ioBuffer = (Ptr) volInfoBuffer;
err = PBGetVolMountInfo(&pb);
}
// Print the info.
if (err == noErr) {
PrintVolumeMountInfo(volInfoSize, volInfoBuffer, indent, verbose);
}
free(volInfoBuffer);
return CommandErrorMakeWithOSStatus(err);
}
const CommandInfo kPBGetVolMountInfoCommand = {
PrintPBGetVolMountInfo,
"PBGetVolMountInfo",
"itemPath",
"Print information from PBGetVolMountInfo.",
NULL
};
#endif
static CommandError PrintFSGetVolumeMountInfo(CommandArgsRef args, uint32_t indent, uint32_t verbose)
// Uses PBGetVolMountInfo to get information about the specified volume and
// prints the result.
//
// indent and verbose are as per the comments for FPPrinter.
{
OSStatus err;
FSVolumeRefNum volRefNum;
size_t volInfoSize;
VolumeMountInfoHeaderPtr volInfoBuffer;
size_t junkSize;
assert( CommandArgsValid(args) );
if ( FSGetVolumeMountInfoSize == NULL ) {
return CommandErrorMakeWithCustom(kUnavailableCustomError);
}