FileManager C

Iniciado por ANTRAX, Mayo 22, 2011, 09:50:21 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Mayo 22, 2011, 09:50:21 PM Ultima modificación: Febrero 08, 2014, 06:07:55 PM por Expermicid
Código: c
#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);
    }