/*
- * 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.
#include <sys/vmmeter.h>
#include <sys/mount.h>
#include <sys/wait.h>
-
-#include <bsd/dev/disk.h>
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/disk.h>
#include <sys/loadable_fs.h>
+#include <sys/attr.h>
#include <hfs/hfs_format.h>
+#include <hfs/hfs_mount.h>
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <syslog.h>
-#include <CoreFoundation/CFString.h>
+/*
+ * 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 <CommonCrypto/CommonDigest.h>
-#define READ_DEFAULT_ENCODING 1
+#include <libkern/OSByteOrder.h>
-#ifndef FSUR_MOUNT_HIDDEN
-#define FSUR_MOUNT_HIDDEN (-9)
-#endif
+#include <CoreFoundation/CFString.h>
-#ifndef FSUC_GETKEY
-#define FSUC_GETKEY 'k'
-#endif
+#include <System/uuid/uuid.h>
+#include <System/uuid/namespace.h>
+
+#define READ_DEFAULT_ENCODING 1
#ifndef FSUC_ADOPT
#define FSUC_ADOPT 'a'
#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 ******************************************* */
char gHFS_FS_NAME[] = "hfs";
char gHFS_FS_NAME_NAME[] = "HFS";
-char gFS_UUID_SUFFIX[] = ".uuid";
char gNewlineString[] = "\n";
char gMountCommand[] = "/sbin/mount";
char gReadOnlyOption[] = "-r";
char gReadWriteOption[] = "-w";
+char gSuidOption[] = "suid";
+char gNoSuidOption[] = "nosuid";
+
+char gDevOption[] = "dev";
+char gNoDevOption[] = "nodev";
+
char gUsePermissionsOption[] = "perm";
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];
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);
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 );
+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 );
static int DoGetUUIDKey( const char * theDeviceNamePtr );
static int DoChangeUUIDKey( const char * theDeviceNamePtr );
static int DoAdopt( const char * theDeviceNamePtr );
static int DoDisown( const char * theDeviceNamePtr );
-static int ParseArgs( int argc, const char * argv[], const char ** actionPtr, const char ** mountPointPtr, boolean_t * isEjectablePtr, boolean_t * isLockedPtr );
+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
}
#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; i<numEncodings; ++i)
+ {
+ if (hfs_mnt_encodinglist[i].encoding_id == encoding)
+ {
+ encodingName = hfs_mnt_encodinglist[i].encoding_name;
+ break;
+ }
+ }
+
+ if (encodingName == NULL)
+ {
+ /* Couldn't figure out which encoding KEXT to load */
+ syslog(LOG_ERR, "Couldn't find name for encoding #%d", encoding);
+ return FSUR_LOADERR;
+ }
+
+ sprintf(kmodfile, "%sHFS_Mac%s.kext", ENCODING_MODULE_PATH, encodingName);
+ if (stat(kmodfile, &sb) == -1)
+ {
+ /* We recognized the encoding, but couldn't find the KEXT */
+ syslog(LOG_ERR, "Couldn't stat HFS_Mac%s.kext: %s", encodingName, strerror(errno));
+ return FSUR_LOADERR;
+ }
+
+ pid = fork();
+ if (pid == 0)
+ {
+ (void) execl(KEXT_LOAD_COMMAND, KEXT_LOAD_COMMAND, "-q", kmodfile, NULL);
+
+ exit(1); /* We can only get here if the exec failed */
+ }
+ else if (pid != -1)
+ {
+ if ((waitpid(pid, (int *)&status, 0) == pid) && WIFEXITED(status))
+ {
+ if (WEXITSTATUS(status) != 0)
+ {
+ /* kextload returned an error. Too bad its output doesn't get logged. */
+ syslog(LOG_ERR, "Couldn't load HFS_Mac%s.kext", encodingName);
+ return FSUR_LOADERR;
+ }
+ }
+ }
+
+ return FSUR_IO_SUCCESS;
+}
+
+
/* ******************************************** main ************************************************
Purpose -
This our main entry point to this utility. We get called by the WorkSpace. See ParseArgs
const char * mountPointPtr = NULL;
int result = FSUR_IO_SUCCESS;
boolean_t isLocked = 0; /* reasonable assumptions */
+ boolean_t isSetuid = 0; /* reasonable assumptions */
+ boolean_t isDev = 0; /* reasonable assumptions */
+
+ openlog("hfs.util", LOG_PID, LOG_DAEMON);
/* Verify our arguments */
- if ( (result = ParseArgs( argc, argv, & actionPtr, & mountPointPtr, & gIsEjectable, & isLocked )) != 0 ) {
+ if ( (result = ParseArgs( argc, argv, & actionPtr, & mountPointPtr, & gIsEjectable, & isLocked, &isSetuid, &isDev )) != 0 ) {
goto AllDone;
}
/* call the appropriate routine to handle the given action argument after becoming root */
- result = seteuid( 0 );
- if ( result ) {
- result = FSUR_INVAL;
- goto AllDone;
- }
-
- result = setegid( 0 ); // PPD - is this necessary?
-
switch( * actionPtr ) {
case FSUC_PROBE:
result = DoProbe(rawDeviceName);
case FSUC_MOUNT:
case FSUC_MOUNT_FORCE:
- result = DoMount(blockDeviceName, mountPointPtr, isLocked);
+ result = DoMount(blockDeviceName, mountPointPtr, isLocked, isSetuid, isDev);
break;
case FSUC_UNMOUNT:
result = DoUnmount( mountPointPtr );
break;
-
- case FSUC_GETKEY:
+ case FSUC_GETUUID:
result = DoGetUUIDKey( blockDeviceName );
break;
- case FSUC_NEWUUID:
+ case FSUC_SETUUID:
result = DoChangeUUIDKey( blockDeviceName );
break;
-
case FSUC_ADOPT:
result = DoAdopt( blockDeviceName );
break;
case FSUC_DISOWN:
result = DoDisown( blockDeviceName );
break;
+
+ case FSUC_MKJNL:
+ if (gJournalSize) {
+ result = DoMakeJournaled( argv[3], gJournalSize );
+ } else {
+ result = DoMakeJournaled( argv[2], gJournalSize );
+ }
+ break;
+
+ case FSUC_UNJNL:
+ result = DoUnJournal( argv[2] );
+ break;
+ case FSUC_UNJNL_RAW:
+ result = RawDisableJournaling( argv[2] );
+ break;
+
+ case FSUC_JNLINFO:
+ result = DoGetJournalInfo( argv[2] );
+ break;
+
default:
/* should never get here since ParseArgs should handle this situation */
DoDisplayUsage( argv );
returns FSUR_IO_SUCCESS everything is cool else one of several other FSUR_xyz error codes.
*********************************************************************** */
static int
-DoMount(char *deviceNamePtr, const char *mountPointPtr, boolean_t isLocked)
+DoMount(char *deviceNamePtr, const char *mountPointPtr, boolean_t isLocked, boolean_t isSetuid, boolean_t isDev)
{
int pid;
- char *isLockedstr;
+ char *isLockedstr;
+ char *isSetuidstr;
+ char *isDevstr;
char *permissionsOption;
int result = FSUR_IO_FAIL;
union wait status;
fprintf(stderr, "hfs.util: DoMount: Not adopting ejectable %s.\n", deviceNamePtr);
#endif
targetVolumeStatus = 0;
- };
+ }
#endif
} else {
/* We've got a real volume UUID! */
fprintf(stderr, "hfs.util: DoMount: Not adopting ejectable %s.\n", deviceNamePtr);
#endif
targetVolumeStatus = 0;
- };
+ }
#else
targetVolumeStatus = 0;
#endif
- };
+ }
(void)CloseVolumeStatusDB(vsdbhandle);
vsdbhandle = NULL;
- };
- };
+ }
+ }
pid = fork();
if (pid == 0) {
- isLockedstr = isLocked ? gReadOnlyOption : gReadWriteOption;
+ isLockedstr = isLocked ? gReadOnlyOption : gReadWriteOption;
+ isSetuidstr = isSetuid ? gSuidOption : gNoSuidOption;
+ isDevstr = isDev ? gDevOption : gNoDevOption;
permissionsOption =
(targetVolumeStatus & VOLUME_USEPERMISSIONS) ? gUsePermissionsOption : gIgnorePermissionsOption;
fprintf(stderr, "hfs.util: %s %s -o -x -o %s -o %s -o -u=unknown,-g=unknown,-m=0777 -t %s %s %s ...\n",
gMountCommand, isLockedstr, encodeopt, permissionsOption, gHFS_FS_NAME, deviceNamePtr, mountPointPtr);
#endif
- (void) execl(gMountCommand, gMountCommand, isLockedstr,
- "-o", encodeopt, "-o", permissionsOption,
- "-o", "-u=unknown,-g=unknown,-m=0777",
- "-t", gHFS_FS_NAME, deviceNamePtr, mountPointPtr, NULL);
+ (void) execl(gMountCommand, gMountCommand, isLockedstr, "-o", isSetuidstr, "-o", isDevstr,
+ "-o", encodeopt, "-o", permissionsOption,
+ "-o", "-u=unknown,-g=unknown,-m=0777",
+ "-t", gHFS_FS_NAME, deviceNamePtr, mountPointPtr, NULL);
+
/* IF WE ARE HERE, WE WERE UNSUCCESFULL */
return (FSUR_IO_FAIL);
Input -
theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
Output -
- returns FSUR_MOUNT_HIDDEN (previously FSUR_RECOGNIZED) if we can handle the media else one of the FSUR_xyz error codes.
+ returns FSUR_RECOGNIZED if we can handle the media else one of the FSUR_xyz error codes.
*************************************************************************************************** */
static int
DoProbe(char *deviceNamePtr)
goto Return;
/* get classic HFS volume name (from MDB) */
- if (mdbPtr->drSigWord == 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) {
/* 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,
}
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;
- };
-
- colon = CFStringCreateWithCString(kCFAllocatorDefault, ":", kCFStringEncodingUTF8);
- if (colon == NULL) {
- result = FSUR_IO_FAIL;
- goto Return;
- };
+ unsigned char *s;
- 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:
} /* 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 -
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:
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;
closeresult = CloseVolumeStatusDB(vsdbhandle);
vsdbhandle = NULL;
if (result == FSUR_IO_SUCCESS) result = closeresult;
- };
+ }
if ((result != 0) && (result != FSUR_IO_SUCCESS)) result = FSUR_IO_FAIL;
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;
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
}
+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 -
(these are ignored for CDROMs)
either "readonly" OR "writable"
either "removable" OR "fixed"
+ either "nosuid" or "suid"
+ either "nodev" or "dev"
examples:
hfs.util -p disk0s2 removable writable
static int
ParseArgs(int argc, const char *argv[], const char ** actionPtr,
const char ** mountPointPtr, boolean_t * isEjectablePtr,
- boolean_t * isLockedPtr)
+ boolean_t * isLockedPtr, boolean_t * isSetuidPtr, boolean_t * isDevPtr)
{
int result = FSUR_INVAL;
- int deviceLength;
+ int deviceLength, doLengthCheck = 1;
int index;
+ int mounting = 0;
/* Must have at least 3 arguments and the action argument must start with a '-' */
if ( (argc < 3) || (argv[1][0] != '-') ) {
case FSUC_MOUNT:
case FSUC_MOUNT_FORCE:
- /* action Mount and ForceMount require 6 arguments (need the mountpoint and the flags) */
- if ( argc < 6 ) {
+ /* action Mount and ForceMount require 8 arguments (need the mountpoint and the flags) */
+ if ( argc < 8 ) {
DoDisplayUsage( argv );
goto Return;
} else {
* mountPointPtr = argv[3];
index = 4;
+ mounting = 1;
}
break;
- case FSUC_GETKEY:
+ case FSUC_GETUUID:
index = 0;
break;
- case FSUC_NEWUUID:
+ case FSUC_SETUUID:
index = 0;
break;
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;
/* 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;
}
} else {
printf("hfs.util: ERROR: unrecognized flag (readonly/writable) argv[%d]='%s'\n",index,argv[index+1]);
}
+
+ if (mounting) {
+ /* Flags: suid/nosuid. */
+ if ( 0 == strcmp(argv[index+2],"suid") ) {
+ * isSetuidPtr = 1;
+ } else if ( 0 == strcmp(argv[index+2],"nosuid") ) {
+ * isSetuidPtr = 0;
+ } else {
+ printf("hfs.util: ERROR: unrecognized flag (suid/nosuid) argv[%d]='%s'\n",index,argv[index+2]);
+ }
+
+ /* Flags: dev/nodev. */
+ if ( 0 == strcmp(argv[index+3],"dev") ) {
+ * isDevPtr = 1;
+ } else if ( 0 == strcmp(argv[index+3],"nodev") ) {
+ * isDevPtr = 0;
+ } else {
+ printf("hfs.util: ERROR: unrecognized flag (dev/nodev) argv[%d]='%s'\n",index,argv[index+3]);
+ }
+ }
+
+
}
result = 0;
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; i<numMounts; ++i) {
+ if (!strcmp(deviceNamePtr, buf[i].f_mntfromname)) {
+ /* Found a mounted volume; check the type */
+ if (!strcmp(buf[i].f_fstypename, "hfs")) {
+ *pathPtr = buf[i].f_mntonname;
+ /* result = FSUR_IO_SUCCESS, above */
+ } else {
+ result = FSUR_UNRECOGNIZED;
+ }
+ break;
+ }
+ }
+
+ return result;
+}
- return;
-} /* DoFileSystemFile */
+/*
+ ReadHeaderBlock
+
+ Read the Master Directory Block or Volume Header Block from an HFS,
+ HFS Plus, or HFSX volume into a caller-supplied buffer. Return the
+ offset of an embedded HFS Plus volume (or 0 if not embedded HFS Plus).
+ Return a pointer to the volume UUID in the Finder Info.
+ Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL, FSUR_UNRECOGNIZED
+*/
+static int
+ReadHeaderBlock(int fd, void *bufPtr, off_t *startOffset, VolumeUUID **finderInfoUUIDPtr)
+{
+ int result;
+ HFSMasterDirectoryBlock * mdbPtr;
+ HFSPlusVolumeHeader * volHdrPtr;
+ mdbPtr = bufPtr;
+ volHdrPtr = bufPtr;
+
+ /*
+ * Read the HFS Master Directory Block or Volume Header from sector 2
+ */
+ *startOffset = 0;
+ result = readAt(fd, bufPtr, (off_t)(2 * HFS_BLOCK_SIZE), HFS_BLOCK_SIZE);
+ if (result != FSUR_IO_SUCCESS)
+ goto Err_Exit;
+
+ /*
+ * If this is a wrapped HFS Plus volume, read the Volume Header from
+ * sector 2 of the embedded volume.
+ */
+ if (OSSwapBigToHostInt16(mdbPtr->drSigWord) == 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;
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;
+}
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) +
*/
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;
/* 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");
goto Return;
}
- blockSize = volHdrPtr->blockSize;
+ blockSize = OSSwapBigToHostInt32(volHdrPtr->blockSize);
catalogExtents = (HFSPlusExtentDescriptor *) malloc(sizeof(HFSPlusExtentRecord));
if ( ! catalogExtents ) {
result = FSUR_IO_FAIL;
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);
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
}
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");
// 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");
/* 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; i<swapped->length; 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;
--
*/
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;
/* 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;
}
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);
} /* 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 */
-
-
/*
--
--
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;
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 */
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;
/* 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;
}
}
+
+/*
+ * 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()
--
void * rawData = NULL;
off_t rawOffset;
ssize_t rawLength;
+ 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
}
/* put offset and length in terms of device blocksize */
rawOffset = offset / blocksize * blocksize;
- rawLength = ((length + blocksize - 1) / blocksize) * blocksize;
+ dataOffset = offset - rawOffset;
+ rawLength = ((length + dataOffset + blocksize - 1) / blocksize) * blocksize;
rawData = malloc(rawLength);
if (rawData == NULL) {
result = FSUR_IO_FAIL;
result = FSUR_IO_FAIL;
goto Return;
}
- bcopy(rawData + (offset - rawOffset), bufPtr, length);
+ bcopy(rawData + dataOffset, bufPtr, length);
Return:
if (rawData) {
void * rawData = NULL;
off_t rawOffset;
ssize_t rawLength;
+ 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
}
/* put offset and length in terms of device blocksize */
rawOffset = offset / blocksize * blocksize;
- rawLength = ((length + blocksize - 1) / blocksize) * blocksize;
+ dataOffset = offset - rawOffset;
+ rawLength = ((length + dataOffset + blocksize - 1) / blocksize) * blocksize;
rawData = malloc(rawLength);
if (rawData == NULL) {
result = FSUR_IO_FAIL;
result = FSUR_IO_FAIL;
goto Return;
}
- };
+ }
- bcopy(bufPtr, rawData + (offset - rawOffset), length); /* Copy in the new data */
+ bcopy(bufPtr, rawData + dataOffset, length); /* Copy in the new data */
deviceoffset = lseek( fd, rawOffset, SEEK_SET );
if ( deviceoffset != rawOffset ) {
} /* 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
typedef struct VSDBState *VSDBStatePtr;
-typedef struct {
- unsigned long state[5];
- unsigned long count[2];
- unsigned char buffer[64];
-} SHA1_CTX;
-
/* Internal function prototypes: */
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);
-
/******************************************************************************
*****************************************************************************/
void GenerateVolumeUUID(VolumeUUID *newVolumeID) {
- SHA1_CTX context;
+ SHA_CTX context;
char randomInputBuffer[26];
unsigned char digest[20];
time_t now;
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));
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;
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);
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;
if ((result = FindVolumeRecordByUUID(dbstateptr, volumeID, &dbentry, 0)) != 0) {
goto ErrExit;
- };
+ }
*VolumeStatus = VOLUME_RECORDED | ConvertHexStringToULong(dbentry.record.statusFlags, sizeof(dbentry.record.statusFlags));
result = 0;
result = AddVolumeRecord(dbstateptr, &dbentry);
} else {
goto ErrExit;
- };
+ }
fsync(dbstateptr->dbfile);
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);
if (iobuffer == NULL) {
result = ENOMEM;
goto ErrExit;
- };
+ }
dataoffset = dbstateptr->recordPosition + sizeof(struct VSDBEntry);
do {
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)));
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);
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;
(entry.space != DBBLANKSPACE) ||
(entry.terminator != DBRECORDTERMINATOR)) {
return -1;
- };
+ }
#if DEBUG_TRACE
strncpy(id, entry.key.uuid, sizeof(entry.key.uuid));
#endif
memcpy(dbentry, &entry, sizeof(*dbentry));
return 0;
-};
+}
*digitptr++ = (char)(d + '0');
} else {
*digitptr++ = (char)(d - 10 + 'A');
- };
+ }
u = u << 4;
- };
+ }
}
FormatULong(volumeID->v.high, UUIDField);
FormatULong(volumeID->v.low, UUIDField+8);
-};
+}
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 <steve@edmweb.com>
- 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
-}