X-Git-Url: https://git.saurik.com/apple/hfs.git/blobdiff_plain/c008b8640c766dc2c747ee6c23cd99952ce58d7d..e74bfeef39406b1d74075ba0ce340588618ea58d:/hfs_util/hfsutil_main.c?ds=sidebyside diff --git a/hfs_util/hfsutil_main.c b/hfs_util/hfsutil_main.c index 738c475..15bb2d1 100644 --- a/hfs_util/hfsutil_main.c +++ b/hfs_util/hfsutil_main.c @@ -1,10 +1,10 @@ /* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the + * are subject to the Apple Public Source License Version 1.2 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. @@ -47,11 +47,15 @@ #include #include #include - -#include +#include +#include +#include #include +#include #include +#include +#include #include #include #include @@ -59,18 +63,24 @@ #include #include #include +#include -#include +/* + * CommonCrypto provides a more stable API than OpenSSL guarantees; + * the #define causes it to use the same API for MD5 and SHA1, so the rest of + * the code need not change. + */ +#define COMMON_DIGEST_FOR_OPENSSL +#include -#define READ_DEFAULT_ENCODING 1 +#include -#ifndef FSUR_MOUNT_HIDDEN -#define FSUR_MOUNT_HIDDEN (-9) -#endif +#include -#ifndef FSUC_GETKEY -#define FSUC_GETKEY 'k' -#endif +#include +#include + +#define READ_DEFAULT_ENCODING 1 #ifndef FSUC_ADOPT #define FSUC_ADOPT 'a' @@ -80,11 +90,30 @@ #define FSUC_DISOWN 'd' #endif -#ifndef FSUC_NEWUUID -#define FSUC_NEWUUID 'n' +#ifndef FSUC_GETUUID +#define FSUC_GETUUID 'k' #endif +#ifndef FSUC_SETUUID +#define FSUC_SETUUID 's' +#endif +#ifndef FSUC_MKJNL +#define FSUC_MKJNL 'J' +#endif + +#ifndef FSUC_UNJNL +#define FSUC_UNJNL 'U' +#endif + +#ifndef FSUC_UNJNL_RAW +#define FSUC_UNJNL_RAW 'N' +#endif + +#ifndef FSUC_JNLINFO +#define FSUC_JNLINFO 'I' +#endif + /* **************************************** L O C A L S ******************************************* */ @@ -93,7 +122,6 @@ char gHFS_FS_NAME[] = "hfs"; char gHFS_FS_NAME_NAME[] = "HFS"; -char gFS_UUID_SUFFIX[] = ".uuid"; char gNewlineString[] = "\n"; char gMountCommand[] = "/sbin/mount"; @@ -114,10 +142,18 @@ char gIgnorePermissionsOption[] = "noperm"; boolean_t gIsEjectable = 0; +int gJournalSize = 0; + #define AUTO_ADOPT_FIXED 1 #define AUTO_ENTER_FIXED 0 +struct FinderAttrBuf { + unsigned long info_length; + unsigned long finderinfo[8]; +}; + + #define VOLUMEUUIDVALUESIZE 2 typedef union VolumeUUID { unsigned long value[VOLUMEUUIDVALUESIZE]; @@ -139,7 +175,6 @@ typedef void *VolumeStatusDBHandle; void GenerateVolumeUUID(VolumeUUID *newVolumeID); void ConvertVolumeUUIDStringToUUID(const char *UUIDString, VolumeUUID *volumeID); void ConvertVolumeUUIDToString(VolumeUUID *volumeID, char *UUIDString); - int OpenVolumeStatusDB(VolumeStatusDBHandle *DBHandlePtr); int GetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, unsigned long *VolumeStatus); int SetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, unsigned long VolumeStatus); @@ -147,9 +182,7 @@ int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeI int CloseVolumeStatusDB(VolumeStatusDBHandle DBHandle); /* ************************************ P R O T O T Y P E S *************************************** */ - static void DoDisplayUsage( const char * argv[] ); -static void DoFileSystemFile( char * theFileNameSuffixPtr, char * theContentsPtr ); static int DoMount( char * theDeviceNamePtr, const char * theMountPointPtr, boolean_t isLocked, boolean_t isSetuid, boolean_t isDev ); static int DoProbe( char * theDeviceNamePtr ); static int DoUnmount( const char * theMountPointPtr ); @@ -157,20 +190,44 @@ static int DoGetUUIDKey( const char * theDeviceNamePtr ); static int DoChangeUUIDKey( const char * theDeviceNamePtr ); static int DoAdopt( const char * theDeviceNamePtr ); static int DoDisown( const char * theDeviceNamePtr ); + +extern int DoMakeJournaled( const char * volNamePtr, int journalSize ); // XXXdbg +extern int DoUnJournal( const char * volNamePtr ); // XXXdbg +extern int DoGetJournalInfo( const char * volNamePtr ); +extern int RawDisableJournaling( const char *devname ); + static int ParseArgs( int argc, const char * argv[], const char ** actionPtr, const char ** mountPointPtr, boolean_t * isEjectablePtr, boolean_t * isLockedPtr, boolean_t * isSetuidPtr, boolean_t * isDevPtr ); +static int GetHFSMountPoint(const char *deviceNamePtr, char **pathPtr); +static int ReadHeaderBlock(int fd, void *bufptr, off_t *startOffset, VolumeUUID **finderInfoUUIDPtr); +static int GetVolumeUUIDRaw(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr); +static int GetVolumeUUIDAttr(const char *path, VolumeUUID *volumeUUIDPtr); static int GetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr, boolean_t generate); +static int SetVolumeUUIDRaw(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr); +static int SetVolumeUUIDAttr(const char *path, VolumeUUID *volumeUUIDPtr); static int SetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr); static int GetEmbeddedHFSPlusVol(HFSMasterDirectoryBlock * hfsMasterDirectoryBlockPtr, off_t * startOffsetPtr); -static int GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * name_o); -static int GetBTreeNodeInfo(int fd, off_t btreeOffset, u_int32_t *nodeSize, u_int32_t *firstLeafNode); -static off_t CalcLeafNodeOffset(off_t fileOffset, u_int32_t blockSize, u_int32_t extentCount, - HFSPlusExtentDescriptor *extentList); +static int GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, unsigned char * name_o); +static int GetBTreeNodeInfo(int fd, off_t hfsPlusVolumeOffset, u_int32_t blockSize, + u_int32_t extentCount, const HFSPlusExtentDescriptor *extentList, + u_int32_t *nodeSize, u_int32_t *firstLeafNode); static int GetCatalogOverflowExtents(int fd, off_t hfsPlusVolumeOffset, HFSPlusVolumeHeader *volHdrPtr, HFSPlusExtentDescriptor **catalogExtents, u_int32_t *catalogExtCount); +static int LogicalToPhysical(off_t logicalOffset, ssize_t length, u_int32_t blockSize, + u_int32_t extentCount, const HFSPlusExtentDescriptor *extentList, + off_t *physicalOffset, ssize_t *availableBytes); +static int ReadFile(int fd, void *buffer, off_t offset, ssize_t length, + off_t volOffset, u_int32_t blockSize, + u_int32_t extentCount, const HFSPlusExtentDescriptor *extentList); static ssize_t readAt( int fd, void * buf, off_t offset, ssize_t length ); static ssize_t writeAt( int fd, void * buf, off_t offset, ssize_t length ); +static int GetEncodingBias(void); + + +CF_EXPORT Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, UInt8 *buffer, CFIndex maxBufLen); + +static void uuid_create_md5_from_name(uuid_t result_uuid, const uuid_t namespace, const void *name, int namelen); /* * The fuction CFStringGetSystemEncoding does not work correctly in @@ -203,6 +260,119 @@ static unsigned int __CFStringGetDefaultEncodingForHFSUtil() { } #endif + +#define MXENCDNAMELEN 16 /* Maximun length of encoding name string */ + +struct hfs_mnt_encoding { + char encoding_name[MXENCDNAMELEN]; /* encoding type name */ + CFStringEncoding encoding_id; /* encoding type number */ +}; + +static struct hfs_mnt_encoding hfs_mnt_encodinglist[] = { + { "Arabic", 4 }, + { "Armenian", 24 }, + { "Bengali", 13 }, + { "Burmese", 19 }, + { "Celtic", 39 }, + { "CentralEurRoman", 29 }, + { "ChineseSimp", 25 }, + { "ChineseTrad", 2 }, + { "Croatian", 36 }, + { "Cyrillic", 7 }, + { "Devanagari", 9 }, + { "Ethiopic", 28 }, + { "Farsi", 140 }, + { "Gaelic", 40 }, + { "Georgian", 23 }, + { "Greek", 6 }, + { "Gujarati", 11 }, + { "Gurmukhi", 10 }, + { "Hebrew", 5 }, + { "Icelandic", 37 }, + { "Japanese", 1 }, + { "Kannada", 16 }, + { "Khmer", 20 }, + { "Korean", 3 }, + { "Laotian", 22 }, + { "Malayalam", 17 }, + { "Mongolian", 27 }, + { "Oriya", 12 }, + { "Roman", 0 }, /* default */ + { "Romanian", 38 }, + { "Sinhalese", 18 }, + { "Tamil", 14 }, + { "Telugu", 15 }, + { "Thai", 21 }, + { "Tibetan", 26 }, + { "Turkish", 35 }, + { "Ukrainian", 152 }, + { "Vietnamese", 30 }, +}; + +#define KEXT_LOAD_COMMAND "/sbin/kextload" +#define ENCODING_MODULE_PATH "/System/Library/Filesystems/hfs.fs/Encodings/" + +static int load_encoding(CFStringEncoding encoding) +{ + int i; + int numEncodings; + int pid; + char *encodingName; + struct stat sb; + union wait status; + char kmodfile[MAXPATHLEN]; + + /* Find the encoding that matches the one passed in */ + numEncodings = sizeof(hfs_mnt_encodinglist) / sizeof(struct hfs_mnt_encoding); + encodingName = NULL; + for (i=0; idrSigWord == kHFSSigWord && - mdbPtr->drEmbedSigWord != kHFSPlusSigWord) { + if (OSSwapBigToHostInt16(mdbPtr->drSigWord) == kHFSSigWord && + OSSwapBigToHostInt16(mdbPtr->drEmbedSigWord) != kHFSPlusSigWord) { Boolean cfOK; CFStringRef cfstr; CFStringEncoding encoding; - encoding = CFStringGetSystemEncoding(); + /* Some poorly mastered HFS CDs have an empty MDB name field! */ + if (mdbPtr->drVN[0] == '\0') { + strcpy((char *)&mdbPtr->drVN[1], gHFS_FS_NAME_NAME); + mdbPtr->drVN[0] = strlen(gHFS_FS_NAME_NAME); + } + + /* Check for an encoding hint in the Finder Info (field 4). */ + encoding = GET_HFS_TEXT_ENCODING(OSSwapBigToHostInt32(mdbPtr->drFndrInfo[4])); + if (encoding == kCFStringEncodingInvalidId) { + /* Next try the encoding bias in the kernel. */ + encoding = GetEncodingBias(); + if (encoding == 0 || encoding == kCFStringEncodingInvalidId) + encoding = __CFStringGetDefaultEncodingForHFSUtil(); + } + cfstr = CFStringCreateWithPascalString(kCFAllocatorDefault, mdbPtr->drVN, encoding); - cfOK = CFStringGetCString(cfstr, volnameUTF8, NAME_MAX, - kCFStringEncodingUTF8); + cfOK = _CFStringGetFileSystemRepresentation(cfstr, volnameUTF8, NAME_MAX); CFRelease(cfstr); if (!cfOK && encoding != kCFStringEncodingMacRoman) { @@ -531,23 +726,35 @@ DoProbe(char *deviceNamePtr) /* default to MacRoman on conversion errors */ cfstr = CFStringCreateWithPascalString(kCFAllocatorDefault, mdbPtr->drVN, kCFStringEncodingMacRoman); - CFStringGetCString(cfstr, volnameUTF8, NAME_MAX, - kCFStringEncodingUTF8); + _CFStringGetFileSystemRepresentation(cfstr, volnameUTF8, NAME_MAX); CFRelease(cfstr); + encoding = kCFStringEncodingMacRoman; } + /* Preload the encoding converter so mount_hfs can run as an ordinary user. */ + if (encoding != kCFStringEncodingMacRoman) { + if (load_encoding(encoding) != FSUR_IO_SUCCESS) { + encoding = kCFStringEncodingMacRoman; + cfstr = CFStringCreateWithPascalString(kCFAllocatorDefault, mdbPtr->drVN, encoding); + _CFStringGetFileSystemRepresentation(cfstr, volnameUTF8, NAME_MAX); + CFRelease(cfstr); + } + } + /* get HFS Plus volume name (from Catalog) */ - } else if ((volHdrPtr->signature == kHFSPlusSigWord) || - (mdbPtr->drSigWord == kHFSSigWord && - mdbPtr->drEmbedSigWord == kHFSPlusSigWord)) { + } else if ((OSSwapBigToHostInt16(volHdrPtr->signature) == kHFSPlusSigWord) || + (OSSwapBigToHostInt16(volHdrPtr->signature) == kHFSXSigWord) || + (OSSwapBigToHostInt16(mdbPtr->drSigWord) == kHFSSigWord && + OSSwapBigToHostInt16(mdbPtr->drEmbedSigWord) == kHFSPlusSigWord)) { off_t startOffset; - if (volHdrPtr->signature == kHFSPlusSigWord) { - startOffset = 0; - } else {/* embedded volume, first find offset */ + if (OSSwapBigToHostInt16(volHdrPtr->signature) == kHFSSigWord) { + /* embedded volume, first find offset */ result = GetEmbeddedHFSPlusVol(mdbPtr, &startOffset); if ( result != FSUR_IO_SUCCESS ) goto Return; + } else { + startOffset = 0; } result = GetNameFromHFSPlusVolumeStartingAt(fd, startOffset, @@ -557,43 +764,17 @@ DoProbe(char *deviceNamePtr) } if (FSUR_IO_SUCCESS == result) { - CFStringRef slash; - CFStringRef colon; - CFMutableStringRef volumeName; - CFIndex volumeNameLength; - CFRange foundSubString; - - slash = CFStringCreateWithCString(kCFAllocatorDefault, "/", kCFStringEncodingUTF8); - if (slash == NULL) { - result = FSUR_IO_FAIL; - goto Return; - }; + unsigned char *s; - colon = CFStringCreateWithCString(kCFAllocatorDefault, ":", kCFStringEncodingUTF8); - if (colon == NULL) { - result = FSUR_IO_FAIL; - goto Return; - }; - - volumeName = CFStringCreateMutableCopy( - kCFAllocatorDefault, - 0, /* maxLength */ - CFStringCreateWithCString(kCFAllocatorDefault, volnameUTF8, kCFStringEncodingUTF8)); - if (volumeName == NULL) { - result = FSUR_IO_FAIL; - goto Return; - }; - volumeNameLength = CFStringGetLength(volumeName); - - while (CFStringFindWithOptions(volumeName, slash, CFRangeMake(0, volumeNameLength-1), 0, &foundSubString)) { - CFStringReplace(volumeName, foundSubString, colon); - }; - - CFStringGetCString(volumeName, volnameUTF8, NAME_MAX, kCFStringEncodingUTF8); + /* Change slashes to colons in the volume name */ + for (s=volnameUTF8; *s; ++s) { + if (*s == '/') + *s = ':'; + } - DoFileSystemFile( FS_NAME_SUFFIX, gHFS_FS_NAME_NAME ); - DoFileSystemFile( FS_LABEL_SUFFIX, volnameUTF8 ); - result = FSUR_MOUNT_HIDDEN; + /* Print the volume name to standard output */ + write(1, volnameUTF8, strlen((char *)volnameUTF8)); + result = FSUR_RECOGNIZED; } Return: @@ -608,11 +789,34 @@ Return: } /* DoProbe */ +/* + * Create a version 3 UUID from a unique "name" in the given "name space". + * Version 3 UUID are derived using "name" via MD5 checksum. + * + * Parameters: + * result_uuid - resulting UUID. + * namespace - namespace in which given name exists and UUID should be created. + * name - unique string used to create version 3 UUID. + * namelen - length of the name string. + */ +static void +uuid_create_md5_from_name(uuid_t result_uuid, const uuid_t namespace, const void *name, int namelen) +{ + MD5_CTX c; + + MD5_Init(&c); + MD5_Update(&c, namespace, sizeof(uuid_t)); + MD5_Update(&c, name, namelen); + MD5_Final(result_uuid, &c); + + result_uuid[6] = (result_uuid[6] & 0x0F) | 0x30; + result_uuid[8] = (result_uuid[8] & 0x3F) | 0x80; +} /* **************************************** DoGetUUIDKey ******************************************* Purpose - - This routine will open the given block device and return the volume UUID in text form. + This routine will open the given block device and return the 128-bit volume UUID in text form written to stdout. Input - theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2). Output - @@ -622,15 +826,19 @@ static int DoGetUUIDKey( const char * theDeviceNamePtr ) { int result; VolumeUUID targetVolumeUUID; - VolumeUUIDString UUIDString; - char uuidLine[VOLUMEUUIDLENGTH+2]; - + uuid_t uuid; + char uuidLine[40]; + + unsigned char rawUUID[8]; + if ((result = GetVolumeUUID(theDeviceNamePtr, &targetVolumeUUID, FALSE)) != FSUR_IO_SUCCESS) goto Err_Exit; - - ConvertVolumeUUIDToString( &targetVolumeUUID, UUIDString); - strncpy(uuidLine, UUIDString, VOLUMEUUIDLENGTH+1); - strcat(uuidLine, gNewlineString); - DoFileSystemFile( gFS_UUID_SUFFIX, uuidLine ); + + ((uint32_t *)rawUUID)[0] = OSSwapHostToBigInt32(targetVolumeUUID.v.high); + ((uint32_t *)rawUUID)[1] = OSSwapHostToBigInt32(targetVolumeUUID.v.low); + + uuid_create_md5_from_name(uuid, kFSUUIDNamespaceSHA1, rawUUID, sizeof(rawUUID)); + uuid_unparse(uuid, uuidLine); + write(1, uuidLine, strlen(uuidLine)); result = FSUR_IO_SUCCESS; Err_Exit: @@ -680,7 +888,7 @@ DoAdopt( const char * theDeviceNamePtr ) { if ((result = OpenVolumeStatusDB(&vsdbhandle)) != 0) goto Err_Exit; if ((result = GetVolumeStatusDBEntry(vsdbhandle, &targetVolumeUUID, &targetVolumeStatus)) != 0) { targetVolumeStatus = 0; - }; + } targetVolumeStatus = (targetVolumeStatus & VOLUME_VALIDSTATUSBITS) | VOLUME_USEPERMISSIONS; if ((result = SetVolumeStatusDBEntry(vsdbhandle, &targetVolumeUUID, targetVolumeStatus)) != 0) goto Err_Exit; @@ -691,7 +899,7 @@ Err_Exit: closeresult = CloseVolumeStatusDB(vsdbhandle); vsdbhandle = NULL; if (result == FSUR_IO_SUCCESS) result = closeresult; - }; + } if ((result != 0) && (result != FSUR_IO_SUCCESS)) result = FSUR_IO_FAIL; @@ -724,7 +932,7 @@ DoDisown( const char * theDeviceNamePtr ) { if ((result = OpenVolumeStatusDB(&vsdbhandle)) != 0) goto Err_Exit; if ((result = GetVolumeStatusDBEntry(vsdbhandle, &targetVolumeUUID, &targetVolumeStatus)) != 0) { targetVolumeStatus = 0; - }; + } targetVolumeStatus = (targetVolumeStatus & VOLUME_VALIDSTATUSBITS) & ~VOLUME_USEPERMISSIONS; if ((result = SetVolumeStatusDBEntry(vsdbhandle, &targetVolumeUUID, targetVolumeStatus)) != 0) goto Err_Exit; @@ -735,14 +943,14 @@ Err_Exit: closeresult = CloseVolumeStatusDB(vsdbhandle); vsdbhandle = NULL; if (result == FSUR_IO_SUCCESS) result = closeresult; - }; + } if ((result != 0) && (result != FSUR_IO_SUCCESS)) { #if TRACE_HFS_UTIL if (result != 0) fprintf(stderr, "DoDisown: result = %d; changing to %d...\n", result, FSUR_IO_FAIL); #endif result = FSUR_IO_FAIL; - }; + } Err_Return: #if TRACE_HFS_UTIL @@ -752,6 +960,19 @@ Err_Return: } +static int +get_multiplier(char c) +{ + if (tolower(c) == 'k') { + return 1024; + } else if (tolower(c) == 'm') { + return 1024 * 1024; + } else if (tolower(c) == 'g') { + return 1024 * 1024 * 1024; + } + + return 1; +} /* **************************************** ParseArgs ******************************************** Purpose - @@ -779,6 +1000,7 @@ flagsArg: either "readonly" OR "writable" either "removable" OR "fixed" either "nosuid" or "suid" + either "nodev" or "dev" examples: hfs.util -p disk0s2 removable writable @@ -797,7 +1019,7 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, boolean_t * isLockedPtr, boolean_t * isSetuidPtr, boolean_t * isDevPtr) { int result = FSUR_INVAL; - int deviceLength; + int deviceLength, doLengthCheck = 1; int index; int mounting = 0; @@ -830,8 +1052,8 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, case FSUC_MOUNT: case FSUC_MOUNT_FORCE: - /* action Mount and ForceMount require 7 arguments (need the mountpoint and the flags) */ - if ( argc < 7 ) { + /* action Mount and ForceMount require 8 arguments (need the mountpoint and the flags) */ + if ( argc < 8 ) { DoDisplayUsage( argv ); goto Return; } else { @@ -841,11 +1063,11 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, } break; - case FSUC_GETKEY: + case FSUC_GETUUID: index = 0; break; - case FSUC_NEWUUID: + case FSUC_SETUUID: index = 0; break; @@ -857,6 +1079,36 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, index = 0; break; + // XXXdbg + case FSUC_MKJNL: + index = 0; + doLengthCheck = 0; + if (isdigit(argv[2][0])) { + char *ptr; + gJournalSize = strtoul(argv[2], &ptr, 0); + if (ptr) { + gJournalSize *= get_multiplier(*ptr); + } + return 0; + } + break; + + case FSUC_UNJNL: + index = 0; + doLengthCheck = 0; + break; + + case FSUC_UNJNL_RAW: + index = 0; + doLengthCheck = 0; + break; + + case FSUC_JNLINFO: + index = 0; + doLengthCheck = 0; + break; + // XXXdbg + default: DoDisplayUsage( argv ); goto Return; @@ -865,7 +1117,7 @@ ParseArgs(int argc, const char *argv[], const char ** actionPtr, /* Make sure device (argv[2]) is something reasonable */ deviceLength = strlen( argv[2] ); - if ( deviceLength < 3 || deviceLength > 10 ) { + if ( doLengthCheck && (deviceLength < 3 || deviceLength > NAME_MAX) ) { DoDisplayUsage( argv ); goto Return; } @@ -937,82 +1189,155 @@ DoDisplayUsage(const char *argv[]) printf(" -%c (Mount)\n", FSUC_MOUNT); printf(" -%c (Unmount)\n", FSUC_UNMOUNT); printf(" -%c (Force Mount)\n", FSUC_MOUNT_FORCE); - printf(" -%c (Get UUID Key)\n", FSUC_GETKEY); - printf(" -%c (New UUID Key)\n", FSUC_NEWUUID); +#ifdef HFS_UUID_SUPPORT + printf(" -%c (Get UUID Key)\n", FSUC_GETUUID); + printf(" -%c (Set UUID Key)\n", FSUC_SETUUID); +#endif HFS_UUID_SUPPORT printf(" -%c (Adopt permissions)\n", FSUC_ADOPT); + printf(" -%c (Make a file system journaled)\n", FSUC_MKJNL); + printf(" -%c (Turn off journaling on a file system)\n", FSUC_UNJNL); + printf(" -%c (Turn off journaling on a raw device)\n", FSUC_UNJNL_RAW); + printf(" -%c (Get size & location of journaling on a file system)\n", FSUC_JNLINFO); printf("device_arg:\n"); printf(" device we are acting upon (for example, 'disk0s2')\n"); + printf(" if '-%c' or '-%c' is specified, this should be the\n", FSUC_MKJNL, FSUC_UNJNL); + printf(" name of the file system we're to act on (for example, '/Volumes/foo' or '/')\n"); printf("mount_point_arg:\n"); printf(" required for Mount and Force Mount \n"); printf("Flags:\n"); printf(" required for Mount, Force Mount and Probe\n"); printf(" indicates removable or fixed (for example 'fixed')\n"); printf(" indicates readonly or writable (for example 'readonly')\n"); + printf(" indicates suid or nosuid (for example 'suid')\n"); + printf(" indicates dev or nodev (for example 'dev')\n"); printf("Examples:\n"); printf(" %s -p disk0s2 fixed writable\n", argv[0]); - printf(" %s -m disk0s2 /my/hfs removable readonly\n", argv[0]); + printf(" %s -m disk0s2 /my/hfs removable readonly nosuid nodev\n", argv[0]); return; } /* DoDisplayUsage */ -/* ************************************** DoFileSystemFile ******************************************* -Purpose - - This routine will create a file system info file that is used by WorkSpace. After creating the - file it will write whatever theContentsPtr points to the new file. - We end up with a file something like: - /System/Library/Filesystems/hfs.fs/hfs.name - when our file system name is "hfs" and theFileNameSuffixPtr points to ".name" -Input - - theFileNameSuffixPtr - pointer to a suffix we add to the file name we're creating. - theContentsPtr - pointer to C string to write into the file. -Output - - NA. -*************************************************************************************************** */ -static void -DoFileSystemFile(char *fileNameSuffixPtr, char *contentsPtr) +/* + GetHFSMountPoint + + Given a path to a device, determine if a volume is mounted on that + device. If there is an HFS volume, return its path and FSUR_IO_SUCCESS. + If there is a non-HFS volume, return FSUR_UNRECOGNIZED. If there is + no volume mounted on the device, set *pathPtr to NULL and return + FSUR_IO_SUCCESS. + + Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL, FSUR_UNRECOGNIZED +*/ +static int +GetHFSMountPoint(const char *deviceNamePtr, char **pathPtr) { - int fd; - char fileName[MAXPATHLEN]; - - sprintf(fileName, "%s/%s%s/%s", FS_DIR_LOCATION, gHFS_FS_NAME, - FS_DIR_SUFFIX, gHFS_FS_NAME ); - strcat(fileName, fileNameSuffixPtr ); - unlink(fileName); /* delete existing string */ - - if ( strlen( fileNameSuffixPtr ) ) { - int oldMask = umask(0); - - fd = open( & fileName[0], O_CREAT | O_TRUNC | O_WRONLY, 0644 ); - umask( oldMask ); - if ( fd > 0 ) { - write( fd, contentsPtr, strlen( contentsPtr ) ); - close( fd ); - } else { - perror( fileName ); - } - } + int result; + int i, numMounts; + struct statfs *buf; + + /* Assume no mounted volume found */ + *pathPtr = NULL; + result = FSUR_IO_SUCCESS; + + numMounts = getmntinfo(&buf, MNT_NOWAIT); + if (numMounts == 0) + return FSUR_IO_FAIL; + + for (i=0; idrSigWord) == kHFSSigWord && + OSSwapBigToHostInt16(mdbPtr->drEmbedSigWord) == kHFSPlusSigWord) { + result = GetEmbeddedHFSPlusVol(mdbPtr, startOffset); + if (result != FSUR_IO_SUCCESS) + goto Err_Exit; + result = readAt(fd, bufPtr, *startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); + if (result != FSUR_IO_SUCCESS) + goto Err_Exit; + } + + /* + * At this point, we have the MDB for plain HFS, or VHB for HFS Plus and HFSX + * volumes (including wrapped HFS Plus). Verify the signature and grab the + * UUID from the Finder Info. + */ + if (OSSwapBigToHostInt16(mdbPtr->drSigWord) == kHFSSigWord) { + *finderInfoUUIDPtr = (VolumeUUID *)(&mdbPtr->drFndrInfo[6]); + } else if (OSSwapBigToHostInt16(volHdrPtr->signature) == kHFSPlusSigWord || + OSSwapBigToHostInt16(volHdrPtr->signature) == kHFSXSigWord) { + *finderInfoUUIDPtr = (VolumeUUID *)&volHdrPtr->finderInfo[24]; + } else { + result = FSUR_UNRECOGNIZED; + } +Err_Exit: + return result; +} /* - -- GetVolumeUUID - -- - -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL - */ + GetVolumeUUIDRaw + + Read the UUID from an unmounted volume, by doing direct access to the device. + Assumes the caller has already determined that a volume is not mounted + on the device. + Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL, FSUR_UNRECOGNIZED +*/ static int -GetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr, boolean_t generate) { +GetVolumeUUIDRaw(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr) +{ int fd = 0; char * bufPtr; - HFSMasterDirectoryBlock * mdbPtr; - HFSPlusVolumeHeader * volHdrPtr; + off_t startOffset; VolumeUUID *finderInfoUUIDPtr; int result; @@ -1022,185 +1347,290 @@ GetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr, boolean_t ge goto Err_Exit; } - mdbPtr = (HFSMasterDirectoryBlock *) bufPtr; - volHdrPtr = (HFSPlusVolumeHeader *) bufPtr; - - fd = open( deviceNamePtr, O_RDWR, 0 ); - if( fd <= 0 ) { - fd = open( deviceNamePtr, O_RDONLY, 0); - if (fd <= 0) { + fd = open( deviceNamePtr, O_RDONLY, 0); + if (fd <= 0) { #if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: GetVolumeUUID: device open failed (errno = %d).\n", errno); + fprintf(stderr, "hfs.util: GetVolumeUUIDRaw: device open failed (errno = %d).\n", errno); #endif - result = FSUR_IO_FAIL; - goto Err_Exit; - }; - }; + result = FSUR_IO_FAIL; + goto Err_Exit; + } /* - * Read the HFS Master Directory Block from sector 2 + * Get the pointer to the volume UUID in the Finder Info */ - result = readAt(fd, volHdrPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); - if (result != FSUR_IO_SUCCESS) { + result = ReadHeaderBlock(fd, bufPtr, &startOffset, &finderInfoUUIDPtr); + if (result != FSUR_IO_SUCCESS) goto Err_Exit; - }; - - if (mdbPtr->drSigWord == kHFSSigWord && - mdbPtr->drEmbedSigWord != kHFSPlusSigWord) { - finderInfoUUIDPtr = (VolumeUUID *)(&mdbPtr->drFndrInfo[6]); - if (generate && ((finderInfoUUIDPtr->v.high == 0) || (finderInfoUUIDPtr->v.low == 0))) { - GenerateVolumeUUID(volumeUUIDPtr); - bcopy(volumeUUIDPtr, finderInfoUUIDPtr, sizeof(*finderInfoUUIDPtr)); - result = writeAt(fd, volHdrPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); - if (result != FSUR_IO_SUCCESS) goto Err_Exit; - }; - bcopy(finderInfoUUIDPtr, volumeUUIDPtr, sizeof(*volumeUUIDPtr)); - result = FSUR_IO_SUCCESS; - } else if ((volHdrPtr->signature == kHFSPlusSigWord) || - ((mdbPtr->drSigWord == kHFSSigWord) && - (mdbPtr->drEmbedSigWord == kHFSPlusSigWord))) { - off_t startOffset; - if (volHdrPtr->signature == kHFSPlusSigWord) { - startOffset = 0; - } else {/* embedded volume, first find offset */ - result = GetEmbeddedHFSPlusVol(mdbPtr, &startOffset); - if ( result != FSUR_IO_SUCCESS ) { - goto Err_Exit; - }; - } - - result = readAt( fd, volHdrPtr, startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE ); - if (result != FSUR_IO_SUCCESS) { - goto Err_Exit; // return FSUR_IO_FAIL - } - - /* Verify that it is an HFS+ volume. */ + /* + * Copy the volume UUID out of the Finder Info + */ + volumeUUIDPtr->v.high = OSSwapBigToHostInt32(finderInfoUUIDPtr->v.high); + volumeUUIDPtr->v.low = OSSwapBigToHostInt32(finderInfoUUIDPtr->v.low); + +Err_Exit: + if (fd > 0) close(fd); + if (bufPtr) free(bufPtr); - if (volHdrPtr->signature != kHFSPlusSigWord) { - result = FSUR_IO_FAIL; - goto Err_Exit; - } +#if TRACE_HFS_UTIL + if (result != FSUR_IO_SUCCESS) fprintf(stderr, "hfs.util: GetVolumeUUIDRaw: result = %d...\n", result); +#endif + return (result == FSUR_IO_SUCCESS) ? FSUR_IO_SUCCESS : FSUR_IO_FAIL; +} + + +/* + SetVolumeUUIDRaw - finderInfoUUIDPtr = (VolumeUUID *)&volHdrPtr->finderInfo[24]; - if (generate && ((finderInfoUUIDPtr->v.high == 0) || (finderInfoUUIDPtr->v.low == 0))) { - GenerateVolumeUUID(volumeUUIDPtr); - bcopy(volumeUUIDPtr, finderInfoUUIDPtr, sizeof(*finderInfoUUIDPtr)); - result = writeAt( fd, volHdrPtr, startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE ); - if (result != FSUR_IO_SUCCESS) { - goto Err_Exit; - }; - }; - bcopy(finderInfoUUIDPtr, volumeUUIDPtr, sizeof(*volumeUUIDPtr)); - result = FSUR_IO_SUCCESS; - } else { + Write a previously generated UUID to an unmounted volume, by doing direct + access to the device. Assumes the caller has already determined that a + volume is not mounted on the device. + + Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL, FSUR_UNRECOGNIZED +*/ +static int +SetVolumeUUIDRaw(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr) +{ + int fd = 0; + char * bufPtr; + off_t startOffset; + VolumeUUID *finderInfoUUIDPtr; + int result; + + bufPtr = (char *)malloc(HFS_BLOCK_SIZE); + if ( ! bufPtr ) { result = FSUR_UNRECOGNIZED; - }; + goto Err_Exit; + } + + fd = open( deviceNamePtr, O_RDWR, 0); + if (fd <= 0) { +#if TRACE_HFS_UTIL + fprintf(stderr, "hfs.util: SetVolumeUUIDRaw: device open failed (errno = %d).\n", errno); +#endif + result = FSUR_IO_FAIL; + goto Err_Exit; + } + + /* + * Get the pointer to the volume UUID in the Finder Info + */ + result = ReadHeaderBlock(fd, bufPtr, &startOffset, &finderInfoUUIDPtr); + if (result != FSUR_IO_SUCCESS) + goto Err_Exit; + + /* + * Update the UUID in the Finder Info + */ + finderInfoUUIDPtr->v.high = OSSwapHostToBigInt32(volumeUUIDPtr->v.high); + finderInfoUUIDPtr->v.low = OSSwapHostToBigInt32(volumeUUIDPtr->v.low); + + /* + * Write the modified MDB or VHB back to disk + */ + result = writeAt(fd, bufPtr, startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); Err_Exit: if (fd > 0) close(fd); if (bufPtr) free(bufPtr); #if TRACE_HFS_UTIL - if (result != FSUR_IO_SUCCESS) fprintf(stderr, "hfs.util: GetVolumeUUID: result = %d...\n", result); + if (result != FSUR_IO_SUCCESS) fprintf(stderr, "hfs.util: SetVolumeUUIDRaw: result = %d...\n", result); #endif return (result == FSUR_IO_SUCCESS) ? FSUR_IO_SUCCESS : FSUR_IO_FAIL; -}; +} + + +/* + GetVolumeUUIDAttr + + Read the UUID from a mounted volume, by calling getattrlist(). + Assumes the path is the mount point of an HFS volume. + + Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL +*/ +static int +GetVolumeUUIDAttr(const char *path, VolumeUUID *volumeUUIDPtr) +{ + struct attrlist alist; + struct FinderAttrBuf volFinderInfo; + VolumeUUID *finderInfoUUIDPtr; + int result; + /* Set up the attrlist structure to get the volume's Finder Info */ + alist.bitmapcount = 5; + alist.reserved = 0; + alist.commonattr = ATTR_CMN_FNDRINFO; + alist.volattr = ATTR_VOL_INFO; + alist.dirattr = 0; + alist.fileattr = 0; + alist.forkattr = 0; + + /* Get the Finder Info */ + result = getattrlist(path, &alist, &volFinderInfo, sizeof(volFinderInfo), 0); + if (result) { + result = FSUR_IO_FAIL; + goto Err_Exit; + } + + /* Copy the UUID from the Finder Into to caller's buffer */ + finderInfoUUIDPtr = (VolumeUUID *)(&volFinderInfo.finderinfo[6]); + volumeUUIDPtr->v.high = OSSwapBigToHostInt32(finderInfoUUIDPtr->v.high); + volumeUUIDPtr->v.low = OSSwapBigToHostInt32(finderInfoUUIDPtr->v.low); + result = FSUR_IO_SUCCESS; + +Err_Exit: + return result; +} /* - -- SetVolumeUUID - -- - -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL - */ + SetVolumeUUIDAttr + + Write a UUID to a mounted volume, by calling setattrlist(). + Assumes the path is the mount point of an HFS volume. + Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL +*/ static int -SetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr) { - int fd = 0; - char * bufPtr; - HFSMasterDirectoryBlock * mdbPtr; - HFSPlusVolumeHeader * volHdrPtr; +SetVolumeUUIDAttr(const char *path, VolumeUUID *volumeUUIDPtr) +{ + struct attrlist alist; + struct FinderAttrBuf volFinderInfo; VolumeUUID *finderInfoUUIDPtr; int result; - bufPtr = (char *)malloc(HFS_BLOCK_SIZE); - if ( ! bufPtr ) { - result = FSUR_UNRECOGNIZED; + /* Set up the attrlist structure to get the volume's Finder Info */ + alist.bitmapcount = 5; + alist.reserved = 0; + alist.commonattr = ATTR_CMN_FNDRINFO; + alist.volattr = ATTR_VOL_INFO; + alist.dirattr = 0; + alist.fileattr = 0; + alist.forkattr = 0; + + /* Get the Finder Info */ + result = getattrlist(path, &alist, &volFinderInfo, sizeof(volFinderInfo), 0); + if (result) { + result = FSUR_IO_FAIL; goto Err_Exit; } - mdbPtr = (HFSMasterDirectoryBlock *) bufPtr; - volHdrPtr = (HFSPlusVolumeHeader *) bufPtr; + /* Update the UUID in the Finder Info */ + finderInfoUUIDPtr = (VolumeUUID *)(&volFinderInfo.finderinfo[6]); + finderInfoUUIDPtr->v.high = OSSwapHostToBigInt32(volumeUUIDPtr->v.high); + finderInfoUUIDPtr->v.low = OSSwapHostToBigInt32(volumeUUIDPtr->v.low); - fd = open( deviceNamePtr, O_RDWR, 0 ); - if( fd <= 0 ) { -#if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: SetVolumeUUID: device open failed (errno = %d).\n", errno); -#endif + /* Write the Finder Info back to the volume */ + result = setattrlist(path, &alist, &volFinderInfo.finderinfo, sizeof(volFinderInfo.finderinfo), 0); + if (result) { result = FSUR_IO_FAIL; goto Err_Exit; - }; + } + + result = FSUR_IO_SUCCESS; + +Err_Exit: + return result; +} + + +/* + GetVolumeUUID + + Return the UUID of an HFS, HFS Plus or HFSX volume. If there is no UUID and + we were asked to generate one, then generate a new UUID and write it to the + volume. + + Determine whether an HFS volume is mounted on the given device. If so, we + need to use GetVolumeUUIDAttr and SetVolumeUUIDAttr to access the UUID through + the filesystem. If there is no mounted volume, then do direct device access + with GetVolumeUUIDRaw and SetVolumeUUIDRaw. + + Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL, FSUR_UNRECOGNIZED + */ + +static int +GetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr, boolean_t generate) +{ + int result; + char *path = NULL; + + /* + * Determine whether a volume is mounted on this device. If it is HFS, then + * get the mount point's path. If it is non-HFS, then we can exit immediately + * with FSUR_UNRECOGNIZED. + */ + result = GetHFSMountPoint(deviceNamePtr, &path); + if (result != FSUR_IO_SUCCESS) + goto Err_Exit; /* - * Read the HFS Master Directory Block from sector 2 + * Get any existing UUID. */ - result = readAt(fd, volHdrPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); - if (result != FSUR_IO_SUCCESS) { + if (path) + result = GetVolumeUUIDAttr(path, volumeUUIDPtr); + else + result = GetVolumeUUIDRaw(deviceNamePtr, volumeUUIDPtr); + if (result != FSUR_IO_SUCCESS) goto Err_Exit; - }; - - if (mdbPtr->drSigWord == kHFSSigWord && - mdbPtr->drEmbedSigWord != kHFSPlusSigWord) { - finderInfoUUIDPtr = (VolumeUUID *)(&mdbPtr->drFndrInfo[6]); - bcopy(volumeUUIDPtr, finderInfoUUIDPtr, sizeof(*finderInfoUUIDPtr)); - result = writeAt(fd, volHdrPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE); - } else if ((volHdrPtr->signature == kHFSPlusSigWord) || - ((mdbPtr->drSigWord == kHFSSigWord) && - (mdbPtr->drEmbedSigWord == kHFSPlusSigWord))) { - off_t startOffset; - if (volHdrPtr->signature == kHFSPlusSigWord) { - startOffset = 0; - } else {/* embedded volume, first find offset */ - result = GetEmbeddedHFSPlusVol(mdbPtr, &startOffset); - if ( result != FSUR_IO_SUCCESS ) { - goto Err_Exit; - }; - } + /* + * If there was no valid UUID, and we were asked to generate one, then + * generate it and write it back to disk. + */ + if (generate && (volumeUUIDPtr->v.high == 0 || volumeUUIDPtr->v.low == 0)) { + GenerateVolumeUUID(volumeUUIDPtr); + if (path) + result = SetVolumeUUIDAttr(path, volumeUUIDPtr); + else + result = SetVolumeUUIDRaw(deviceNamePtr, volumeUUIDPtr); + /* Fall through to Err_Exit */ + } + +Err_Exit: + return result; +} + + + +/* + SetVolumeUUID - result = readAt( fd, volHdrPtr, startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE ); - if (result != FSUR_IO_SUCCESS) { - goto Err_Exit; // return FSUR_IO_FAIL - } + Write a UUID to an HFS, HFS Plus or HFSX volume. - /* Verify that it is an HFS+ volume. */ + Determine whether an HFS volume is mounted on the given device. If so, we + need to use SetVolumeUUIDAttr to access the UUID through the filesystem. + If there is no mounted volume, then do direct device access SetVolumeUUIDRaw. - if (volHdrPtr->signature != kHFSPlusSigWord) { - result = FSUR_IO_FAIL; - goto Err_Exit; - } + Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL, FSUR_UNRECOGNIZED + */ +static int +SetVolumeUUID(const char *deviceNamePtr, VolumeUUID *volumeUUIDPtr) { + int result; + char *path = NULL; - finderInfoUUIDPtr = (VolumeUUID *)&volHdrPtr->finderInfo[24]; - bcopy(volumeUUIDPtr, finderInfoUUIDPtr, sizeof(*finderInfoUUIDPtr)); - result = writeAt( fd, volHdrPtr, startOffset + (off_t)(2*HFS_BLOCK_SIZE), HFS_BLOCK_SIZE ); - if (result != FSUR_IO_SUCCESS) { - goto Err_Exit; - }; - result = FSUR_IO_SUCCESS; - } else { - result = FSUR_UNRECOGNIZED; - }; + /* + * Determine whether a volume is mounted on this device. If it is HFS, then + * get the mount point's path. If it is non-HFS, then we can exit immediately + * with FSUR_UNRECOGNIZED. + */ + result = GetHFSMountPoint(deviceNamePtr, &path); + if (result != FSUR_IO_SUCCESS) + goto Err_Exit; + + /* + * Update the UUID. + */ + if (path) + result = SetVolumeUUIDAttr(path, volumeUUIDPtr); + else + result = SetVolumeUUIDRaw(deviceNamePtr, volumeUUIDPtr); Err_Exit: - if (fd > 0) close(fd); - if (bufPtr) free(bufPtr); - -#if TRACE_HFS_UTIL - if (result != FSUR_IO_SUCCESS) fprintf(stderr, "hfs.util: SetVolumeUUID: result = %d...\n", result); -#endif - return (result == FSUR_IO_SUCCESS) ? FSUR_IO_SUCCESS : FSUR_IO_FAIL; -}; + return result; +} @@ -1219,21 +1649,21 @@ GetEmbeddedHFSPlusVol (HFSMasterDirectoryBlock * hfsMasterDirectoryBlockPtr, off int result = FSUR_IO_SUCCESS; u_int32_t allocationBlockSize, firstAllocationBlock, startBlock, blockCount; - if (hfsMasterDirectoryBlockPtr->drSigWord != kHFSSigWord) { + if (OSSwapBigToHostInt16(hfsMasterDirectoryBlockPtr->drSigWord) != kHFSSigWord) { result = FSUR_UNRECOGNIZED; goto Return; } - allocationBlockSize = hfsMasterDirectoryBlockPtr->drAlBlkSiz; - firstAllocationBlock = hfsMasterDirectoryBlockPtr->drAlBlSt; + allocationBlockSize = OSSwapBigToHostInt32(hfsMasterDirectoryBlockPtr->drAlBlkSiz); + firstAllocationBlock = OSSwapBigToHostInt16(hfsMasterDirectoryBlockPtr->drAlBlSt); - if (hfsMasterDirectoryBlockPtr->drEmbedSigWord != kHFSPlusSigWord) { + if (OSSwapBigToHostInt16(hfsMasterDirectoryBlockPtr->drEmbedSigWord) != kHFSPlusSigWord) { result = FSUR_UNRECOGNIZED; goto Return; } - startBlock = hfsMasterDirectoryBlockPtr->drEmbedExtent.startBlock; - blockCount = hfsMasterDirectoryBlockPtr->drEmbedExtent.blockCount; + startBlock = OSSwapBigToHostInt16(hfsMasterDirectoryBlockPtr->drEmbedExtent.startBlock); + blockCount = OSSwapBigToHostInt16(hfsMasterDirectoryBlockPtr->drEmbedExtent.blockCount); if ( startOffsetPtr ) *startOffsetPtr = ((u_int64_t)startBlock * (u_int64_t)allocationBlockSize) + @@ -1255,13 +1685,12 @@ Return: */ static int -GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * name_o) +GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, unsigned char * name_o) { int result = FSUR_IO_SUCCESS; u_int32_t blockSize; char * bufPtr = NULL; HFSPlusVolumeHeader * volHdrPtr; - off_t offset; BTNodeDescriptor * bTreeNodeDescriptorPtr; u_int32_t catalogNodeSize; u_int32_t leafNode; @@ -1288,7 +1717,8 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * nam /* Verify that it is an HFS+ volume. */ - if (volHdrPtr->signature != kHFSPlusSigWord) { + if (OSSwapBigToHostInt16(volHdrPtr->signature) != kHFSPlusSigWord && + OSSwapBigToHostInt16(volHdrPtr->signature) != kHFSXSigWord) { result = FSUR_IO_FAIL; #if TRACE_HFS_UTIL fprintf(stderr, "hfs.util: GetNameFromHFSPlusVolumeStartingAt: volHdrPtr->signature != kHFSPlusSigWord\n"); @@ -1296,7 +1726,7 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * nam goto Return; } - blockSize = volHdrPtr->blockSize; + blockSize = OSSwapBigToHostInt32(volHdrPtr->blockSize); catalogExtents = (HFSPlusExtentDescriptor *) malloc(sizeof(HFSPlusExtentRecord)); if ( ! catalogExtents ) { result = FSUR_IO_FAIL; @@ -1306,32 +1736,20 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * nam catalogExtCount = kHFSPlusExtentDensity; /* if there are overflow catalog extents, then go get them */ - if (catalogExtents[7].blockCount != 0) { + if (OSSwapBigToHostInt32(catalogExtents[7].blockCount) != 0) { result = GetCatalogOverflowExtents(fd, hfsPlusVolumeOffset, volHdrPtr, &catalogExtents, &catalogExtCount); if (result != FSUR_IO_SUCCESS) goto Return; } - offset = (off_t)catalogExtents[0].startBlock * (off_t)blockSize; - /* Read the header node of the catalog B-Tree */ - result = GetBTreeNodeInfo(fd, hfsPlusVolumeOffset + offset, &catalogNodeSize, &leafNode); + result = GetBTreeNodeInfo(fd, hfsPlusVolumeOffset, blockSize, + catalogExtCount, catalogExtents, + &catalogNodeSize, &leafNode); if (result != FSUR_IO_SUCCESS) goto Return; - /* Calculate the starting block of the first leaf node */ - - offset = CalcLeafNodeOffset((leafNode * catalogNodeSize), blockSize, catalogExtCount, catalogExtents); - - if ( offset == 0 ) { - result = FSUR_IO_FAIL; -#if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: ERROR: can't find leaf block\n"); -#endif - goto Return; - } - /* Read the first leaf node of the catalog b-tree */ bufPtr = (char *)malloc(catalogNodeSize); @@ -1342,10 +1760,12 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * nam bTreeNodeDescriptorPtr = (BTNodeDescriptor *)bufPtr; - result = readAt( fd, bufPtr, hfsPlusVolumeOffset + offset, catalogNodeSize ); + result = ReadFile(fd, bufPtr, (off_t) leafNode * (off_t) catalogNodeSize, catalogNodeSize, + hfsPlusVolumeOffset, blockSize, + catalogExtCount, catalogExtents); if (result == FSUR_IO_FAIL) { #if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: ERROR: readAt (first leaf) failed\n"); + fprintf(stderr, "hfs.util: ERROR: reading first leaf failed\n"); #endif goto Return; // return FSUR_IO_FAIL } @@ -1356,7 +1776,7 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * nam HFSPlusCatalogKey * k; CFStringRef cfstr; - if ( bTreeNodeDescriptorPtr->numRecords < 1) { + if ( OSSwapBigToHostInt16(bTreeNodeDescriptorPtr->numRecords) < 1) { result = FSUR_IO_FAIL; #if TRACE_HFS_UTIL fprintf(stderr, "hfs.util: ERROR: bTreeNodeDescriptorPtr->numRecords < 1\n"); @@ -1371,12 +1791,12 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * nam // Get a pointer to the first record. - p = bufPtr + *v; // pointer arithmetic in bytes + p = bufPtr + OSSwapBigToHostInt16(*v); // pointer arithmetic in bytes k = (HFSPlusCatalogKey *)p; // There should be only one record whose parent is the root parent. It should be the first record. - if (k->parentID != kHFSRootParentID) { + if (OSSwapBigToHostInt32(k->parentID) != kHFSRootParentID) { result = FSUR_IO_FAIL; #if TRACE_HFS_UTIL fprintf(stderr, "hfs.util: ERROR: k->parentID != kHFSRootParentID\n"); @@ -1386,9 +1806,26 @@ GetNameFromHFSPlusVolumeStartingAt(int fd, off_t hfsPlusVolumeOffset, char * nam /* Extract the name of the root directory */ - cfstr = CFStringCreateWithCharacters(kCFAllocatorDefault, k->nodeName.unicode, k->nodeName.length); - (void) CFStringGetCString(cfstr, name_o, NAME_MAX, kCFStringEncodingUTF8); - CFRelease(cfstr); + { + HFSUniStr255 *swapped; + int i; + + swapped = (HFSUniStr255 *)malloc(sizeof(HFSUniStr255)); + if (swapped == NULL) { + result = FSUR_IO_FAIL; + goto Return; + } + swapped->length = OSSwapBigToHostInt16(k->nodeName.length); + + for (i=0; ilength; i++) { + swapped->unicode[i] = OSSwapBigToHostInt16(k->nodeName.unicode[i]); + } + swapped->unicode[i] = 0; + cfstr = CFStringCreateWithCharacters(kCFAllocatorDefault, swapped->unicode, swapped->length); + (void) CFStringGetCString(cfstr, (char *)name_o, NAME_MAX, kCFStringEncodingUTF8); + CFRelease(cfstr); + free(swapped); + } } result = FSUR_IO_SUCCESS; @@ -1422,7 +1859,9 @@ typedef struct { -- */ static int -GetBTreeNodeInfo(int fd, off_t btreeOffset, u_int32_t *nodeSize, u_int32_t *firstLeafNode) +GetBTreeNodeInfo(int fd, off_t hfsPlusVolumeOffset, u_int32_t blockSize, + u_int32_t extentCount, const HFSPlusExtentDescriptor *extentList, + u_int32_t *nodeSize, u_int32_t *firstLeafNode) { int result; HeaderRec * bTreeHeaderPtr = NULL; @@ -1433,10 +1872,12 @@ GetBTreeNodeInfo(int fd, off_t btreeOffset, u_int32_t *nodeSize, u_int32_t *firs /* Read the b-tree header node */ - result = readAt( fd, bTreeHeaderPtr, btreeOffset, HFS_BLOCK_SIZE ); + result = ReadFile(fd, bTreeHeaderPtr, 0, HFS_BLOCK_SIZE, + hfsPlusVolumeOffset, blockSize, + extentCount, extentList); if ( result == FSUR_IO_FAIL ) { #if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: ERROR: readAt (header node) failed\n"); + fprintf(stderr, "hfs.util: ERROR: reading header node failed\n"); #endif goto free; } @@ -1449,12 +1890,12 @@ GetBTreeNodeInfo(int fd, off_t btreeOffset, u_int32_t *nodeSize, u_int32_t *firs goto free; } - *nodeSize = bTreeHeaderPtr->header.nodeSize; + *nodeSize = OSSwapBigToHostInt16(bTreeHeaderPtr->header.nodeSize); - if (bTreeHeaderPtr->header.leafRecords == 0) + if (OSSwapBigToHostInt32(bTreeHeaderPtr->header.leafRecords) == 0) *firstLeafNode = 0; else - *firstLeafNode = bTreeHeaderPtr->header.firstLeafNode; + *firstLeafNode = OSSwapBigToHostInt32(bTreeHeaderPtr->header.firstLeafNode); free:; free((char*) bTreeHeaderPtr); @@ -1464,44 +1905,6 @@ free:; } /* GetBTreeNodeInfo */ -/* - -- - -- - -- Returns: byte offset to first leaf node - -- - */ -static off_t -CalcLeafNodeOffset(off_t fileOffset, u_int32_t blockSize, u_int32_t extentCount, - HFSPlusExtentDescriptor *extentList) -{ - off_t offset = 0; - int i; - u_long extblks; - u_long leafblk; - - /* Find this block in the list of extents */ - - leafblk = fileOffset / blockSize; - extblks = 0; - - for (i = 0; i < extentCount; ++i) { - if (extentList[i].startBlock == 0 || extentList[i].blockCount == 0) - break; /* done when we reach empty extents */ - - extblks += extentList [i].blockCount; - - if (extblks > leafblk) { - offset = (off_t) extentList[i].startBlock * (off_t) blockSize; - offset += fileOffset - (off_t) ((extblks - extentList[i].blockCount) * blockSize); - break; - } - } - - return offset; - -} /* CalcLeafNodeOffset */ - - /* -- -- @@ -1515,8 +1918,10 @@ GetCatalogOverflowExtents(int fd, off_t hfsPlusVolumeOffset, u_int32_t *catalogExtCount) { off_t offset; + u_int32_t numRecords; u_int32_t nodeSize; u_int32_t leafNode; + u_int32_t blockSize; BTNodeDescriptor * bTreeNodeDescriptorPtr; HFSPlusExtentDescriptor * extents; size_t listsize; @@ -1524,30 +1929,23 @@ GetCatalogOverflowExtents(int fd, off_t hfsPlusVolumeOffset, int i; int result; + blockSize = OSSwapBigToHostInt32(volHdrPtr->blockSize); listsize = *catalogExtCount * sizeof(HFSPlusExtentDescriptor); extents = *catalogExtents; - offset = (off_t)volHdrPtr->extentsFile.extents[0].startBlock * - (off_t)volHdrPtr->blockSize; + offset = (off_t)OSSwapBigToHostInt32(volHdrPtr->extentsFile.extents[0].startBlock) * + (off_t)blockSize; /* Read the header node of the extents B-Tree */ - result = GetBTreeNodeInfo(fd, hfsPlusVolumeOffset + offset, + result = GetBTreeNodeInfo(fd, hfsPlusVolumeOffset, blockSize, + kHFSPlusExtentDensity, volHdrPtr->extentsFile.extents, &nodeSize, &leafNode); if (result != FSUR_IO_SUCCESS || leafNode == 0) goto Return; - /* Calculate the starting block of the first leaf node */ - - offset = CalcLeafNodeOffset((leafNode * nodeSize), volHdrPtr->blockSize, - kHFSPlusExtentDensity, &volHdrPtr->extentsFile.extents[0]); + /* Calculate the logical position of the first leaf node */ - if (offset == 0) { - result = FSUR_IO_FAIL; -#if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: ERROR: can't find extents b-tree leaf block\n"); -#endif - goto Return; - } + offset = (off_t) leafNode * (off_t) nodeSize; /* Read the first leaf node of the extents b-tree */ @@ -1560,20 +1958,23 @@ GetCatalogOverflowExtents(int fd, off_t hfsPlusVolumeOffset, bTreeNodeDescriptorPtr = (BTNodeDescriptor *)bufPtr; again: - result = readAt(fd, bufPtr, hfsPlusVolumeOffset + offset, nodeSize); - if ( result == FSUR_IO_FAIL ) { + result = ReadFile(fd, bufPtr, offset, nodeSize, + hfsPlusVolumeOffset, blockSize, + kHFSPlusExtentDensity, volHdrPtr->extentsFile.extents); + if ( result == FSUR_IO_FAIL ) { #if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: ERROR: readAt (first leaf) failed\n"); + fprintf(stderr, "hfs.util: ERROR: reading first leaf failed\n"); #endif - goto Return; + goto Return; } - if (bTreeNodeDescriptorPtr->kind != kBTLeafNode) { + if (bTreeNodeDescriptorPtr->kind != kBTLeafNode) { result = FSUR_IO_FAIL; goto Return; } - for (i = 1; i <= bTreeNodeDescriptorPtr->numRecords; ++i) { + numRecords = OSSwapBigToHostInt16(bTreeNodeDescriptorPtr->numRecords); + for (i = 1; i <= numRecords; ++i) { u_int16_t * v; char * p; HFSPlusExtentKey * k; @@ -1587,35 +1988,26 @@ again: /* Get a pointer to the record */ - p = bufPtr + *v; /* pointer arithmetic in bytes */ + p = bufPtr + OSSwapBigToHostInt16(*v); /* pointer arithmetic in bytes */ k = (HFSPlusExtentKey *)p; - if (k->fileID != kHFSCatalogFileID) + if (OSSwapBigToHostInt32(k->fileID) != kHFSCatalogFileID) goto Return; /* grow list and copy additional extents */ listsize += sizeof(HFSPlusExtentRecord); extents = (HFSPlusExtentDescriptor *) realloc(extents, listsize); - bcopy(p + k->keyLength + sizeof(u_int16_t), + bcopy(p + OSSwapBigToHostInt16(k->keyLength) + sizeof(u_int16_t), &extents[*catalogExtCount], sizeof(HFSPlusExtentRecord)); *catalogExtCount += kHFSPlusExtentDensity; *catalogExtents = extents; } - if ((leafNode = bTreeNodeDescriptorPtr->fLink) != 0) { + if ((leafNode = OSSwapBigToHostInt32(bTreeNodeDescriptorPtr->fLink)) != 0) { - offset = CalcLeafNodeOffset((leafNode * nodeSize), - volHdrPtr->blockSize, kHFSPlusExtentDensity, - &volHdrPtr->extentsFile.extents[0]); + offset = (off_t) leafNode * (off_t) nodeSize; - if (offset == 0) { - result = FSUR_IO_FAIL; -#if TRACE_HFS_UTIL - fprintf(stderr, "hfs.util: ERROR: can't find extents b-tree leaf block\n"); -#endif - goto Return; - } goto again; } @@ -1627,6 +2019,122 @@ Return:; } + +/* + * LogicalToPhysical - Map a logical file position and size to volume-relative physical + * position and number of contiguous bytes at that position. + * + * Inputs: + * logicalOffset Logical offset in bytes from start of file + * length Maximum number of bytes to map + * blockSize Number of bytes per allocation block + * extentCount Number of extents in file + * extentList The file's extents + * + * Outputs: + * physicalOffset Physical offset in bytes from start of volume + * availableBytes Number of bytes physically contiguous (up to length) + * + * Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL + */ +static int LogicalToPhysical(off_t offset, ssize_t length, u_int32_t blockSize, + u_int32_t extentCount, const HFSPlusExtentDescriptor *extentList, + off_t *physicalOffset, ssize_t *availableBytes) +{ + off_t temp; + u_int32_t logicalBlock; + u_int32_t extent; + u_int32_t blockCount = 0; + + /* Determine allocation block containing logicalOffset */ + logicalBlock = offset / blockSize; /* This can't overflow for valid volumes */ + offset %= blockSize; /* Offset from start of allocation block */ + + /* Find the extent containing logicalBlock */ + for (extent = 0; extent < extentCount; ++extent) + { + blockCount = OSSwapBigToHostInt32(extentList[extent].blockCount); + + if (blockCount == 0) + return FSUR_IO_FAIL; /* Tried to map past physical end of file */ + + if (logicalBlock < blockCount) + break; /* Found it! */ + + logicalBlock -= blockCount; + } + + if (extent >= extentCount) + return FSUR_IO_FAIL; /* Tried to map past physical end of file */ + + /* + * When we get here, extentList[extent] is the extent containing logicalOffset. + * The desired allocation block is logicalBlock blocks into the extent. + */ + + /* Compute the physical starting position */ + temp = OSSwapBigToHostInt32(extentList[extent].startBlock) + logicalBlock; /* First physical block */ + temp *= blockSize; /* Byte offset of first physical block */ + *physicalOffset = temp + offset; + + /* Compute the available contiguous bytes. */ + temp = blockCount - logicalBlock; /* Number of blocks available in extent */ + temp *= blockSize; + temp -= offset; /* Number of bytes available */ + + if (temp < length) + *availableBytes = temp; + else + *availableBytes = length; + + return FSUR_IO_SUCCESS; +} + + + +/* + * ReadFile - Read bytes from a file. Handles cases where the starting and/or + * ending position are not allocation or device block aligned. + * + * Inputs: + * fd Descriptor for reading the volume + * buffer The bytes are read into here + * offset Offset in file to start reading + * length Number of bytes to read + * volOffset Byte offset from start of device to start of volume + * blockSize Number of bytes per allocation block + * extentCount Number of extents in file + * extentList The file's exents + * + * Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL + */ +static int ReadFile(int fd, void *buffer, off_t offset, ssize_t length, + off_t volOffset, u_int32_t blockSize, + u_int32_t extentCount, const HFSPlusExtentDescriptor *extentList) +{ + int result = FSUR_IO_SUCCESS; + off_t physOffset; + ssize_t physLength; + + while (length > 0) + { + result = LogicalToPhysical(offset, length, blockSize, extentCount, extentList, + &physOffset, &physLength); + if (result != FSUR_IO_SUCCESS) + break; + + result = readAt(fd, buffer, volOffset+physOffset, physLength); + if (result != FSUR_IO_SUCCESS) + break; + + length -= physLength; + offset += physLength; + buffer = (char *) buffer + physLength; + } + + return result; +} + /* -- readAt = lseek() + read() -- @@ -1646,7 +2154,7 @@ readAt( int fd, void * bufPtr, off_t offset, ssize_t length ) ssize_t dataOffset = 0; int result = FSUR_IO_SUCCESS; - if (ioctl(fd, DKIOCBLKSIZE, &blocksize) < 0) { + if (ioctl(fd, DKIOCGETBLOCKSIZE, &blocksize) < 0) { #if TRACE_HFS_UTIL fprintf(stderr, "hfs.util: readAt: couldn't determine block size of device.\n"); #endif @@ -1706,7 +2214,7 @@ writeAt( int fd, void * bufPtr, off_t offset, ssize_t length ) ssize_t dataOffset = 0; int result = FSUR_IO_SUCCESS; - if (ioctl(fd, DKIOCBLKSIZE, &blocksize) < 0) { + if (ioctl(fd, DKIOCGETBLOCKSIZE, &blocksize) < 0) { #if TRACE_HFS_UTIL fprintf(stderr, "hfs.util: couldn't determine block size of device.\n"); #endif @@ -1739,7 +2247,7 @@ writeAt( int fd, void * bufPtr, off_t offset, ssize_t length ) result = FSUR_IO_FAIL; goto Return; } - }; + } bcopy(bufPtr, rawData + dataOffset, length); /* Copy in the new data */ @@ -1766,6 +2274,31 @@ Return: } /* writeAt */ +/* + * Get kernel's encoding bias. + */ +static int +GetEncodingBias() +{ + int mib[3]; + size_t buflen = sizeof(int); + struct vfsconf vfc; + int hint = 0; + + if (getvfsbyname("hfs", &vfc) < 0) + goto error; + + mib[0] = CTL_VFS; + mib[1] = vfc.vfc_typenum; + mib[2] = HFS_ENCODINGBIAS; + + if (sysctl(mib, 3, &hint, &buflen, NULL, 0) < 0) + goto error; + return (hint); +error: + return (-1); +} + /****************************************************************************** * * V O L U M E S T A T U S D A T A B A S E R O U T I N E S @@ -1814,12 +2347,6 @@ struct VSDBState { typedef struct VSDBState *VSDBStatePtr; -typedef struct { - unsigned long state[5]; - unsigned long count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - /* Internal function prototypes: */ @@ -1839,11 +2366,6 @@ static void FormatDBRecord(unsigned long volumeStatusFlags, struct VSDBRecord *d static void FormatDBEntry(VolumeUUID *volumeID, unsigned long volumeStatusFlags, struct VSDBEntry *dbentry); static unsigned long ConvertHexStringToULong(const char *hs, long maxdigits); -static void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); -static void SHA1Init(SHA1_CTX* context); -static void SHA1Update(SHA1_CTX* context, void* data, size_t len); -static void SHA1Final(unsigned char digest[20], SHA1_CTX* context); - /****************************************************************************** @@ -1853,7 +2375,7 @@ static void SHA1Final(unsigned char digest[20], SHA1_CTX* context); *****************************************************************************/ void GenerateVolumeUUID(VolumeUUID *newVolumeID) { - SHA1_CTX context; + SHA_CTX context; char randomInputBuffer[26]; unsigned char digest[20]; time_t now; @@ -1862,75 +2384,73 @@ void GenerateVolumeUUID(VolumeUUID *newVolumeID) { int sysdata; char sysctlstring[128]; size_t datalen; - struct loadavg sysloadavg; + double sysloadavg[3]; struct vmtotal sysvmtotal; do { /* Initialize the SHA-1 context for processing: */ - SHA1Init(&context); + SHA1_Init(&context); /* Now process successive bits of "random" input to seed the process: */ /* The current system's uptime: */ uptime = clock(); - SHA1Update(&context, &uptime, sizeof(uptime)); + SHA1_Update(&context, &uptime, sizeof(uptime)); /* The kernel's boot time: */ mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; datalen = sizeof(sysdata); sysctl(mib, 2, &sysdata, &datalen, NULL, 0); - SHA1Update(&context, &sysdata, datalen); + SHA1_Update(&context, &sysdata, datalen); /* The system's host id: */ mib[0] = CTL_KERN; mib[1] = KERN_HOSTID; datalen = sizeof(sysdata); sysctl(mib, 2, &sysdata, &datalen, NULL, 0); - SHA1Update(&context, &sysdata, datalen); + SHA1_Update(&context, &sysdata, datalen); /* The system's host name: */ mib[0] = CTL_KERN; mib[1] = KERN_HOSTNAME; datalen = sizeof(sysctlstring); sysctl(mib, 2, sysctlstring, &datalen, NULL, 0); - SHA1Update(&context, sysctlstring, datalen); + SHA1_Update(&context, sysctlstring, datalen); /* The running kernel's OS release string: */ mib[0] = CTL_KERN; mib[1] = KERN_OSRELEASE; datalen = sizeof(sysctlstring); sysctl(mib, 2, sysctlstring, &datalen, NULL, 0); - SHA1Update(&context, sysctlstring, datalen); + SHA1_Update(&context, sysctlstring, datalen); /* The running kernel's version string: */ mib[0] = CTL_KERN; mib[1] = KERN_VERSION; datalen = sizeof(sysctlstring); sysctl(mib, 2, sysctlstring, &datalen, NULL, 0); - SHA1Update(&context, sysctlstring, datalen); + SHA1_Update(&context, sysctlstring, datalen); /* The system's load average: */ - mib[0] = CTL_VM; - mib[1] = VM_LOADAVG; datalen = sizeof(sysloadavg); - sysctl(mib, 2, &sysloadavg, &datalen, NULL, 0); - SHA1Update(&context, &sysloadavg, datalen); + getloadavg(sysloadavg, 3); + SHA1_Update(&context, &sysloadavg, datalen); /* The system's VM statistics: */ mib[0] = CTL_VM; mib[1] = VM_METER; datalen = sizeof(sysvmtotal); sysctl(mib, 2, &sysvmtotal, &datalen, NULL, 0); - SHA1Update(&context, &sysvmtotal, datalen); + SHA1_Update(&context, &sysvmtotal, datalen); /* The current GMT (26 ASCII characters): */ time(&now); strncpy(randomInputBuffer, asctime(gmtime(&now)), 26); /* "Mon Mar 27 13:46:26 2000" */ - SHA1Update(&context, randomInputBuffer, 26); + SHA1_Update(&context, randomInputBuffer, 26); /* Pad the accumulated input and extract the final digest hash: */ - SHA1Final(digest, &context); + SHA1_Final(digest, &context); memcpy(newVolumeID, digest, sizeof(*newVolumeID)); } while ((newVolumeID->v.high == 0) || (newVolumeID->v.low == 0)); @@ -1955,11 +2475,11 @@ void ConvertVolumeUUIDStringToUUID(const char *UUIDString, VolumeUUID *volumeID) nextdigit = c - 'a' + 10; } else { nextdigit = 0; - }; + } carry = ((low & 0xF0000000) >> 28) & 0x0000000F; high = (high << 4) | carry; low = (low << 4) | nextdigit; - }; + } volumeID->v.high = high; volumeID->v.low = low; @@ -1982,7 +2502,7 @@ int OpenVolumeStatusDB(VolumeStatusDBHandle *DBHandlePtr) { dbstateptr = (VSDBStatePtr)malloc(sizeof(*dbstateptr)); if (dbstateptr == NULL) { return ENOMEM; - }; + } dbstateptr->dbmode = O_RDWR; dbstateptr->dbfile = open(gVSDBPath, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); @@ -1995,8 +2515,8 @@ int OpenVolumeStatusDB(VolumeStatusDBHandle *DBHandlePtr) { dbstateptr->dbfile = open(gVSDBPath, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (dbstateptr->dbfile == -1) { return errno; - }; - }; + } + } dbstateptr->signature = DBHANDLESIGNATURE; *DBHandlePtr = (VolumeStatusDBHandle)dbstateptr; @@ -2016,7 +2536,7 @@ int GetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, if ((result = FindVolumeRecordByUUID(dbstateptr, volumeID, &dbentry, 0)) != 0) { goto ErrExit; - }; + } *VolumeStatus = VOLUME_RECORDED | ConvertHexStringToULong(dbentry.record.statusFlags, sizeof(dbentry.record.statusFlags)); result = 0; @@ -2051,7 +2571,7 @@ int SetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, result = AddVolumeRecord(dbstateptr, &dbentry); } else { goto ErrExit; - }; + } fsync(dbstateptr->dbfile); @@ -2093,7 +2613,7 @@ int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeI iobuffersize = dbinfo.st_size - dbstateptr->recordPosition - sizeof(struct VSDBEntry); } else { iobuffersize = MAXIOMALLOC; - }; + } #if DEBUG_TRACE fprintf(stderr, "DeleteLocalVolumeUUID: DB size = 0x%08lx; recordPosition = 0x%08lx;\n", (unsigned long)dbinfo.st_size, (unsigned long)dbstateptr->recordPosition); @@ -2104,7 +2624,7 @@ int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeI if (iobuffer == NULL) { result = ENOMEM; goto ErrExit; - }; + } dataoffset = dbstateptr->recordPosition + sizeof(struct VSDBEntry); do { @@ -2120,7 +2640,7 @@ int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeI if (bytestransferred != iotransfersize) { result = errno; goto ErrExit; - }; + } #if DEBUG_TRACE fprintf(stderr, "DeleteLocalVolumeUUID: writing 0x%08lx bytes starting at 0x%08lx ...\n", iotransfersize, (unsigned long)(dataoffset - (off_t)sizeof(struct VSDBEntry))); @@ -2130,23 +2650,23 @@ int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeI if (bytestransferred != iotransfersize) { result = errno; goto ErrExit; - }; + } dataoffset += (off_t)iotransfersize; - }; + } } while (iotransfersize > 0); - }; + } #if DEBUG_TRACE fprintf(stderr, "DeleteLocalVolumeUUID: truncating database file to 0x%08lx bytes.\n", (unsigned long)(dbinfo.st_size - (off_t)(sizeof(struct VSDBEntry)))); #endif if ((result = ftruncate(dbstateptr->dbfile, dbinfo.st_size - (off_t)(sizeof(struct VSDBEntry)))) != 0) { goto ErrExit; - }; + } fsync(dbstateptr->dbfile); result = 0; - }; + } ErrExit: if (iobuffer) free(iobuffer); @@ -2215,9 +2735,9 @@ static int FindVolumeRecordByUUID(VSDBStatePtr dbstateptr, VolumeUUID *volumeID, fprintf(stderr, "FindVolumeRecordByUUID: copying %d. bytes from %08xl to %08l...\n", sizeof(*targetEntry), &dbentry, targetEntry); #endif memcpy(targetEntry, &dbentry, sizeof(*targetEntry)); - }; + } return 0; - }; + } } while (result == 0); return -1; @@ -2278,7 +2798,7 @@ static int GetVSDBEntry(VSDBStatePtr dbstateptr, struct VSDBEntry *dbentry) { (entry.space != DBBLANKSPACE) || (entry.terminator != DBRECORDTERMINATOR)) { return -1; - }; + } #if DEBUG_TRACE strncpy(id, entry.key.uuid, sizeof(entry.key.uuid)); @@ -2287,7 +2807,7 @@ static int GetVSDBEntry(VSDBStatePtr dbstateptr, struct VSDBEntry *dbentry) { #endif memcpy(dbentry, &entry, sizeof(*dbentry)); return 0; -}; +} @@ -2325,9 +2845,9 @@ static void FormatULong(unsigned long u, char *s) { *digitptr++ = (char)(d + '0'); } else { *digitptr++ = (char)(d - 10 + 'A'); - }; + } u = u << 4; - }; + } } @@ -2336,7 +2856,7 @@ static void FormatUUID(VolumeUUID *volumeID, char *UUIDField) { FormatULong(volumeID->v.high, UUIDField); FormatULong(volumeID->v.low, UUIDField+8); -}; +} @@ -2382,191 +2902,9 @@ static unsigned long ConvertHexStringToULong(const char *hs, long maxdigits) { nextdigit = c - 'a' + 10; } else { nextdigit = 0; - }; + } n = (n << 4) + nextdigit; - }; + } return n; } - - - -/****************************************************************************** - * - * S H A - 1 I M P L E M E N T A T I O N R O U T I N E S - * - *****************************************************************************/ - -/* - Derived from SHA-1 in C - By Steve Reid - 100% Public Domain - - Test Vectors (from FIPS PUB 180-1) - "abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 - A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#ifdef LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#if TRACE_HASH -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);printf("t = %2d: %08lX %08lX %08lX %08lX %08lX\n", i, a, b, c, d, e); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);printf("t = %2d: %08lX %08lX %08lX %08lX %08lX\n", i, a, b, c, d, e); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);printf("t = %2d: %08lX %08lX %08lX %08lX %08lX\n", i, a, b, c, d, e); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);printf("t = %2d: %08lX %08lX %08lX %08lX %08lX\n", i, a, b, c, d, e); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);printf("t = %2d: %08lX %08lX %08lX %08lX %08lX\n", i, a, b, c, d, e); -#else -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); -#endif - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -static void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) -{ -unsigned long a, b, c, d, e; -typedef union { - unsigned char c[64]; - unsigned long l[16]; -} CHAR64LONG16; -CHAR64LONG16* block; -#ifdef SHA1HANDSOFF -static unsigned char workspace[64]; - block = (CHAR64LONG16*)workspace; - memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16*)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; -#if TRACE_HASH - printf(" A B C D E\n"); - printf(" -------- -------- -------- -------- --------\n"); - printf(" %08lX %08lX %08lX %08lX %08lX\n", a, b, c, d, e); -#endif - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -} - - -/* SHA1Init - Initialize new context */ - -static void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -static void SHA1Update(SHA1_CTX* context, void* data, size_t len) -{ - unsigned char *dataptr = (char *)data; - unsigned int i, j; - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - memcpy(&context->buffer[j], dataptr, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &dataptr[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &dataptr[i], len - i); -} - - -/* Add padding and return the message digest. */ - -static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ -unsigned long i, j; -unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (unsigned char *)"\200", 1); - while ((context->count[0] & 504) != 448) { - SHA1Update(context, (unsigned char *)"\0", 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - i = j = 0; - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); -#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); -#endif -}