2 * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 Copyright (c) 1987-99 Apple Computer, Inc.
27 Contains code to implement hfs utility used by the WorkSpace to mount HFS.
30 5-Jan-1999 Don Brady Write hfs.label names in UTF-8.
31 10-Dec-1998 Pat Dirks Changed to try built-in hfs filesystem first.
32 3-Sep-1998 Don Brady Disable the daylight savings time stuff.
33 28-Aug-1998 chw Fixed parse args and verify args to indicate that the
34 flags (fixed or removable) are required in the probe case.
35 22-Jun-1998 Pat Dirks Changed HFSToUFSStr table to switch ":" and "/".
36 13-Jan-1998 jwc first cut (derived from old NextStep macfs.util code and cdrom.util code).
40 /* ************************************** I N C L U D E S ***************************************** */
42 #include <sys/types.h>
45 #include <sys/sysctl.h>
46 #include <sys/resource.h>
47 #include <sys/vmmeter.h>
48 #include <sys/mount.h>
52 #include <sys/loadable_fs.h>
53 #include <hfs/hfs_format.h>
64 #include <CoreFoundation/CFString.h>
66 #define READ_DEFAULT_ENCODING 1
68 #ifndef FSUR_MOUNT_HIDDEN
69 #define FSUR_MOUNT_HIDDEN (-9)
73 #define FSUC_ADOPT 'a'
77 #define FSUC_DISOWN 'd'
81 #define FSUC_GETUUID 'k'
85 #define FSUC_SETUUID 's'
89 #define FSUC_MKJNL 'J'
93 #define FSUC_UNJNL 'U'
97 /* **************************************** L O C A L S ******************************************* */
99 #define HFS_BLOCK_SIZE 512
101 char gHFS_FS_NAME
[] = "hfs";
102 char gHFS_FS_NAME_NAME
[] = "HFS";
104 char gNewlineString
[] = "\n";
106 char gMountCommand
[] = "/sbin/mount";
108 char gUnmountCommand
[] = "/sbin/umount";
110 char gReadOnlyOption
[] = "-r";
111 char gReadWriteOption
[] = "-w";
113 char gSuidOption
[] = "suid";
114 char gNoSuidOption
[] = "nosuid";
116 char gDevOption
[] = "dev";
117 char gNoDevOption
[] = "nodev";
119 char gUsePermissionsOption
[] = "perm";
120 char gIgnorePermissionsOption
[] = "noperm";
122 boolean_t gIsEjectable
= 0;
124 int gJournalSize
= 0;
126 #define AUTO_ADOPT_FIXED 1
127 #define AUTO_ENTER_FIXED 0
130 #define VOLUMEUUIDVALUESIZE 2
131 typedef union VolumeUUID
{
132 unsigned long value
[VOLUMEUUIDVALUESIZE
];
139 #define VOLUMEUUIDLENGTH 16
140 typedef char VolumeUUIDString
[VOLUMEUUIDLENGTH
+1];
142 #define VOLUME_RECORDED 0x80000000
143 #define VOLUME_USEPERMISSIONS 0x00000001
144 #define VOLUME_VALIDSTATUSBITS ( VOLUME_USEPERMISSIONS )
146 typedef void *VolumeStatusDBHandle
;
148 void GenerateVolumeUUID(VolumeUUID
*newVolumeID
);
149 void ConvertVolumeUUIDStringToUUID(const char *UUIDString
, VolumeUUID
*volumeID
);
150 void ConvertVolumeUUIDToString(VolumeUUID
*volumeID
, char *UUIDString
);
151 int OpenVolumeStatusDB(VolumeStatusDBHandle
*DBHandlePtr
);
152 int GetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle
, VolumeUUID
*volumeID
, unsigned long *VolumeStatus
);
153 int SetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle
, VolumeUUID
*volumeID
, unsigned long VolumeStatus
);
154 int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle
, VolumeUUID
*volumeID
);
155 int CloseVolumeStatusDB(VolumeStatusDBHandle DBHandle
);
157 /* ************************************ P R O T O T Y P E S *************************************** */
158 static void DoDisplayUsage( const char * argv
[] );
159 static void DoFileSystemFile( char * theFileNameSuffixPtr
, char * theContentsPtr
);
160 static int DoMount( char * theDeviceNamePtr
, const char * theMountPointPtr
, boolean_t isLocked
, boolean_t isSetuid
, boolean_t isDev
);
161 static int DoProbe( char * theDeviceNamePtr
);
162 static int DoUnmount( const char * theMountPointPtr
);
163 static int DoGetUUIDKey( const char * theDeviceNamePtr
);
164 static int DoChangeUUIDKey( const char * theDeviceNamePtr
);
165 static int DoAdopt( const char * theDeviceNamePtr
);
166 static int DoDisown( const char * theDeviceNamePtr
);
168 extern int DoMakeJournaled( const char * volNamePtr
, int journalSize
); // XXXdbg
169 extern int DoUnJournal( const char * volNamePtr
); // XXXdbg
171 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
);
173 static int GetVolumeUUID(const char *deviceNamePtr
, VolumeUUID
*volumeUUIDPtr
, boolean_t generate
);
174 static int SetVolumeUUID(const char *deviceNamePtr
, VolumeUUID
*volumeUUIDPtr
);
175 static int GetEmbeddedHFSPlusVol(HFSMasterDirectoryBlock
* hfsMasterDirectoryBlockPtr
, off_t
* startOffsetPtr
);
176 static int GetNameFromHFSPlusVolumeStartingAt(int fd
, off_t hfsPlusVolumeOffset
, char * name_o
);
177 static int GetBTreeNodeInfo(int fd
, off_t hfsPlusVolumeOffset
, u_int32_t blockSize
,
178 u_int32_t extentCount
, const HFSPlusExtentDescriptor
*extentList
,
179 u_int32_t
*nodeSize
, u_int32_t
*firstLeafNode
);
180 static int GetCatalogOverflowExtents(int fd
, off_t hfsPlusVolumeOffset
, HFSPlusVolumeHeader
*volHdrPtr
,
181 HFSPlusExtentDescriptor
**catalogExtents
, u_int32_t
*catalogExtCount
);
182 static int LogicalToPhysical(off_t logicalOffset
, ssize_t length
, u_int32_t blockSize
,
183 u_int32_t extentCount
, const HFSPlusExtentDescriptor
*extentList
,
184 off_t
*physicalOffset
, ssize_t
*availableBytes
);
185 static int ReadFile(int fd
, void *buffer
, off_t offset
, ssize_t length
,
186 off_t volOffset
, u_int32_t blockSize
,
187 u_int32_t extentCount
, const HFSPlusExtentDescriptor
*extentList
);
188 static ssize_t
readAt( int fd
, void * buf
, off_t offset
, ssize_t length
);
189 static ssize_t
writeAt( int fd
, void * buf
, off_t offset
, ssize_t length
);
191 CF_EXPORT Boolean
_CFStringGetFileSystemRepresentation(CFStringRef string
, UInt8
*buffer
, CFIndex maxBufLen
);
194 * The fuction CFStringGetSystemEncoding does not work correctly in
195 * our context (autodiskmount deamon). We include a local copy here
196 * so that we can derive the default encoding. Radar 2516316.
198 #if READ_DEFAULT_ENCODING
199 #define __kCFUserEncodingFileName ("/.CFUserTextEncoding")
201 static unsigned int __CFStringGetDefaultEncodingForHFSUtil() {
202 struct passwd
*passwdp
;
204 if ((passwdp
= getpwuid(0))) { // root account
205 char buffer
[MAXPATHLEN
+ 1];
208 strcpy(buffer
, passwdp
->pw_dir
);
209 strcat(buffer
, __kCFUserEncodingFileName
);
211 if ((fd
= open(buffer
, O_RDONLY
, 0)) > 0) {
214 readSize
= read(fd
, buffer
, MAXPATHLEN
);
215 buffer
[(readSize
< 0 ? 0 : readSize
)] = '\0';
217 return strtol(buffer
, NULL
, 0);
220 return 0; // Fallback to smRoman
224 /* ******************************************** main ************************************************
226 This our main entry point to this utility. We get called by the WorkSpace. See ParseArgs
227 for detail info on input arguments.
229 argc - the number of arguments in argv.
230 argv - array of arguments.
232 returns FSUR_IO_SUCCESS if OK else one of the other FSUR_xyz errors in loadable_fs.h.
233 *************************************************************************************************** */
235 int main (int argc
, const char *argv
[])
237 const char * actionPtr
= NULL
;
238 char rawDeviceName
[MAXPATHLEN
];
239 char blockDeviceName
[MAXPATHLEN
];
240 const char * mountPointPtr
= NULL
;
241 int result
= FSUR_IO_SUCCESS
;
242 boolean_t isLocked
= 0; /* reasonable assumptions */
243 boolean_t isSetuid
= 0; /* reasonable assumptions */
244 boolean_t isDev
= 0; /* reasonable assumptions */
246 /* Verify our arguments */
247 if ( (result
= ParseArgs( argc
, argv
, & actionPtr
, & mountPointPtr
, & gIsEjectable
, & isLocked
, &isSetuid
, &isDev
)) != 0 ) {
252 -- Build our device name (full path), should end up with something like:
256 sprintf(rawDeviceName
, "/dev/r%s", argv
[2]);
257 sprintf(blockDeviceName
, "/dev/%s", argv
[2]);
259 /* call the appropriate routine to handle the given action argument after becoming root */
261 switch( * actionPtr
) {
263 result
= DoProbe(rawDeviceName
);
267 case FSUC_MOUNT_FORCE
:
268 result
= DoMount(blockDeviceName
, mountPointPtr
, isLocked
, isSetuid
, isDev
);
272 result
= DoUnmount( mountPointPtr
);
275 result
= DoGetUUIDKey( blockDeviceName
);
279 result
= DoChangeUUIDKey( blockDeviceName
);
282 result
= DoAdopt( blockDeviceName
);
286 result
= DoDisown( blockDeviceName
);
291 result
= DoMakeJournaled( argv
[3], gJournalSize
);
293 result
= DoMakeJournaled( argv
[2], gJournalSize
);
298 result
= DoUnJournal( argv
[2] );
302 /* should never get here since ParseArgs should handle this situation */
303 DoDisplayUsage( argv
);
312 return result
; /*...and make main fit the ANSI spec. */
316 /* ***************************** DoMount ********************************
318 This routine will fire off a system command to mount the given device at the given mountpoint.
319 autodiskmount will make sure the mountpoint exists and will remove it at Unmount time.
321 deviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
322 mountPointPtr - pointer to the mount point.
325 returns FSUR_IO_SUCCESS everything is cool else one of several other FSUR_xyz error codes.
326 *********************************************************************** */
328 DoMount(char *deviceNamePtr
, const char *mountPointPtr
, boolean_t isLocked
, boolean_t isSetuid
, boolean_t isDev
)
334 char *permissionsOption
;
335 int result
= FSUR_IO_FAIL
;
337 char encodeopt
[16] = "";
338 CFStringEncoding encoding
;
339 VolumeUUID targetVolumeUUID
;
340 VolumeStatusDBHandle vsdbhandle
= NULL
;
341 unsigned long targetVolumeStatus
;
343 if (mountPointPtr
== NULL
|| *mountPointPtr
== '\0')
344 return (FSUR_IO_FAIL
);
346 /* get the volume UUID to check if permissions should be used: */
347 targetVolumeStatus
= 0;
348 if (((result
= GetVolumeUUID(deviceNamePtr
, &targetVolumeUUID
, FALSE
)) != FSUR_IO_SUCCESS
) ||
349 (targetVolumeUUID
.v
.high
==0) ||
350 (targetVolumeUUID
.v
.low
== 0)) {
352 fprintf(stderr
, "hfs.util: DoMount: GetVolumeUUID returned %d.\n", result
);
355 if (gIsEjectable
== 0) {
356 result
= DoAdopt( deviceNamePtr
);
358 fprintf(stderr
, "hfs.util: DoMount: Auto-adopting %s; result = %d.\n", deviceNamePtr
, result
);
360 targetVolumeStatus
= VOLUME_USEPERMISSIONS
;
363 fprintf(stderr
, "hfs.util: DoMount: Not adopting ejectable %s.\n", deviceNamePtr
);
365 targetVolumeStatus
= 0;
369 /* We've got a real volume UUID! */
371 fprintf(stderr
, "hfs.util: DoMount: UUID = %08lX%08lX.\n", targetVolumeUUID
.v
.high
, targetVolumeUUID
.v
.low
);
373 if ((result
= OpenVolumeStatusDB(&vsdbhandle
)) != 0) {
374 /* Can't even get access to the volume info db; assume permissions are OK. */
376 fprintf(stderr
, "hfs.util: DoMount: OpenVolumeStatusDB returned %d; ignoring permissions.\n", result
);
378 targetVolumeStatus
= VOLUME_USEPERMISSIONS
;
381 fprintf(stderr
, "hfs.util: DoMount: Looking up volume status...\n");
383 if ((result
= GetVolumeStatusDBEntry(vsdbhandle
, &targetVolumeUUID
, &targetVolumeStatus
)) != 0) {
385 fprintf(stderr
, "hfs.util: DoMount: GetVolumeStatusDBEntry returned %d.\n", result
);
388 if (gIsEjectable
== 0) {
389 result
= DoAdopt( deviceNamePtr
);
391 fprintf(stderr
, "hfs.util: DoMount: Auto-adopting %s; result = %d.\n", deviceNamePtr
, result
);
393 targetVolumeStatus
= VOLUME_USEPERMISSIONS
;
396 fprintf(stderr
, "hfs.util: DoMount: Not adopting ejectable %s.\n", deviceNamePtr
);
398 targetVolumeStatus
= 0;
401 targetVolumeStatus
= 0;
404 (void)CloseVolumeStatusDB(vsdbhandle
);
411 isLockedstr
= isLocked
? gReadOnlyOption
: gReadWriteOption
;
412 isSetuidstr
= isSetuid
? gSuidOption
: gNoSuidOption
;
413 isDevstr
= isDev
? gDevOption
: gNoDevOption
;
416 (targetVolumeStatus
& VOLUME_USEPERMISSIONS
) ? gUsePermissionsOption
: gIgnorePermissionsOption
;
418 /* get default encoding value (for hfs volumes) */
419 #if READ_DEFAULT_ENCODING
420 encoding
= __CFStringGetDefaultEncodingForHFSUtil();
422 encoding
= CFStringGetSystemEncoding();
424 sprintf(encodeopt
, "-e=%d", (int)encoding
);
426 fprintf(stderr
, "hfs.util: %s %s -o -x -o %s -o %s -o -u=unknown,-g=unknown,-m=0777 -t %s %s %s ...\n",
427 gMountCommand
, isLockedstr
, encodeopt
, permissionsOption
, gHFS_FS_NAME
, deviceNamePtr
, mountPointPtr
);
429 (void) execl(gMountCommand
, gMountCommand
, isLockedstr
, "-o", isSetuidstr
, "-o", isDevstr
,
430 "-o", encodeopt
, "-o", permissionsOption
,
431 "-o", "-u=unknown,-g=unknown,-m=0777",
432 "-t", gHFS_FS_NAME
, deviceNamePtr
, mountPointPtr
, NULL
);
435 /* IF WE ARE HERE, WE WERE UNSUCCESFULL */
436 return (FSUR_IO_FAIL
);
440 return (FSUR_IO_FAIL
);
443 if ((wait4(pid
, (int *)&status
, 0, NULL
) == pid
) && (WIFEXITED(status
)))
444 result
= status
.w_retcode
;
448 return (result
== 0) ? FSUR_IO_SUCCESS
: FSUR_IO_FAIL
;
452 /* ****************************************** DoUnmount *********************************************
454 This routine will fire off a system command to unmount the given device.
456 theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
458 returns FSUR_IO_SUCCESS everything is cool else FSUR_IO_FAIL.
459 *************************************************************************************************** */
461 DoUnmount(const char * theMountPointPtr
)
467 if (theMountPointPtr
== NULL
|| *theMountPointPtr
== '\0') return (FSUR_IO_FAIL
);
472 fprintf(stderr
, "hfs.util: %s %s ...\n", gUnmountCommand
, theMountPointPtr
);
474 (void) execl(gUnmountCommand
, gUnmountCommand
, theMountPointPtr
, NULL
);
476 /* IF WE ARE HERE, WE WERE UNSUCCESFULL */
477 return (FSUR_IO_FAIL
);
481 return (FSUR_IO_FAIL
);
484 if ((wait4(pid
, (int *)&status
, 0, NULL
) == pid
) && (WIFEXITED(status
)))
485 result
= status
.w_retcode
;
489 return (result
== 0 ? FSUR_IO_SUCCESS
: FSUR_IO_FAIL
);
494 /* ******************************************* DoProbe **********************************************
496 This routine will open the given raw device and check to make sure there is media that looks
499 theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
501 returns FSUR_MOUNT_HIDDEN (previously FSUR_RECOGNIZED) if we can handle the media else one of the FSUR_xyz error codes.
502 *************************************************************************************************** */
504 DoProbe(char *deviceNamePtr
)
506 int result
= FSUR_UNRECOGNIZED
;
509 HFSMasterDirectoryBlock
* mdbPtr
;
510 HFSPlusVolumeHeader
* volHdrPtr
;
511 u_char volnameUTF8
[NAME_MAX
+1];
513 bufPtr
= (char *)malloc(HFS_BLOCK_SIZE
);
515 result
= FSUR_UNRECOGNIZED
;
519 mdbPtr
= (HFSMasterDirectoryBlock
*) bufPtr
;
520 volHdrPtr
= (HFSPlusVolumeHeader
*) bufPtr
;
522 fd
= open( deviceNamePtr
, O_RDONLY
, 0 );
524 result
= FSUR_IO_FAIL
;
529 * Read the HFS Master Directory Block from sector 2
531 result
= readAt(fd
, bufPtr
, (off_t
)(2 * HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
532 if (FSUR_IO_FAIL
== result
)
535 /* get classic HFS volume name (from MDB) */
536 if (mdbPtr
->drSigWord
== kHFSSigWord
&&
537 mdbPtr
->drEmbedSigWord
!= kHFSPlusSigWord
) {
540 CFStringEncoding encoding
;
542 /* Some poorly mastered HFS CDs have an empty MDB name field! */
543 if (mdbPtr
->drVN
[0] == '\0') {
544 strcpy(&mdbPtr
->drVN
[1], gHFS_FS_NAME_NAME
);
545 mdbPtr
->drVN
[0] = strlen(gHFS_FS_NAME_NAME
);
548 encoding
= CFStringGetSystemEncoding();
549 cfstr
= CFStringCreateWithPascalString(kCFAllocatorDefault
,
550 mdbPtr
->drVN
, encoding
);
551 cfOK
= _CFStringGetFileSystemRepresentation(cfstr
, volnameUTF8
, NAME_MAX
);
554 if (!cfOK
&& encoding
!= kCFStringEncodingMacRoman
) {
556 /* default to MacRoman on conversion errors */
557 cfstr
= CFStringCreateWithPascalString(kCFAllocatorDefault
,
558 mdbPtr
->drVN
, kCFStringEncodingMacRoman
);
559 _CFStringGetFileSystemRepresentation(cfstr
, volnameUTF8
, NAME_MAX
);
563 /* get HFS Plus volume name (from Catalog) */
564 } else if ((volHdrPtr
->signature
== kHFSPlusSigWord
) ||
565 (mdbPtr
->drSigWord
== kHFSSigWord
&&
566 mdbPtr
->drEmbedSigWord
== kHFSPlusSigWord
)) {
569 if (volHdrPtr
->signature
== kHFSPlusSigWord
) {
571 } else {/* embedded volume, first find offset */
572 result
= GetEmbeddedHFSPlusVol(mdbPtr
, &startOffset
);
573 if ( result
!= FSUR_IO_SUCCESS
)
577 result
= GetNameFromHFSPlusVolumeStartingAt(fd
, startOffset
,
580 result
= FSUR_UNRECOGNIZED
;
583 if (FSUR_IO_SUCCESS
== result
) {
586 CFMutableStringRef volumeName
;
587 CFIndex volumeNameLength
;
588 CFRange foundSubString
;
590 slash
= CFStringCreateWithCString(kCFAllocatorDefault
, "/", kCFStringEncodingUTF8
);
592 result
= FSUR_IO_FAIL
;
596 colon
= CFStringCreateWithCString(kCFAllocatorDefault
, ":", kCFStringEncodingUTF8
);
598 result
= FSUR_IO_FAIL
;
602 volumeName
= CFStringCreateMutableCopy(
605 CFStringCreateWithCString(kCFAllocatorDefault
, volnameUTF8
, kCFStringEncodingUTF8
));
606 if (volumeName
== NULL
) {
607 result
= FSUR_IO_FAIL
;
610 volumeNameLength
= CFStringGetLength(volumeName
);
612 while (CFStringFindWithOptions(volumeName
, slash
, CFRangeMake(0, volumeNameLength
-1), 0, &foundSubString
)) {
613 CFStringReplace(volumeName
, foundSubString
, colon
);
616 CFStringGetCString(volumeName
, volnameUTF8
, NAME_MAX
, kCFStringEncodingUTF8
);
617 write(1, volnameUTF8
, strlen(volnameUTF8
));
619 /* backwards compatibility */
620 DoFileSystemFile( FS_NAME_SUFFIX
, gHFS_FS_NAME
);
621 DoFileSystemFile( FS_LABEL_SUFFIX
, volnameUTF8
);
622 result
= FSUR_MOUNT_HIDDEN
;
639 /* **************************************** DoGetUUIDKey *******************************************
641 This routine will open the given block device and return the volume UUID in text form written to stdout.
643 theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
645 returns FSUR_IO_SUCCESS or else one of the FSUR_xyz error codes.
646 *************************************************************************************************** */
648 DoGetUUIDKey( const char * theDeviceNamePtr
) {
650 VolumeUUID targetVolumeUUID
;
651 VolumeUUIDString UUIDString
;
652 char uuidLine
[VOLUMEUUIDLENGTH
+2];
654 if ((result
= GetVolumeUUID(theDeviceNamePtr
, &targetVolumeUUID
, FALSE
)) != FSUR_IO_SUCCESS
) goto Err_Exit
;
656 ConvertVolumeUUIDToString( &targetVolumeUUID
, UUIDString
);
657 strncpy(uuidLine
, UUIDString
, VOLUMEUUIDLENGTH
+1);
658 write(1, uuidLine
, strlen(uuidLine
));
659 result
= FSUR_IO_SUCCESS
;
667 /* *************************************** DoChangeUUIDKey ******************************************
669 This routine will change the UUID on the specified block device.
671 theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
673 returns FSUR_IO_SUCCESS or else one of the FSUR_xyz error codes.
674 *************************************************************************************************** */
676 DoChangeUUIDKey( const char * theDeviceNamePtr
) {
678 VolumeUUID newVolumeUUID
;
680 GenerateVolumeUUID(&newVolumeUUID
);
681 result
= SetVolumeUUID(theDeviceNamePtr
, &newVolumeUUID
);
688 /* **************************************** DoAdopt *******************************************
690 This routine will add the UUID of the specified block device to the list of local volumes.
692 theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
694 returns FSUR_IO_SUCCESS or else one of the FSUR_xyz error codes.
695 *************************************************************************************************** */
697 DoAdopt( const char * theDeviceNamePtr
) {
698 int result
, closeresult
;
699 VolumeUUID targetVolumeUUID
;
700 VolumeStatusDBHandle vsdbhandle
= NULL
;
701 unsigned long targetVolumeStatus
;
703 if ((result
= GetVolumeUUID(theDeviceNamePtr
, &targetVolumeUUID
, TRUE
)) != FSUR_IO_SUCCESS
) goto Err_Return
;
705 if ((result
= OpenVolumeStatusDB(&vsdbhandle
)) != 0) goto Err_Exit
;
706 if ((result
= GetVolumeStatusDBEntry(vsdbhandle
, &targetVolumeUUID
, &targetVolumeStatus
)) != 0) {
707 targetVolumeStatus
= 0;
709 targetVolumeStatus
= (targetVolumeStatus
& VOLUME_VALIDSTATUSBITS
) | VOLUME_USEPERMISSIONS
;
710 if ((result
= SetVolumeStatusDBEntry(vsdbhandle
, &targetVolumeUUID
, targetVolumeStatus
)) != 0) goto Err_Exit
;
712 result
= FSUR_IO_SUCCESS
;
716 closeresult
= CloseVolumeStatusDB(vsdbhandle
);
718 if (result
== FSUR_IO_SUCCESS
) result
= closeresult
;
721 if ((result
!= 0) && (result
!= FSUR_IO_SUCCESS
)) result
= FSUR_IO_FAIL
;
725 if (result
!= FSUR_IO_SUCCESS
) fprintf(stderr
, "DoAdopt: returning %d...\n", result
);
732 /* **************************************** DoDisown *******************************************
734 This routine will change the status of the specified block device to ignore its permissions.
736 theDeviceNamePtr - pointer to the device name (full path, like /dev/disk0s2).
738 returns FSUR_IO_SUCCESS or else one of the FSUR_xyz error codes.
739 *************************************************************************************************** */
741 DoDisown( const char * theDeviceNamePtr
) {
742 int result
, closeresult
;
743 VolumeUUID targetVolumeUUID
;
744 VolumeStatusDBHandle vsdbhandle
= NULL
;
745 unsigned long targetVolumeStatus
;
747 if ((result
= GetVolumeUUID(theDeviceNamePtr
, &targetVolumeUUID
, TRUE
)) != FSUR_IO_SUCCESS
) goto Err_Return
;
749 if ((result
= OpenVolumeStatusDB(&vsdbhandle
)) != 0) goto Err_Exit
;
750 if ((result
= GetVolumeStatusDBEntry(vsdbhandle
, &targetVolumeUUID
, &targetVolumeStatus
)) != 0) {
751 targetVolumeStatus
= 0;
753 targetVolumeStatus
= (targetVolumeStatus
& VOLUME_VALIDSTATUSBITS
) & ~VOLUME_USEPERMISSIONS
;
754 if ((result
= SetVolumeStatusDBEntry(vsdbhandle
, &targetVolumeUUID
, targetVolumeStatus
)) != 0) goto Err_Exit
;
756 result
= FSUR_IO_SUCCESS
;
760 closeresult
= CloseVolumeStatusDB(vsdbhandle
);
762 if (result
== FSUR_IO_SUCCESS
) result
= closeresult
;
765 if ((result
!= 0) && (result
!= FSUR_IO_SUCCESS
)) {
767 if (result
!= 0) fprintf(stderr
, "DoDisown: result = %d; changing to %d...\n", result
, FSUR_IO_FAIL
);
769 result
= FSUR_IO_FAIL
;
774 if (result
!= FSUR_IO_SUCCESS
) fprintf(stderr
, "DoDisown: returning %d...\n", result
);
781 get_multiplier(char c
)
783 if (tolower(c
) == 'k') {
785 } else if (tolower(c
) == 'm') {
787 } else if (tolower(c
) == 'g') {
788 return 1024 * 1024 * 1024;
794 /* **************************************** ParseArgs ********************************************
796 This routine will make sure the arguments passed in to us are cool.
797 Here is how this utility is used:
799 usage: hfs.util actionArg deviceArg [mountPointArg] [flagsArg]
801 -p (Probe for mounting)
802 -P (Probe for initializing - not supported)
804 -r (Repair - not supported)
807 -i (Initialize - not supported)
810 disk0s2 (for example)
813 /foo/bar/ (required for Mount and Force Mount actions)
816 (these are ignored for CDROMs)
817 either "readonly" OR "writable"
818 either "removable" OR "fixed"
819 either "nosuid" or "suid"
822 hfs.util -p disk0s2 removable writable
823 hfs.util -p disk0s2 removable readonly
824 hfs.util -m disk0s2 /my/hfs
827 argc - the number of arguments in argv.
828 argv - array of arguments.
830 returns FSUR_INVAL if we find a bad argument else 0.
831 *************************************************************************************************** */
833 ParseArgs(int argc
, const char *argv
[], const char ** actionPtr
,
834 const char ** mountPointPtr
, boolean_t
* isEjectablePtr
,
835 boolean_t
* isLockedPtr
, boolean_t
* isSetuidPtr
, boolean_t
* isDevPtr
)
837 int result
= FSUR_INVAL
;
838 int deviceLength
, doLengthCheck
= 1;
842 /* Must have at least 3 arguments and the action argument must start with a '-' */
843 if ( (argc
< 3) || (argv
[1][0] != '-') ) {
844 DoDisplayUsage( argv
);
848 /* we only support actions Probe, Mount, Force Mount, and Unmount */
850 * actionPtr
= & argv
[1][1];
852 switch ( argv
[1][1] ) {
854 /* action Probe and requires 5 arguments (need the flags) */
856 DoDisplayUsage( argv
);
864 /* Note: the device argument in argv[2] is checked further down but ignored. */
865 * mountPointPtr
= argv
[3];
866 index
= 0; /* No isEjectable/isLocked flags for unmount. */
870 case FSUC_MOUNT_FORCE
:
871 /* action Mount and ForceMount require 7 arguments (need the mountpoint and the flags) */
873 DoDisplayUsage( argv
);
876 * mountPointPtr
= argv
[3];
902 if (isdigit(argv
[2][0])) {
904 gJournalSize
= strtoul(argv
[2], &ptr
, 0);
906 gJournalSize
*= get_multiplier(*ptr
);
919 DoDisplayUsage( argv
);
924 /* Make sure device (argv[2]) is something reasonable */
925 deviceLength
= strlen( argv
[2] );
926 if ( doLengthCheck
&& (deviceLength
< 3 || deviceLength
> NAME_MAX
) ) {
927 DoDisplayUsage( argv
);
932 /* Flags: removable/fixed. */
933 if ( 0 == strcmp(argv
[index
],"removable") ) {
934 * isEjectablePtr
= 1;
935 } else if ( 0 == strcmp(argv
[index
],"fixed") ) {
936 * isEjectablePtr
= 0;
938 printf("hfs.util: ERROR: unrecognized flag (removable/fixed) argv[%d]='%s'\n",index
,argv
[index
]);
941 /* Flags: readonly/writable. */
942 if ( 0 == strcmp(argv
[index
+1],"readonly") ) {
944 } else if ( 0 == strcmp(argv
[index
+1],"writable") ) {
947 printf("hfs.util: ERROR: unrecognized flag (readonly/writable) argv[%d]='%s'\n",index
,argv
[index
+1]);
951 /* Flags: suid/nosuid. */
952 if ( 0 == strcmp(argv
[index
+2],"suid") ) {
954 } else if ( 0 == strcmp(argv
[index
+2],"nosuid") ) {
957 printf("hfs.util: ERROR: unrecognized flag (suid/nosuid) argv[%d]='%s'\n",index
,argv
[index
+2]);
960 /* Flags: dev/nodev. */
961 if ( 0 == strcmp(argv
[index
+3],"dev") ) {
963 } else if ( 0 == strcmp(argv
[index
+3],"nodev") ) {
966 printf("hfs.util: ERROR: unrecognized flag (dev/nodev) argv[%d]='%s'\n",index
,argv
[index
+3]);
981 /* *************************************** DoDisplayUsage ********************************************
983 This routine will do a printf of the correct usage for this utility.
985 argv - array of arguments.
988 *************************************************************************************************** */
990 DoDisplayUsage(const char *argv
[])
992 printf("usage: %s action_arg device_arg [mount_point_arg] [Flags] \n", argv
[0]);
993 printf("action_arg:\n");
994 printf(" -%c (Probe for mounting)\n", FSUC_PROBE
);
995 printf(" -%c (Mount)\n", FSUC_MOUNT
);
996 printf(" -%c (Unmount)\n", FSUC_UNMOUNT
);
997 printf(" -%c (Force Mount)\n", FSUC_MOUNT_FORCE
);
998 #ifdef HFS_UUID_SUPPORT
999 printf(" -%c (Get UUID Key)\n", FSUC_GETUUID
);
1000 printf(" -%c (Set UUID Key)\n", FSUC_SETUUID
);
1001 #endif HFS_UUID_SUPPORT
1002 printf(" -%c (Adopt permissions)\n", FSUC_ADOPT
);
1003 printf(" -%c (Make a volume journaled)\n", FSUC_MKJNL
);
1004 printf(" -%c (Turn off journaling on a volume)\n", FSUC_UNJNL
);
1005 printf("device_arg:\n");
1006 printf(" device we are acting upon (for example, 'disk0s2')\n");
1007 printf(" if '-%c' or '-%c' is specified, this should be the\n", FSUC_MKJNL
, FSUC_UNJNL
);
1008 printf(" name of the volume we to act on (for example, '/Volumes/foo' or '/')\n");
1009 printf("mount_point_arg:\n");
1010 printf(" required for Mount and Force Mount \n");
1012 printf(" required for Mount, Force Mount and Probe\n");
1013 printf(" indicates removable or fixed (for example 'fixed')\n");
1014 printf(" indicates readonly or writable (for example 'readonly')\n");
1015 printf("Examples:\n");
1016 printf(" %s -p disk0s2 fixed writable\n", argv
[0]);
1017 printf(" %s -m disk0s2 /my/hfs removable readonly\n", argv
[0]);
1021 } /* DoDisplayUsage */
1024 /* ************************************** DoFileSystemFile *******************************************
1026 This routine will create a file system info file that is used by WorkSpace. After creating the
1027 file it will write whatever theContentsPtr points to the new file.
1028 We end up with a file something like:
1029 /System/Library/Filesystems/hfs.fs/hfs.name
1030 when our file system name is "hfs" and theFileNameSuffixPtr points to ".name"
1032 theFileNameSuffixPtr - pointer to a suffix we add to the file name we're creating.
1033 theContentsPtr - pointer to C string to write into the file.
1036 *************************************************************************************************** */
1038 DoFileSystemFile(char *fileNameSuffixPtr
, char *contentsPtr
)
1041 char fileName
[MAXPATHLEN
];
1043 sprintf(fileName
, "%s/%s%s/%s", FS_DIR_LOCATION
, gHFS_FS_NAME
,
1044 FS_DIR_SUFFIX
, gHFS_FS_NAME
);
1045 strcat(fileName
, fileNameSuffixPtr
);
1046 unlink(fileName
); /* delete existing string */
1048 if ( strlen( fileNameSuffixPtr
) ) {
1049 int oldMask
= umask(0);
1051 fd
= open( & fileName
[0], O_CREAT
| O_TRUNC
| O_WRONLY
, 0644 );
1054 write( fd
, contentsPtr
, strlen( contentsPtr
) );
1061 } /* DoFileSystemFile */
1066 -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1070 GetVolumeUUID(const char *deviceNamePtr
, VolumeUUID
*volumeUUIDPtr
, boolean_t generate
) {
1073 HFSMasterDirectoryBlock
* mdbPtr
;
1074 HFSPlusVolumeHeader
* volHdrPtr
;
1075 VolumeUUID
*finderInfoUUIDPtr
;
1078 bufPtr
= (char *)malloc(HFS_BLOCK_SIZE
);
1080 result
= FSUR_UNRECOGNIZED
;
1084 mdbPtr
= (HFSMasterDirectoryBlock
*) bufPtr
;
1085 volHdrPtr
= (HFSPlusVolumeHeader
*) bufPtr
;
1087 fd
= open( deviceNamePtr
, O_RDWR
, 0 );
1089 fd
= open( deviceNamePtr
, O_RDONLY
, 0);
1092 fprintf(stderr
, "hfs.util: GetVolumeUUID: device open failed (errno = %d).\n", errno
);
1094 result
= FSUR_IO_FAIL
;
1100 * Read the HFS Master Directory Block from sector 2
1102 result
= readAt(fd
, volHdrPtr
, (off_t
)(2 * HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1103 if (result
!= FSUR_IO_SUCCESS
) {
1107 if (mdbPtr
->drSigWord
== kHFSSigWord
&&
1108 mdbPtr
->drEmbedSigWord
!= kHFSPlusSigWord
) {
1109 finderInfoUUIDPtr
= (VolumeUUID
*)(&mdbPtr
->drFndrInfo
[6]);
1110 if (generate
&& ((finderInfoUUIDPtr
->v
.high
== 0) || (finderInfoUUIDPtr
->v
.low
== 0))) {
1111 GenerateVolumeUUID(volumeUUIDPtr
);
1112 bcopy(volumeUUIDPtr
, finderInfoUUIDPtr
, sizeof(*finderInfoUUIDPtr
));
1113 result
= writeAt(fd
, volHdrPtr
, (off_t
)(2 * HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1114 if (result
!= FSUR_IO_SUCCESS
) goto Err_Exit
;
1116 bcopy(finderInfoUUIDPtr
, volumeUUIDPtr
, sizeof(*volumeUUIDPtr
));
1117 result
= FSUR_IO_SUCCESS
;
1118 } else if ((volHdrPtr
->signature
== kHFSPlusSigWord
) ||
1119 ((mdbPtr
->drSigWord
== kHFSSigWord
) &&
1120 (mdbPtr
->drEmbedSigWord
== kHFSPlusSigWord
))) {
1123 if (volHdrPtr
->signature
== kHFSPlusSigWord
) {
1125 } else {/* embedded volume, first find offset */
1126 result
= GetEmbeddedHFSPlusVol(mdbPtr
, &startOffset
);
1127 if ( result
!= FSUR_IO_SUCCESS
) {
1132 result
= readAt( fd
, volHdrPtr
, startOffset
+ (off_t
)(2*HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1133 if (result
!= FSUR_IO_SUCCESS
) {
1134 goto Err_Exit
; // return FSUR_IO_FAIL
1137 /* Verify that it is an HFS+ volume. */
1139 if (volHdrPtr
->signature
!= kHFSPlusSigWord
) {
1140 result
= FSUR_IO_FAIL
;
1144 finderInfoUUIDPtr
= (VolumeUUID
*)&volHdrPtr
->finderInfo
[24];
1145 if (generate
&& ((finderInfoUUIDPtr
->v
.high
== 0) || (finderInfoUUIDPtr
->v
.low
== 0))) {
1146 GenerateVolumeUUID(volumeUUIDPtr
);
1147 bcopy(volumeUUIDPtr
, finderInfoUUIDPtr
, sizeof(*finderInfoUUIDPtr
));
1148 result
= writeAt( fd
, volHdrPtr
, startOffset
+ (off_t
)(2*HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1149 if (result
!= FSUR_IO_SUCCESS
) {
1153 bcopy(finderInfoUUIDPtr
, volumeUUIDPtr
, sizeof(*volumeUUIDPtr
));
1154 result
= FSUR_IO_SUCCESS
;
1156 result
= FSUR_UNRECOGNIZED
;
1160 if (fd
> 0) close(fd
);
1161 if (bufPtr
) free(bufPtr
);
1164 if (result
!= FSUR_IO_SUCCESS
) fprintf(stderr
, "hfs.util: GetVolumeUUID: result = %d...\n", result
);
1166 return (result
== FSUR_IO_SUCCESS
) ? FSUR_IO_SUCCESS
: FSUR_IO_FAIL
;
1174 -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1178 SetVolumeUUID(const char *deviceNamePtr
, VolumeUUID
*volumeUUIDPtr
) {
1181 HFSMasterDirectoryBlock
* mdbPtr
;
1182 HFSPlusVolumeHeader
* volHdrPtr
;
1183 VolumeUUID
*finderInfoUUIDPtr
;
1186 bufPtr
= (char *)malloc(HFS_BLOCK_SIZE
);
1188 result
= FSUR_UNRECOGNIZED
;
1192 mdbPtr
= (HFSMasterDirectoryBlock
*) bufPtr
;
1193 volHdrPtr
= (HFSPlusVolumeHeader
*) bufPtr
;
1195 fd
= open( deviceNamePtr
, O_RDWR
, 0 );
1198 fprintf(stderr
, "hfs.util: SetVolumeUUID: device open failed (errno = %d).\n", errno
);
1200 result
= FSUR_IO_FAIL
;
1205 * Read the HFS Master Directory Block from sector 2
1207 result
= readAt(fd
, volHdrPtr
, (off_t
)(2 * HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1208 if (result
!= FSUR_IO_SUCCESS
) {
1212 if (mdbPtr
->drSigWord
== kHFSSigWord
&&
1213 mdbPtr
->drEmbedSigWord
!= kHFSPlusSigWord
) {
1214 finderInfoUUIDPtr
= (VolumeUUID
*)(&mdbPtr
->drFndrInfo
[6]);
1215 bcopy(volumeUUIDPtr
, finderInfoUUIDPtr
, sizeof(*finderInfoUUIDPtr
));
1216 result
= writeAt(fd
, volHdrPtr
, (off_t
)(2 * HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1217 } else if ((volHdrPtr
->signature
== kHFSPlusSigWord
) ||
1218 ((mdbPtr
->drSigWord
== kHFSSigWord
) &&
1219 (mdbPtr
->drEmbedSigWord
== kHFSPlusSigWord
))) {
1222 if (volHdrPtr
->signature
== kHFSPlusSigWord
) {
1224 } else {/* embedded volume, first find offset */
1225 result
= GetEmbeddedHFSPlusVol(mdbPtr
, &startOffset
);
1226 if ( result
!= FSUR_IO_SUCCESS
) {
1231 result
= readAt( fd
, volHdrPtr
, startOffset
+ (off_t
)(2*HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1232 if (result
!= FSUR_IO_SUCCESS
) {
1233 goto Err_Exit
; // return FSUR_IO_FAIL
1236 /* Verify that it is an HFS+ volume. */
1238 if (volHdrPtr
->signature
!= kHFSPlusSigWord
) {
1239 result
= FSUR_IO_FAIL
;
1243 finderInfoUUIDPtr
= (VolumeUUID
*)&volHdrPtr
->finderInfo
[24];
1244 bcopy(volumeUUIDPtr
, finderInfoUUIDPtr
, sizeof(*finderInfoUUIDPtr
));
1245 result
= writeAt( fd
, volHdrPtr
, startOffset
+ (off_t
)(2*HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1246 if (result
!= FSUR_IO_SUCCESS
) {
1249 result
= FSUR_IO_SUCCESS
;
1251 result
= FSUR_UNRECOGNIZED
;
1255 if (fd
> 0) close(fd
);
1256 if (bufPtr
) free(bufPtr
);
1259 if (result
!= FSUR_IO_SUCCESS
) fprintf(stderr
, "hfs.util: SetVolumeUUID: result = %d...\n", result
);
1261 return (result
== FSUR_IO_SUCCESS
) ? FSUR_IO_SUCCESS
: FSUR_IO_FAIL
;
1267 -- GetEmbeddedHFSPlusVol
1269 -- In: hfsMasterDirectoryBlockPtr
1270 -- Out: startOffsetPtr - the disk offset at which the HFS+ volume starts
1271 (that is, 2 blocks before the volume header)
1276 GetEmbeddedHFSPlusVol (HFSMasterDirectoryBlock
* hfsMasterDirectoryBlockPtr
, off_t
* startOffsetPtr
)
1278 int result
= FSUR_IO_SUCCESS
;
1279 u_int32_t allocationBlockSize
, firstAllocationBlock
, startBlock
, blockCount
;
1281 if (hfsMasterDirectoryBlockPtr
->drSigWord
!= kHFSSigWord
) {
1282 result
= FSUR_UNRECOGNIZED
;
1286 allocationBlockSize
= hfsMasterDirectoryBlockPtr
->drAlBlkSiz
;
1287 firstAllocationBlock
= hfsMasterDirectoryBlockPtr
->drAlBlSt
;
1289 if (hfsMasterDirectoryBlockPtr
->drEmbedSigWord
!= kHFSPlusSigWord
) {
1290 result
= FSUR_UNRECOGNIZED
;
1294 startBlock
= hfsMasterDirectoryBlockPtr
->drEmbedExtent
.startBlock
;
1295 blockCount
= hfsMasterDirectoryBlockPtr
->drEmbedExtent
.blockCount
;
1297 if ( startOffsetPtr
)
1298 *startOffsetPtr
= ((u_int64_t
)startBlock
* (u_int64_t
)allocationBlockSize
) +
1299 ((u_int64_t
)firstAllocationBlock
* (u_int64_t
)HFS_BLOCK_SIZE
);
1309 -- GetNameFromHFSPlusVolumeStartingAt
1311 -- Caller's responsibility to allocate and release memory for the converted string.
1313 -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1317 GetNameFromHFSPlusVolumeStartingAt(int fd
, off_t hfsPlusVolumeOffset
, char * name_o
)
1319 int result
= FSUR_IO_SUCCESS
;
1320 u_int32_t blockSize
;
1321 char * bufPtr
= NULL
;
1322 HFSPlusVolumeHeader
* volHdrPtr
;
1323 BTNodeDescriptor
* bTreeNodeDescriptorPtr
;
1324 u_int32_t catalogNodeSize
;
1326 u_int32_t catalogExtCount
;
1327 HFSPlusExtentDescriptor
*catalogExtents
= NULL
;
1329 volHdrPtr
= (HFSPlusVolumeHeader
*)malloc(HFS_BLOCK_SIZE
);
1330 if ( ! volHdrPtr
) {
1331 result
= FSUR_IO_FAIL
;
1336 * Read the Volume Header
1337 * (This is a little redundant for a pure, unwrapped HFS+ volume)
1339 result
= readAt( fd
, volHdrPtr
, hfsPlusVolumeOffset
+ (off_t
)(2*HFS_BLOCK_SIZE
), HFS_BLOCK_SIZE
);
1340 if (result
== FSUR_IO_FAIL
) {
1342 fprintf(stderr
, "hfs.util: GetNameFromHFSPlusVolumeStartingAt: readAt failed\n");
1344 goto Return
; // return FSUR_IO_FAIL
1347 /* Verify that it is an HFS+ volume. */
1349 if (volHdrPtr
->signature
!= kHFSPlusSigWord
) {
1350 result
= FSUR_IO_FAIL
;
1352 fprintf(stderr
, "hfs.util: GetNameFromHFSPlusVolumeStartingAt: volHdrPtr->signature != kHFSPlusSigWord\n");
1357 blockSize
= volHdrPtr
->blockSize
;
1358 catalogExtents
= (HFSPlusExtentDescriptor
*) malloc(sizeof(HFSPlusExtentRecord
));
1359 if ( ! catalogExtents
) {
1360 result
= FSUR_IO_FAIL
;
1363 bcopy(volHdrPtr
->catalogFile
.extents
, catalogExtents
, sizeof(HFSPlusExtentRecord
));
1364 catalogExtCount
= kHFSPlusExtentDensity
;
1366 /* if there are overflow catalog extents, then go get them */
1367 if (catalogExtents
[7].blockCount
!= 0) {
1368 result
= GetCatalogOverflowExtents(fd
, hfsPlusVolumeOffset
, volHdrPtr
, &catalogExtents
, &catalogExtCount
);
1369 if (result
!= FSUR_IO_SUCCESS
)
1373 /* Read the header node of the catalog B-Tree */
1375 result
= GetBTreeNodeInfo(fd
, hfsPlusVolumeOffset
, blockSize
,
1376 catalogExtCount
, catalogExtents
,
1377 &catalogNodeSize
, &leafNode
);
1378 if (result
!= FSUR_IO_SUCCESS
)
1381 /* Read the first leaf node of the catalog b-tree */
1383 bufPtr
= (char *)malloc(catalogNodeSize
);
1385 result
= FSUR_IO_FAIL
;
1389 bTreeNodeDescriptorPtr
= (BTNodeDescriptor
*)bufPtr
;
1391 result
= ReadFile(fd
, bufPtr
, (off_t
) leafNode
* (off_t
) catalogNodeSize
, catalogNodeSize
,
1392 hfsPlusVolumeOffset
, blockSize
,
1393 catalogExtCount
, catalogExtents
);
1394 if (result
== FSUR_IO_FAIL
) {
1396 fprintf(stderr
, "hfs.util: ERROR: reading first leaf failed\n");
1398 goto Return
; // return FSUR_IO_FAIL
1404 HFSPlusCatalogKey
* k
;
1407 if ( bTreeNodeDescriptorPtr
->numRecords
< 1) {
1408 result
= FSUR_IO_FAIL
;
1410 fprintf(stderr
, "hfs.util: ERROR: bTreeNodeDescriptorPtr->numRecords < 1\n");
1415 // Get the offset (in bytes) of the first record from the list of offsets at the end of the node.
1417 p
= bufPtr
+ catalogNodeSize
- sizeof(u_int16_t
); // pointer arithmetic in bytes
1420 // Get a pointer to the first record.
1422 p
= bufPtr
+ *v
; // pointer arithmetic in bytes
1423 k
= (HFSPlusCatalogKey
*)p
;
1425 // There should be only one record whose parent is the root parent. It should be the first record.
1427 if (k
->parentID
!= kHFSRootParentID
) {
1428 result
= FSUR_IO_FAIL
;
1430 fprintf(stderr
, "hfs.util: ERROR: k->parentID != kHFSRootParentID\n");
1435 /* Extract the name of the root directory */
1437 cfstr
= CFStringCreateWithCharacters(kCFAllocatorDefault
, k
->nodeName
.unicode
, k
->nodeName
.length
);
1438 (void) CFStringGetCString(cfstr
, name_o
, NAME_MAX
, kCFStringEncodingUTF8
);
1442 result
= FSUR_IO_SUCCESS
;
1446 free((char*) volHdrPtr
);
1449 free((char*) catalogExtents
);
1452 free((char*)bufPtr
);
1456 } /* GetNameFromHFSPlusVolumeStartingAt */
1459 #pragma options align=mac68k
1461 BTNodeDescriptor node
;
1463 } HeaderRec
, *HeaderPtr
;
1464 #pragma options align=reset
1469 -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1473 GetBTreeNodeInfo(int fd
, off_t hfsPlusVolumeOffset
, u_int32_t blockSize
,
1474 u_int32_t extentCount
, const HFSPlusExtentDescriptor
*extentList
,
1475 u_int32_t
*nodeSize
, u_int32_t
*firstLeafNode
)
1478 HeaderRec
* bTreeHeaderPtr
= NULL
;
1480 bTreeHeaderPtr
= (HeaderRec
*) malloc(HFS_BLOCK_SIZE
);
1481 if (bTreeHeaderPtr
== NULL
)
1482 return (FSUR_IO_FAIL
);
1484 /* Read the b-tree header node */
1486 result
= ReadFile(fd
, bTreeHeaderPtr
, 0, HFS_BLOCK_SIZE
,
1487 hfsPlusVolumeOffset
, blockSize
,
1488 extentCount
, extentList
);
1489 if ( result
== FSUR_IO_FAIL
) {
1491 fprintf(stderr
, "hfs.util: ERROR: reading header node failed\n");
1496 if ( bTreeHeaderPtr
->node
.kind
!= kBTHeaderNode
) {
1497 result
= FSUR_IO_FAIL
;
1499 fprintf(stderr
, "hfs.util: ERROR: bTreeHeaderPtr->node.kind != kBTHeaderNode\n");
1504 *nodeSize
= bTreeHeaderPtr
->header
.nodeSize
;
1506 if (bTreeHeaderPtr
->header
.leafRecords
== 0)
1509 *firstLeafNode
= bTreeHeaderPtr
->header
.firstLeafNode
;
1512 free((char*) bTreeHeaderPtr
);
1516 } /* GetBTreeNodeInfo */
1522 -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1526 GetCatalogOverflowExtents(int fd
, off_t hfsPlusVolumeOffset
,
1527 HFSPlusVolumeHeader
*volHdrPtr
,
1528 HFSPlusExtentDescriptor
**catalogExtents
,
1529 u_int32_t
*catalogExtCount
)
1534 BTNodeDescriptor
* bTreeNodeDescriptorPtr
;
1535 HFSPlusExtentDescriptor
* extents
;
1537 char * bufPtr
= NULL
;
1541 listsize
= *catalogExtCount
* sizeof(HFSPlusExtentDescriptor
);
1542 extents
= *catalogExtents
;
1543 offset
= (off_t
)volHdrPtr
->extentsFile
.extents
[0].startBlock
*
1544 (off_t
)volHdrPtr
->blockSize
;
1546 /* Read the header node of the extents B-Tree */
1548 result
= GetBTreeNodeInfo(fd
, hfsPlusVolumeOffset
, volHdrPtr
->blockSize
,
1549 kHFSPlusExtentDensity
, volHdrPtr
->extentsFile
.extents
,
1550 &nodeSize
, &leafNode
);
1551 if (result
!= FSUR_IO_SUCCESS
|| leafNode
== 0)
1554 /* Calculate the logical position of the first leaf node */
1556 offset
= (off_t
) leafNode
* (off_t
) nodeSize
;
1558 /* Read the first leaf node of the extents b-tree */
1560 bufPtr
= (char *)malloc(nodeSize
);
1562 result
= FSUR_IO_FAIL
;
1566 bTreeNodeDescriptorPtr
= (BTNodeDescriptor
*)bufPtr
;
1569 result
= ReadFile(fd
, bufPtr
, offset
, nodeSize
,
1570 hfsPlusVolumeOffset
, volHdrPtr
->blockSize
,
1571 kHFSPlusExtentDensity
, volHdrPtr
->extentsFile
.extents
);
1572 if ( result
== FSUR_IO_FAIL
) {
1574 fprintf(stderr
, "hfs.util: ERROR: reading first leaf failed\n");
1579 if (bTreeNodeDescriptorPtr
->kind
!= kBTLeafNode
) {
1580 result
= FSUR_IO_FAIL
;
1584 for (i
= 1; i
<= bTreeNodeDescriptorPtr
->numRecords
; ++i
) {
1587 HFSPlusExtentKey
* k
;
1590 * Get the offset (in bytes) of the record from the
1591 * list of offsets at the end of the node
1593 p
= bufPtr
+ nodeSize
- (sizeof(u_int16_t
) * i
);
1596 /* Get a pointer to the record */
1598 p
= bufPtr
+ *v
; /* pointer arithmetic in bytes */
1599 k
= (HFSPlusExtentKey
*)p
;
1601 if (k
->fileID
!= kHFSCatalogFileID
)
1604 /* grow list and copy additional extents */
1605 listsize
+= sizeof(HFSPlusExtentRecord
);
1606 extents
= (HFSPlusExtentDescriptor
*) realloc(extents
, listsize
);
1607 bcopy(p
+ k
->keyLength
+ sizeof(u_int16_t
),
1608 &extents
[*catalogExtCount
], sizeof(HFSPlusExtentRecord
));
1610 *catalogExtCount
+= kHFSPlusExtentDensity
;
1611 *catalogExtents
= extents
;
1614 if ((leafNode
= bTreeNodeDescriptorPtr
->fLink
) != 0) {
1616 offset
= (off_t
) leafNode
* (off_t
) nodeSize
;
1631 * LogicalToPhysical - Map a logical file position and size to volume-relative physical
1632 * position and number of contiguous bytes at that position.
1635 * logicalOffset Logical offset in bytes from start of file
1636 * length Maximum number of bytes to map
1637 * blockSize Number of bytes per allocation block
1638 * extentCount Number of extents in file
1639 * extentList The file's extents
1642 * physicalOffset Physical offset in bytes from start of volume
1643 * availableBytes Number of bytes physically contiguous (up to length)
1645 * Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1647 static int LogicalToPhysical(off_t offset
, ssize_t length
, u_int32_t blockSize
,
1648 u_int32_t extentCount
, const HFSPlusExtentDescriptor
*extentList
,
1649 off_t
*physicalOffset
, ssize_t
*availableBytes
)
1652 u_int32_t logicalBlock
;
1654 u_int32_t blockCount
= 0;
1656 /* Determine allocation block containing logicalOffset */
1657 logicalBlock
= offset
/ blockSize
; /* This can't overflow for valid volumes */
1658 offset
%= blockSize
; /* Offset from start of allocation block */
1660 /* Find the extent containing logicalBlock */
1661 for (extent
= 0; extent
< extentCount
; ++extent
)
1663 blockCount
= extentList
[extent
].blockCount
;
1665 if (blockCount
== 0)
1666 return FSUR_IO_FAIL
; /* Tried to map past physical end of file */
1668 if (logicalBlock
< blockCount
)
1669 break; /* Found it! */
1671 logicalBlock
-= blockCount
;
1674 if (extent
>= extentCount
)
1675 return FSUR_IO_FAIL
; /* Tried to map past physical end of file */
1678 * When we get here, extentList[extent] is the extent containing logicalOffset.
1679 * The desired allocation block is logicalBlock blocks into the extent.
1682 /* Compute the physical starting position */
1683 temp
= extentList
[extent
].startBlock
+ logicalBlock
; /* First physical block */
1684 temp
*= blockSize
; /* Byte offset of first physical block */
1685 *physicalOffset
= temp
+ offset
;
1687 /* Compute the available contiguous bytes. */
1688 temp
= blockCount
- logicalBlock
; /* Number of blocks available in extent */
1690 temp
-= offset
; /* Number of bytes available */
1693 *availableBytes
= temp
;
1695 *availableBytes
= length
;
1697 return FSUR_IO_SUCCESS
;
1703 * ReadFile - Read bytes from a file. Handles cases where the starting and/or
1704 * ending position are not allocation or device block aligned.
1707 * fd Descriptor for reading the volume
1708 * buffer The bytes are read into here
1709 * offset Offset in file to start reading
1710 * length Number of bytes to read
1711 * volOffset Byte offset from start of device to start of volume
1712 * blockSize Number of bytes per allocation block
1713 * extentCount Number of extents in file
1714 * extentList The file's exents
1716 * Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1718 static int ReadFile(int fd
, void *buffer
, off_t offset
, ssize_t length
,
1719 off_t volOffset
, u_int32_t blockSize
,
1720 u_int32_t extentCount
, const HFSPlusExtentDescriptor
*extentList
)
1722 int result
= FSUR_IO_SUCCESS
;
1728 result
= LogicalToPhysical(offset
, length
, blockSize
, extentCount
, extentList
,
1729 &physOffset
, &physLength
);
1730 if (result
!= FSUR_IO_SUCCESS
)
1733 result
= readAt(fd
, buffer
, volOffset
+physOffset
, physLength
);
1734 if (result
!= FSUR_IO_SUCCESS
)
1737 length
-= physLength
;
1738 offset
+= physLength
;
1739 buffer
= (char *) buffer
+ physLength
;
1746 -- readAt = lseek() + read()
1748 -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1753 readAt( int fd
, void * bufPtr
, off_t offset
, ssize_t length
)
1758 void * rawData
= NULL
;
1761 ssize_t dataOffset
= 0;
1762 int result
= FSUR_IO_SUCCESS
;
1764 if (ioctl(fd
, DKIOCBLKSIZE
, &blocksize
) < 0) {
1766 fprintf(stderr
, "hfs.util: readAt: couldn't determine block size of device.\n");
1768 result
= FSUR_IO_FAIL
;
1771 /* put offset and length in terms of device blocksize */
1772 rawOffset
= offset
/ blocksize
* blocksize
;
1773 dataOffset
= offset
- rawOffset
;
1774 rawLength
= ((length
+ dataOffset
+ blocksize
- 1) / blocksize
) * blocksize
;
1775 rawData
= malloc(rawLength
);
1776 if (rawData
== NULL
) {
1777 result
= FSUR_IO_FAIL
;
1781 lseekResult
= lseek( fd
, rawOffset
, SEEK_SET
);
1782 if ( lseekResult
!= rawOffset
) {
1783 result
= FSUR_IO_FAIL
;
1787 readResult
= read(fd
, rawData
, rawLength
);
1788 if ( readResult
!= rawLength
) {
1790 fprintf(stderr
, "hfs.util: readAt: attempt to read data from device failed (errno = %d)?\n", errno
);
1792 result
= FSUR_IO_FAIL
;
1795 bcopy(rawData
+ dataOffset
, bufPtr
, length
);
1806 -- writeAt = lseek() + write()
1808 -- Returns: FSUR_IO_SUCCESS, FSUR_IO_FAIL
1813 writeAt( int fd
, void * bufPtr
, off_t offset
, ssize_t length
)
1817 ssize_t bytestransferred
;
1818 void * rawData
= NULL
;
1821 ssize_t dataOffset
= 0;
1822 int result
= FSUR_IO_SUCCESS
;
1824 if (ioctl(fd
, DKIOCBLKSIZE
, &blocksize
) < 0) {
1826 fprintf(stderr
, "hfs.util: couldn't determine block size of device.\n");
1828 result
= FSUR_IO_FAIL
;
1831 /* put offset and length in terms of device blocksize */
1832 rawOffset
= offset
/ blocksize
* blocksize
;
1833 dataOffset
= offset
- rawOffset
;
1834 rawLength
= ((length
+ dataOffset
+ blocksize
- 1) / blocksize
) * blocksize
;
1835 rawData
= malloc(rawLength
);
1836 if (rawData
== NULL
) {
1837 result
= FSUR_IO_FAIL
;
1841 deviceoffset
= lseek( fd
, rawOffset
, SEEK_SET
);
1842 if ( deviceoffset
!= rawOffset
) {
1843 result
= FSUR_IO_FAIL
;
1847 /* If the write isn't block-aligned, read the existing data before writing the new data: */
1848 if (((rawOffset
% blocksize
) != 0) || ((rawLength
% blocksize
) != 0)) {
1849 bytestransferred
= read(fd
, rawData
, rawLength
);
1850 if ( bytestransferred
!= rawLength
) {
1852 fprintf(stderr
, "writeAt: attempt to pre-read data from device failed (errno = %d)\n", errno
);
1854 result
= FSUR_IO_FAIL
;
1859 bcopy(bufPtr
, rawData
+ dataOffset
, length
); /* Copy in the new data */
1861 deviceoffset
= lseek( fd
, rawOffset
, SEEK_SET
);
1862 if ( deviceoffset
!= rawOffset
) {
1863 result
= FSUR_IO_FAIL
;
1867 bytestransferred
= write(fd
, rawData
, rawLength
);
1868 if ( bytestransferred
!= rawLength
) {
1870 fprintf(stderr
, "writeAt: attempt to write data to device failed?!");
1872 result
= FSUR_IO_FAIL
;
1877 if (rawData
) free(rawData
);
1884 /******************************************************************************
1886 * 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
1888 *****************************************************************************/
1890 #define DBHANDLESIGNATURE 0x75917737
1892 /* Flag values for operation options: */
1893 #define DBMARKPOSITION 1
1895 static char gVSDBPath
[] = "/var/db/volinfo.database";
1897 #define MAXIOMALLOC 16384
1899 /* Database layout: */
1906 char statusFlags
[8];
1913 struct VSDBRecord record
;
1917 #define DBKEYSEPARATOR ':'
1918 #define DBBLANKSPACE ' '
1919 #define DBRECORDTERMINATOR '\n'
1921 /* In-memory data structures: */
1924 unsigned long signature
;
1927 off_t recordPosition
;
1930 typedef struct VSDBState
*VSDBStatePtr
;
1933 unsigned long state
[5];
1934 unsigned long count
[2];
1935 unsigned char buffer
[64];
1940 /* Internal function prototypes: */
1941 static int LockDB(VSDBStatePtr dbstateptr
, int lockmode
);
1942 static int UnlockDB(VSDBStatePtr dbstateptr
);
1944 static int FindVolumeRecordByUUID(VSDBStatePtr dbstateptr
, VolumeUUID
*volumeID
, struct VSDBEntry
*dbentry
, unsigned long options
);
1945 static int AddVolumeRecord(VSDBStatePtr dbstateptr
, struct VSDBEntry
*dbentry
);
1946 static int UpdateVolumeRecord(VSDBStatePtr dbstateptr
, struct VSDBEntry
*dbentry
);
1947 static int GetVSDBEntry(VSDBStatePtr dbstateptr
, struct VSDBEntry
*dbentry
);
1948 static int CompareVSDBKeys(struct VSDBKey
*key1
, struct VSDBKey
*key2
);
1950 static void FormatULong(unsigned long u
, char *s
);
1951 static void FormatUUID(VolumeUUID
*volumeID
, char *UUIDField
);
1952 static void FormatDBKey(VolumeUUID
*volumeID
, struct VSDBKey
*dbkey
);
1953 static void FormatDBRecord(unsigned long volumeStatusFlags
, struct VSDBRecord
*dbrecord
);
1954 static void FormatDBEntry(VolumeUUID
*volumeID
, unsigned long volumeStatusFlags
, struct VSDBEntry
*dbentry
);
1955 static unsigned long ConvertHexStringToULong(const char *hs
, long maxdigits
);
1957 static void SHA1Transform(unsigned long state
[5], unsigned char buffer
[64]);
1958 static void SHA1Init(SHA1_CTX
* context
);
1959 static void SHA1Update(SHA1_CTX
* context
, void* data
, size_t len
);
1960 static void SHA1Final(unsigned char digest
[20], SHA1_CTX
* context
);
1964 /******************************************************************************
1966 * P U B L I S H E D I N T E R F A C E R O U T I N E S
1968 *****************************************************************************/
1970 void GenerateVolumeUUID(VolumeUUID
*newVolumeID
) {
1972 char randomInputBuffer
[26];
1973 unsigned char digest
[20];
1978 char sysctlstring
[128];
1980 struct loadavg sysloadavg
;
1981 struct vmtotal sysvmtotal
;
1984 /* Initialize the SHA-1 context for processing: */
1987 /* Now process successive bits of "random" input to seed the process: */
1989 /* The current system's uptime: */
1991 SHA1Update(&context
, &uptime
, sizeof(uptime
));
1993 /* The kernel's boot time: */
1995 mib
[1] = KERN_BOOTTIME
;
1996 datalen
= sizeof(sysdata
);
1997 sysctl(mib
, 2, &sysdata
, &datalen
, NULL
, 0);
1998 SHA1Update(&context
, &sysdata
, datalen
);
2000 /* The system's host id: */
2002 mib
[1] = KERN_HOSTID
;
2003 datalen
= sizeof(sysdata
);
2004 sysctl(mib
, 2, &sysdata
, &datalen
, NULL
, 0);
2005 SHA1Update(&context
, &sysdata
, datalen
);
2007 /* The system's host name: */
2009 mib
[1] = KERN_HOSTNAME
;
2010 datalen
= sizeof(sysctlstring
);
2011 sysctl(mib
, 2, sysctlstring
, &datalen
, NULL
, 0);
2012 SHA1Update(&context
, sysctlstring
, datalen
);
2014 /* The running kernel's OS release string: */
2016 mib
[1] = KERN_OSRELEASE
;
2017 datalen
= sizeof(sysctlstring
);
2018 sysctl(mib
, 2, sysctlstring
, &datalen
, NULL
, 0);
2019 SHA1Update(&context
, sysctlstring
, datalen
);
2021 /* The running kernel's version string: */
2023 mib
[1] = KERN_VERSION
;
2024 datalen
= sizeof(sysctlstring
);
2025 sysctl(mib
, 2, sysctlstring
, &datalen
, NULL
, 0);
2026 SHA1Update(&context
, sysctlstring
, datalen
);
2028 /* The system's load average: */
2030 mib
[1] = VM_LOADAVG
;
2031 datalen
= sizeof(sysloadavg
);
2032 sysctl(mib
, 2, &sysloadavg
, &datalen
, NULL
, 0);
2033 SHA1Update(&context
, &sysloadavg
, datalen
);
2035 /* The system's VM statistics: */
2038 datalen
= sizeof(sysvmtotal
);
2039 sysctl(mib
, 2, &sysvmtotal
, &datalen
, NULL
, 0);
2040 SHA1Update(&context
, &sysvmtotal
, datalen
);
2042 /* The current GMT (26 ASCII characters): */
2044 strncpy(randomInputBuffer
, asctime(gmtime(&now
)), 26); /* "Mon Mar 27 13:46:26 2000" */
2045 SHA1Update(&context
, randomInputBuffer
, 26);
2047 /* Pad the accumulated input and extract the final digest hash: */
2048 SHA1Final(digest
, &context
);
2050 memcpy(newVolumeID
, digest
, sizeof(*newVolumeID
));
2051 } while ((newVolumeID
->v
.high
== 0) || (newVolumeID
->v
.low
== 0));
2056 void ConvertVolumeUUIDStringToUUID(const char *UUIDString
, VolumeUUID
*volumeID
) {
2059 unsigned long nextdigit
;
2060 unsigned long high
= 0;
2061 unsigned long low
= 0;
2062 unsigned long carry
;
2064 for (i
= 0; (i
< VOLUMEUUIDLENGTH
) && ((c
= UUIDString
[i
]) != (char)0) ; ++i
) {
2065 if ((c
>= '0') && (c
<= '9')) {
2066 nextdigit
= c
- '0';
2067 } else if ((c
>= 'A') && (c
<= 'F')) {
2068 nextdigit
= c
- 'A' + 10;
2069 } else if ((c
>= 'a') && (c
<= 'f')) {
2070 nextdigit
= c
- 'a' + 10;
2074 carry
= ((low
& 0xF0000000) >> 28) & 0x0000000F;
2075 high
= (high
<< 4) | carry
;
2076 low
= (low
<< 4) | nextdigit
;
2079 volumeID
->v
.high
= high
;
2080 volumeID
->v
.low
= low
;
2085 void ConvertVolumeUUIDToString(VolumeUUID
*volumeID
, char *UUIDString
) {
2086 FormatUUID(volumeID
, UUIDString
);
2087 *(UUIDString
+16) = (char)0; /* Append a terminating null character */
2092 int OpenVolumeStatusDB(VolumeStatusDBHandle
*DBHandlePtr
) {
2093 VSDBStatePtr dbstateptr
;
2095 *DBHandlePtr
= NULL
;
2097 dbstateptr
= (VSDBStatePtr
)malloc(sizeof(*dbstateptr
));
2098 if (dbstateptr
== NULL
) {
2102 dbstateptr
->dbmode
= O_RDWR
;
2103 dbstateptr
->dbfile
= open(gVSDBPath
, O_RDWR
| O_CREAT
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
2104 if (dbstateptr
->dbfile
== -1) {
2106 The file couldn't be opened for read/write access:
2107 try read-only access before giving up altogether.
2109 dbstateptr
->dbmode
= O_RDONLY
;
2110 dbstateptr
->dbfile
= open(gVSDBPath
, O_RDONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
2111 if (dbstateptr
->dbfile
== -1) {
2116 dbstateptr
->signature
= DBHANDLESIGNATURE
;
2117 *DBHandlePtr
= (VolumeStatusDBHandle
)dbstateptr
;
2123 int GetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle
, VolumeUUID
*volumeID
, unsigned long *VolumeStatus
) {
2124 VSDBStatePtr dbstateptr
= (VSDBStatePtr
)DBHandle
;
2125 struct VSDBEntry dbentry
;
2128 if (dbstateptr
->signature
!= DBHANDLESIGNATURE
) return EINVAL
;
2130 if ((result
= LockDB(dbstateptr
, LOCK_SH
)) != 0) return result
;
2132 if ((result
= FindVolumeRecordByUUID(dbstateptr
, volumeID
, &dbentry
, 0)) != 0) {
2135 *VolumeStatus
= VOLUME_RECORDED
| ConvertHexStringToULong(dbentry
.record
.statusFlags
, sizeof(dbentry
.record
.statusFlags
));
2140 UnlockDB(dbstateptr
);
2146 int SetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle
, VolumeUUID
*volumeID
, unsigned long VolumeStatus
) {
2147 VSDBStatePtr dbstateptr
= (VSDBStatePtr
)DBHandle
;
2148 struct VSDBEntry dbentry
;
2151 if (dbstateptr
->signature
!= DBHANDLESIGNATURE
) return EINVAL
;
2152 if (VolumeStatus
& ~VOLUME_VALIDSTATUSBITS
) return EINVAL
;
2154 if ((result
= LockDB(dbstateptr
, LOCK_EX
)) != 0) return result
;
2156 FormatDBEntry(volumeID
, VolumeStatus
, &dbentry
);
2157 if ((result
= FindVolumeRecordByUUID(dbstateptr
, volumeID
, NULL
, DBMARKPOSITION
)) == 0) {
2159 fprintf(stderr
,"AddLocalVolumeUUID: found record in database; updating in place.\n");
2161 result
= UpdateVolumeRecord(dbstateptr
, &dbentry
);
2162 } else if (result
== -1) {
2164 fprintf(stderr
,"AddLocalVolumeUUID: record not found in database; appending at end.\n");
2166 result
= AddVolumeRecord(dbstateptr
, &dbentry
);
2171 fsync(dbstateptr
->dbfile
);
2176 UnlockDB(dbstateptr
);
2182 int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle
, VolumeUUID
*volumeID
) {
2183 VSDBStatePtr dbstateptr
= (VSDBStatePtr
)DBHandle
;
2186 unsigned long iobuffersize
;
2187 void *iobuffer
= NULL
;
2189 unsigned long iotransfersize
;
2190 unsigned long bytestransferred
;
2192 if (dbstateptr
->signature
!= DBHANDLESIGNATURE
) return EINVAL
;
2194 if ((result
= LockDB(dbstateptr
, LOCK_EX
)) != 0) return result
;
2196 if ((result
= FindVolumeRecordByUUID(dbstateptr
, volumeID
, NULL
, DBMARKPOSITION
)) != 0) {
2198 fprintf(stderr
, "DeleteLocalVolumeUUID: No record with matching volume UUID in DB (result = %d).\n", result
);
2200 if (result
== -1) result
= 0; /* Entry wasn't in the database to begin with? */
2204 fprintf(stderr
, "DeleteLocalVolumeUUID: Found record with matching volume UUID...\n");
2206 if ((result
= stat(gVSDBPath
, &dbinfo
)) != 0) goto ErrExit
;
2207 if ((dbinfo
.st_size
- dbstateptr
->recordPosition
- sizeof(struct VSDBEntry
)) <= MAXIOMALLOC
) {
2208 iobuffersize
= dbinfo
.st_size
- dbstateptr
->recordPosition
- sizeof(struct VSDBEntry
);
2210 iobuffersize
= MAXIOMALLOC
;
2213 fprintf(stderr
, "DeleteLocalVolumeUUID: DB size = 0x%08lx; recordPosition = 0x%08lx;\n",
2214 (unsigned long)dbinfo
.st_size
, (unsigned long)dbstateptr
->recordPosition
);
2215 fprintf(stderr
, "DeleteLocalVolumeUUID: I/O buffer size = 0x%lx\n", iobuffersize
);
2217 if (iobuffersize
> 0) {
2218 iobuffer
= malloc(iobuffersize
);
2219 if (iobuffer
== NULL
) {
2224 dataoffset
= dbstateptr
->recordPosition
+ sizeof(struct VSDBEntry
);
2226 iotransfersize
= dbinfo
.st_size
- dataoffset
;
2227 if (iotransfersize
> 0) {
2228 if (iotransfersize
> iobuffersize
) iotransfersize
= iobuffersize
;
2231 fprintf(stderr
, "DeleteLocalVolumeUUID: reading 0x%08lx bytes starting at 0x%08lx ...\n", iotransfersize
, (unsigned long)dataoffset
);
2233 lseek(dbstateptr
->dbfile
, dataoffset
, SEEK_SET
);
2234 bytestransferred
= read(dbstateptr
->dbfile
, iobuffer
, iotransfersize
);
2235 if (bytestransferred
!= iotransfersize
) {
2241 fprintf(stderr
, "DeleteLocalVolumeUUID: writing 0x%08lx bytes starting at 0x%08lx ...\n", iotransfersize
, (unsigned long)(dataoffset
- (off_t
)sizeof(struct VSDBEntry
)));
2243 lseek(dbstateptr
->dbfile
, dataoffset
- (off_t
)sizeof(struct VSDBEntry
), SEEK_SET
);
2244 bytestransferred
= write(dbstateptr
->dbfile
, iobuffer
, iotransfersize
);
2245 if (bytestransferred
!= iotransfersize
) {
2250 dataoffset
+= (off_t
)iotransfersize
;
2252 } while (iotransfersize
> 0);
2255 fprintf(stderr
, "DeleteLocalVolumeUUID: truncating database file to 0x%08lx bytes.\n", (unsigned long)(dbinfo
.st_size
- (off_t
)(sizeof(struct VSDBEntry
))));
2257 if ((result
= ftruncate(dbstateptr
->dbfile
, dbinfo
.st_size
- (off_t
)(sizeof(struct VSDBEntry
)))) != 0) {
2261 fsync(dbstateptr
->dbfile
);
2267 if (iobuffer
) free(iobuffer
);
2268 UnlockDB(dbstateptr
);
2276 int CloseVolumeStatusDB(VolumeStatusDBHandle DBHandle
) {
2277 VSDBStatePtr dbstateptr
= (VSDBStatePtr
)DBHandle
;
2279 if (dbstateptr
->signature
!= DBHANDLESIGNATURE
) return EINVAL
;
2281 dbstateptr
->signature
= 0;
2283 close(dbstateptr
->dbfile
); /* Nothing we can do about any errors... */
2284 dbstateptr
->dbfile
= 0;
2293 /******************************************************************************
2295 * I N T E R N A L O N L Y D A T A B A S E R O U T I N E S
2297 *****************************************************************************/
2299 static int LockDB(VSDBStatePtr dbstateptr
, int lockmode
) {
2301 fprintf(stderr
, "LockDB: Locking VSDB file...\n");
2303 return flock(dbstateptr
->dbfile
, lockmode
);
2308 static int UnlockDB(VSDBStatePtr dbstateptr
) {
2310 fprintf(stderr
, "UnlockDB: Unlocking VSDB file...\n");
2312 return flock(dbstateptr
->dbfile
, LOCK_UN
);
2317 static int FindVolumeRecordByUUID(VSDBStatePtr dbstateptr
, VolumeUUID
*volumeID
, struct VSDBEntry
*targetEntry
, unsigned long options
) {
2318 struct VSDBKey searchkey
;
2319 struct VSDBEntry dbentry
;
2322 FormatDBKey(volumeID
, &searchkey
);
2323 lseek(dbstateptr
->dbfile
, 0, SEEK_SET
);
2326 result
= GetVSDBEntry(dbstateptr
, &dbentry
);
2327 if ((result
== 0) && (CompareVSDBKeys(&dbentry
.key
, &searchkey
) == 0)) {
2328 if (targetEntry
!= NULL
) {
2330 fprintf(stderr
, "FindVolumeRecordByUUID: copying %d. bytes from %08xl to %08l...\n", sizeof(*targetEntry
), &dbentry
, targetEntry
);
2332 memcpy(targetEntry
, &dbentry
, sizeof(*targetEntry
));
2336 } while (result
== 0);
2343 static int AddVolumeRecord(VSDBStatePtr dbstateptr
, struct VSDBEntry
*dbentry
) {
2345 VolumeUUIDString id
;
2349 strncpy(id
, dbentry
->key
.uuid
, sizeof(dbentry
->key
.uuid
));
2350 id
[sizeof(dbentry
->key
.uuid
)] = (char)0;
2351 fprintf(stderr
, "AddVolumeRecord: Adding record for UUID #%s...\n", id
);
2353 lseek(dbstateptr
->dbfile
, 0, SEEK_END
);
2354 return write(dbstateptr
->dbfile
, dbentry
, sizeof(struct VSDBEntry
));
2360 static int UpdateVolumeRecord(VSDBStatePtr dbstateptr
, struct VSDBEntry
*dbentry
) {
2362 VolumeUUIDString id
;
2366 strncpy(id
, dbentry
->key
.uuid
, sizeof(dbentry
->key
.uuid
));
2367 id
[sizeof(dbentry
->key
.uuid
)] = (char)0;
2368 fprintf(stderr
, "UpdateVolumeRecord: Updating record for UUID #%s at offset 0x%08lx in database...\n", id
, (unsigned long)dbstateptr
->recordPosition
);
2370 lseek(dbstateptr
->dbfile
, dbstateptr
->recordPosition
, SEEK_SET
);
2372 fprintf(stderr
, "UpdateVolumeRecord: Writing %d. bytes...\n", sizeof(*dbentry
));
2374 return write(dbstateptr
->dbfile
, dbentry
, sizeof(*dbentry
));
2379 static int GetVSDBEntry(VSDBStatePtr dbstateptr
, struct VSDBEntry
*dbentry
) {
2380 struct VSDBEntry entry
;
2383 VolumeUUIDString id
;
2386 dbstateptr
->recordPosition
= lseek(dbstateptr
->dbfile
, 0, SEEK_CUR
);
2387 #if 0 // DEBUG_TRACE
2388 fprintf(stderr
, "GetVSDBEntry: starting reading record at offset 0x%08lx...\n", (unsigned long)dbstateptr
->recordPosition
);
2390 result
= read(dbstateptr
->dbfile
, &entry
, sizeof(entry
));
2391 if ((result
!= sizeof(entry
)) ||
2392 (entry
.keySeparator
!= DBKEYSEPARATOR
) ||
2393 (entry
.space
!= DBBLANKSPACE
) ||
2394 (entry
.terminator
!= DBRECORDTERMINATOR
)) {
2399 strncpy(id
, entry
.key
.uuid
, sizeof(entry
.key
.uuid
));
2400 id
[sizeof(entry
.key
.uuid
)] = (char)0;
2401 fprintf(stderr
, "GetVSDBEntry: returning entry for UUID #%s...\n", id
);
2403 memcpy(dbentry
, &entry
, sizeof(*dbentry
));
2409 static int CompareVSDBKeys(struct VSDBKey
*key1
, struct VSDBKey
*key2
) {
2410 #if 0 // DEBUG_TRACE
2411 VolumeUUIDString id
;
2413 strncpy(id
, key1
->uuid
, sizeof(key1
->uuid
));
2414 id
[sizeof(key1
->uuid
)] = (char)0;
2415 fprintf(stderr
, "CompareVSDBKeys: comparing #%s to ", id
);
2416 strncpy(id
, key2
->uuid
, sizeof(key2
->uuid
));
2417 id
[sizeof(key2
->uuid
)] = (char)0;
2418 fprintf(stderr
, "%s (%d.)...\n", id
, sizeof(key1
->uuid
));
2421 return memcmp(key1
->uuid
, key2
->uuid
, sizeof(key1
->uuid
));
2426 /******************************************************************************
2428 * F O R M A T T I N G A N D C O N V E R S I O N R O U T I N E S
2430 *****************************************************************************/
2432 static void FormatULong(unsigned long u
, char *s
) {
2437 for (i
= 0; i
< 8; ++i
) {
2438 d
= ((u
& 0xF0000000) >> 28) & 0x0000000F;
2440 *digitptr
++ = (char)(d
+ '0');
2442 *digitptr
++ = (char)(d
- 10 + 'A');
2450 static void FormatUUID(VolumeUUID
*volumeID
, char *UUIDField
) {
2451 FormatULong(volumeID
->v
.high
, UUIDField
);
2452 FormatULong(volumeID
->v
.low
, UUIDField
+8);
2458 static void FormatDBKey(VolumeUUID
*volumeID
, struct VSDBKey
*dbkey
) {
2459 FormatUUID(volumeID
, dbkey
->uuid
);
2464 static void FormatDBRecord(unsigned long volumeStatusFlags
, struct VSDBRecord
*dbrecord
) {
2465 FormatULong(volumeStatusFlags
, dbrecord
->statusFlags
);
2470 static void FormatDBEntry(VolumeUUID
*volumeID
, unsigned long volumeStatusFlags
, struct VSDBEntry
*dbentry
) {
2471 FormatDBKey(volumeID
, &dbentry
->key
);
2472 dbentry
->keySeparator
= DBKEYSEPARATOR
;
2473 dbentry
->space
= DBBLANKSPACE
;
2474 FormatDBRecord(volumeStatusFlags
, &dbentry
->record
);
2475 #if 0 // DEBUG_TRACE
2476 dbentry
->terminator
= (char)0;
2477 fprintf(stderr
, "FormatDBEntry: '%s' (%d.)\n", dbentry
, sizeof(*dbentry
));
2479 dbentry
->terminator
= DBRECORDTERMINATOR
;
2484 static unsigned long ConvertHexStringToULong(const char *hs
, long maxdigits
) {
2487 unsigned long nextdigit
;
2491 for (i
= 0; (i
< 8) && ((c
= hs
[i
]) != (char)0) ; ++i
) {
2492 if ((c
>= '0') && (c
<= '9')) {
2493 nextdigit
= c
- '0';
2494 } else if ((c
>= 'A') && (c
<= 'F')) {
2495 nextdigit
= c
- 'A' + 10;
2496 } else if ((c
>= 'a') && (c
<= 'f')) {
2497 nextdigit
= c
- 'a' + 10;
2501 n
= (n
<< 4) + nextdigit
;
2509 /******************************************************************************
2511 * 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
2513 *****************************************************************************/
2516 Derived from SHA-1 in C
2517 By Steve Reid <steve@edmweb.com>
2520 Test Vectors (from FIPS PUB 180-1)
2522 A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
2523 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
2524 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
2525 A million repetitions of "a"
2526 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
2529 /* #define LITTLE_ENDIAN * This should be #define'd if true. */
2530 /* #define SHA1HANDSOFF * Copies data before messing with it. */
2532 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
2534 /* blk0() and blk() perform the initial expand. */
2535 /* I got the idea of expanding during the round function from SSLeay */
2536 #ifdef LITTLE_ENDIAN
2537 #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
2538 |(rol(block->l[i],8)&0x00FF00FF))
2540 #define blk0(i) block->l[i]
2542 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
2543 ^block->l[(i+2)&15]^block->l[i&15],1))
2545 /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
2547 #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);
2548 #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);
2549 #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);
2550 #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);
2551 #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);
2553 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
2554 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
2555 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
2556 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
2557 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
2561 /* Hash a single 512-bit block. This is the core of the algorithm. */
2563 static void SHA1Transform(unsigned long state
[5], unsigned char buffer
[64])
2565 unsigned long a
, b
, c
, d
, e
;
2567 unsigned char c
[64];
2568 unsigned long l
[16];
2570 CHAR64LONG16
* block
;
2572 static unsigned char workspace
[64];
2573 block
= (CHAR64LONG16
*)workspace
;
2574 memcpy(block
, buffer
, 64);
2576 block
= (CHAR64LONG16
*)buffer
;
2578 /* Copy context->state[] to working vars */
2585 printf(" A B C D E\n");
2586 printf(" -------- -------- -------- -------- --------\n");
2587 printf(" %08lX %08lX %08lX %08lX %08lX\n", a
, b
, c
, d
, e
);
2589 /* 4 rounds of 20 operations each. Loop unrolled. */
2590 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);
2591 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);
2592 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);
2593 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);
2594 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);
2595 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);
2596 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);
2597 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);
2598 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);
2599 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);
2600 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);
2601 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);
2602 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);
2603 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);
2604 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);
2605 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);
2606 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);
2607 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);
2608 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);
2609 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);
2610 /* Add the working vars back into context.state[] */
2616 /* Wipe variables */
2617 a
= b
= c
= d
= e
= 0;
2621 /* SHA1Init - Initialize new context */
2623 static void SHA1Init(SHA1_CTX
* context
)
2625 /* SHA1 initialization constants */
2626 context
->state
[0] = 0x67452301;
2627 context
->state
[1] = 0xEFCDAB89;
2628 context
->state
[2] = 0x98BADCFE;
2629 context
->state
[3] = 0x10325476;
2630 context
->state
[4] = 0xC3D2E1F0;
2631 context
->count
[0] = context
->count
[1] = 0;
2635 /* Run your data through this. */
2637 static void SHA1Update(SHA1_CTX
* context
, void* data
, size_t len
)
2639 unsigned char *dataptr
= (char *)data
;
2642 j
= (context
->count
[0] >> 3) & 63;
2643 if ((context
->count
[0] += len
<< 3) < (len
<< 3)) context
->count
[1]++;
2644 context
->count
[1] += (len
>> 29);
2645 if ((j
+ len
) > 63) {
2646 memcpy(&context
->buffer
[j
], dataptr
, (i
= 64-j
));
2647 SHA1Transform(context
->state
, context
->buffer
);
2648 for ( ; i
+ 63 < len
; i
+= 64) {
2649 SHA1Transform(context
->state
, &dataptr
[i
]);
2654 memcpy(&context
->buffer
[j
], &dataptr
[i
], len
- i
);
2658 /* Add padding and return the message digest. */
2660 static void SHA1Final(unsigned char digest
[20], SHA1_CTX
* context
)
2663 unsigned char finalcount
[8];
2665 for (i
= 0; i
< 8; i
++) {
2666 finalcount
[i
] = (unsigned char)((context
->count
[(i
>= 4 ? 0 : 1)]
2667 >> ((3-(i
& 3)) * 8) ) & 255); /* Endian independent */
2669 SHA1Update(context
, (unsigned char *)"\200", 1);
2670 while ((context
->count
[0] & 504) != 448) {
2671 SHA1Update(context
, (unsigned char *)"\0", 1);
2673 SHA1Update(context
, finalcount
, 8); /* Should cause a SHA1Transform() */
2674 for (i
= 0; i
< 20; i
++) {
2675 digest
[i
] = (unsigned char)
2676 ((context
->state
[i
>>2] >> ((3-(i
& 3)) * 8) ) & 255);
2678 /* Wipe variables */
2680 memset(context
->buffer
, 0, 64);
2681 memset(context
->state
, 0, 20);
2682 memset(context
->count
, 0, 8);
2683 memset(&finalcount
, 0, 8);
2684 #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
2685 SHA1Transform(context
->state
, context
->buffer
);