Exemplo n.º 1
0
/********************************************************************
*	 MoveFile
*		 lpFromFileName: old file path
*		 lpToFileName: new file path
********************************************************************/
BOOL MoveFile(const char * lpFromFileName, const char * lpToFileName)
{
	OSErr theErr;
	FSRef fromFileRef;
	FSRef toFileRef;
	FSRef parentFolderRef;
	
	// Get the path to the old file
	theErr = FSPathMakeRef((const UInt8 *)lpFromFileName, &fromFileRef, NULL);
	if (theErr != noErr)
	{
		SetLastError(theErr);
		return false;
	}
	
	// Get the path to the new folder for the file
	char folderName[strlen(lpToFileName)];
	CFStringRef folderPathCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8);
	CFURLRef fileURL = CFURLCreateWithFileSystemPath(NULL, folderPathCFString, kCFURLPOSIXPathStyle, FALSE);
	CFURLRef folderURL = CFURLCreateCopyDeletingLastPathComponent(NULL, fileURL);
	CFURLGetFileSystemRepresentation(folderURL, TRUE, (UInt8 *)folderName, strlen(lpToFileName));
	theErr = FSPathMakeRef((UInt8 *)folderName, &parentFolderRef, NULL);
	CFRelease(fileURL);
	CFRelease(folderURL);
	CFRelease(folderPathCFString);
	
	// Move the old file
	theErr = FSMoveObject(&fromFileRef, &parentFolderRef, &toFileRef);
	if (theErr != noErr)
	{
		SetLastError(theErr);
		return false;
	}
	
	// Get a CFString for the new file name
	CFStringRef newFileNameCFString = CFStringCreateWithCString(NULL, lpToFileName, kCFStringEncodingUTF8);
	fileURL = CFURLCreateWithFileSystemPath(NULL, newFileNameCFString, kCFURLPOSIXPathStyle, FALSE);
	CFRelease(newFileNameCFString);
	newFileNameCFString = CFURLCopyLastPathComponent(fileURL);
	CFRelease(fileURL);
	
	// Convert CFString to Unicode and rename the file
	UniChar unicodeFileName[256];
	CFStringGetCharacters(newFileNameCFString, CFRangeMake(0, CFStringGetLength(newFileNameCFString)), 
						  unicodeFileName);
	theErr = FSRenameUnicode(&toFileRef, CFStringGetLength(newFileNameCFString), unicodeFileName, 
							 kTextEncodingUnknown, NULL);
	if (theErr != noErr)
	{
		SetLastError(theErr);
		CFRelease(newFileNameCFString);
		return false;
	}
	
	CFRelease(newFileNameCFString);
	
	SetLastError(theErr);
	return true;
}
Exemplo n.º 2
0
void *updatethreadproc(void*)
{
	char tempDir[PATH_MAX] = "";		/* Flawfinder: ignore */
	FSRef tempDirRef;
	char temp[PATH_MAX] = "";	/* Flawfinder: ignore */
	// *NOTE: This buffer length is used in a scanf() below.
	char deviceNode[1024] = "";	/* Flawfinder: ignore */
	LLFILE *downloadFile = NULL;
	OSStatus err;
	ProcessSerialNumber psn;
	char target[PATH_MAX] = "";		/* Flawfinder: ignore */
	FSRef targetRef;
	FSRef targetParentRef;
	FSVolumeRefNum targetVol;
	FSRef trashFolderRef;
	Boolean replacingTarget = false;

	memset(&tempDirRef, 0, sizeof(tempDirRef));
	memset(&targetRef, 0, sizeof(targetRef));
	memset(&targetParentRef, 0, sizeof(targetParentRef));
	
	try
	{
		// Attempt to get a reference to the Second Life application bundle containing this updater.
		// Any failures during this process will cause us to default to updating /Applications/Second Life.app
		{
			FSRef myBundle;

			err = GetCurrentProcess(&psn);
			if(err == noErr)
			{
				err = GetProcessBundleLocation(&psn, &myBundle);
			}

			if(err == noErr)
			{
				// Sanity check:  Make sure the name of the item referenced by targetRef is "Second Life.app".
				FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target));
				
				llinfos << "Updater bundle location: " << target << llendl;
			}
			
			// Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app
			// so we need to go up 3 levels to get the path to the main application bundle.
			if(err == noErr)
			{
				err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
			}
			if(err == noErr)
			{
				err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
			}
			if(err == noErr)
			{
				err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef);
			}
			
			// And once more to get the parent of the target
			if(err == noErr)
			{
				err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef);
			}
			
			if(err == noErr)
			{
				FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
				llinfos << "Path to target: " << target << llendl;
			}
			
			// Sanity check: make sure the target is a bundle with the right identifier
			if(err == noErr)
			{
				// Assume the worst...
				err = -1;

				if(isFSRefViewerBundle(&targetRef))
				{
					// This is the bundle we're looking for.
					err = noErr;
					replacingTarget = true;
				}
			}
			
			// Make sure the target's parent directory is writable.
			if(err == noErr)
			{
				if(!isDirWritable(targetParentRef))
				{
					// Parent directory isn't writable.
					llinfos << "Target parent directory not writable." << llendl;
					err = -1;
					replacingTarget = false;
				}
			}

			if(err != noErr)
			{
				Boolean isDirectory;
				llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl;
				
				// Set up the parent directory
				err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory);
				if((err != noErr) || (!isDirectory))
				{
					// We're so hosed.
					llinfos << "Applications directory not found, giving up." << llendl;
					throw 0;
				}
				
				snprintf(target, sizeof(target), "/Applications/%s.app", gProductName);		

				memset(&targetRef, 0, sizeof(targetRef));
				err = FSPathMakeRef((UInt8*)target, &targetRef, NULL);
				if(err == fnfErr)
				{
					// This is fine, just means we're not replacing anything.
					err = noErr;
					replacingTarget = false;
				}
				else
				{
					replacingTarget = true;
				}

				// Make sure the target's parent directory is writable.
				if(err == noErr)
				{
					if(!isDirWritable(targetParentRef))
					{
						// Parent directory isn't writable.
						llinfos << "Target parent directory not writable." << llendl;
						err = -1;
						replacingTarget = false;
					}
				}

			}
			
			// If we haven't fixed all problems by this point, just bail.
			if(err != noErr)
			{
				llinfos << "Unable to pick a target, giving up." << llendl;
				throw 0;
			}
		}
		
		// Find the volID of the volume the target resides on
		{
			FSCatalogInfo info;
			err = FSGetCatalogInfo(
				&targetParentRef,
				kFSCatInfoVolume,
				&info,
				NULL, 
				NULL,  
				NULL);
				
			if(err != noErr)
				throw 0;
			
			targetVol = info.volume;
		}

		// Find the temporary items and trash folders on that volume.
		err = FSFindFolder(
			targetVol,
			kTrashFolderType,
			true,
			&trashFolderRef);

		if(err != noErr)
			throw 0;

#if 0 // *HACK for DEV-11935 see below for details.

		FSRef tempFolderRef;

		err = FSFindFolder(
			targetVol,
			kTemporaryFolderType,
			true,
			&tempFolderRef);
		
		if(err != noErr)
			throw 0;
		
		err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp));

		if(err != noErr)
			throw 0;

#else		

		// *HACK for DEV-11935  the above kTemporaryFolderType query was giving
		// back results with path names that seem to be too long to be used as
		// mount points.  I suspect this incompatibility was introduced in the
		// Leopard 10.5.2 update, but I have not verified this. 
		char const HARDCODED_TMP[] = "/tmp";
		strncpy(temp, HARDCODED_TMP, sizeof(HARDCODED_TMP));

#endif // 0 *HACK for DEV-11935
		
		// Skip downloading the file if the dmg was passed on the command line.
		std::string dmgName;
		if(gDmgFile != NULL) {
			dmgName = basename((char *)gDmgFile);
			char * dmgDir = dirname((char *)gDmgFile);
			strncpy(tempDir, dmgDir, sizeof(tempDir));
			err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);
			if(err != noErr) throw 0;
			chdir(tempDir);
			goto begin_install;
		} else {
			// Continue on to download file.
			dmgName = "SecondLife.dmg";
		}

		
		strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
		if(mkdtemp(temp) == NULL)
		{
			throw 0;
		}
		
		strncpy(tempDir, temp, sizeof(tempDir));
		temp[sizeof(tempDir) - 1] = '\0';
		
		llinfos << "tempDir is " << tempDir << llendl;

		err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL);

		if(err != noErr)
			throw 0;
				
		chdir(tempDir);
		
		snprintf(temp, sizeof(temp), "SecondLife.dmg");		
		
		downloadFile = LLFile::fopen(temp, "wb");		/* Flawfinder: ignore */
		if(downloadFile == NULL)
		{
			throw 0;
		}

		{
			CURL *curl = curl_easy_init();

			curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
	//		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback);
			curl_easy_setopt(curl, CURLOPT_FILE, downloadFile);
			curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
			curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func);
			curl_easy_setopt(curl, CURLOPT_URL,	gUpdateURL);
			curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
			
			sendProgress(0, 1, CFSTR("Downloading..."));
			
			CURLcode result = curl_easy_perform(curl);
			
			curl_easy_cleanup(curl);
			
			if(gCancelled)
			{
				llinfos << "User cancel, bailing out."<< llendl;
				throw 0;
			}
			
			if(result != CURLE_OK)
			{
				llinfos << "Error " << result << " while downloading disk image."<< llendl;
				throw 0;
			}
			
			fclose(downloadFile);
			downloadFile = NULL;
		}

	begin_install:
		sendProgress(0, 0, CFSTR("Mounting image..."));
		LLFile::mkdir("mnt", 0700);
		
		// NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder,
		//		but if our cleanup fails, this makes it much harder for the user to unmount the image.
		std::string mountOutput;
		boost::format cmdFormat("hdiutil attach %s -mountpoint mnt");
		cmdFormat % dmgName;
		FILE* mounter = popen(cmdFormat.str().c_str(), "r");		/* Flawfinder: ignore */
		
		if(mounter == NULL)
		{
			llinfos << "Failed to mount disk image, exiting."<< llendl;
			throw 0;
		}
		
		// We need to scan the output from hdiutil to find the device node it uses to attach the disk image.
		// If we don't have this information, we can't detach it later.
		while(mounter != NULL)
		{
			size_t len = fread(temp, 1, sizeof(temp)-1, mounter);
			temp[len] = 0;
			mountOutput.append(temp);
			if(len < sizeof(temp)-1)
			{
				// End of file or error.
				int result = pclose(mounter);
				if(result != 0)
				{
					// NOTE: We used to abort here, but pclose() started returning 
					// -1, possibly when the size of the DMG passed a certain point 
					llinfos << "Unexpected result closing pipe: " << result << llendl; 
				}
				mounter = NULL;
			}
		}
		
		if(!mountOutput.empty())
		{
			const char *s = mountOutput.c_str();
			const char *prefix = "/dev/";
			char *sub = strstr(s, prefix);
			
			if(sub != NULL)
			{
				sub += strlen(prefix);	/* Flawfinder: ignore */
				sscanf(sub, "%1023s", deviceNode);	/* Flawfinder: ignore */
			}
		}
		
		if(deviceNode[0] != 0)
		{
			llinfos << "Disk image attached on /dev/" << deviceNode << llendl;
		}
		else
		{
			llinfos << "Disk image device node not found!" << llendl;
			throw 0; 
		}
		
		// Get an FSRef to the new application on the disk image
		FSRef sourceRef;
		FSRef mountRef;
		snprintf(temp, sizeof(temp), "%s/mnt", tempDir);		

		llinfos << "Disk image mount point is: " << temp << llendl;

		err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL);
		if(err != noErr)
		{
			llinfos << "Couldn't make FSRef to disk image mount point." << llendl;
			throw 0;
		}

		sendProgress(0, 0, CFSTR("Searching for the app bundle..."));
		err = findAppBundleOnDiskImage(&mountRef, &sourceRef);
		if(err != noErr)
		{
			llinfos << "Couldn't find application bundle on mounted disk image." << llendl;
			throw 0;
		}
		else
		{
			llinfos << "found the bundle." << llendl;
		}

		sendProgress(0, 0, CFSTR("Preparing to copy files..."));
		
		FSRef asideRef;
		char aside[MAX_PATH];		/* Flawfinder: ignore */
		
		// this will hold the name of the destination target
		CFStringRef appNameRef;

		if(replacingTarget)
		{
			// Get the name of the target we're replacing
			HFSUniStr255 appNameUniStr;
			err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL);
			if(err != noErr)
				throw 0;
			appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr);
			
			// Move aside old version (into work directory)
			err = FSMoveObject(&targetRef, &tempDirRef, &asideRef);
			if(err != noErr)
			{
				llwarns << "failed to move aside old version (error code " << 
					err << ")" << llendl;
				throw 0;
			}

			// Grab the path for later use.
			err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside));
		}
		else
		{
			// Construct the name of the target based on the product name
			char appName[MAX_PATH];		/* Flawfinder: ignore */
			snprintf(appName, sizeof(appName), "%s.app", gProductName);		
			appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8);
		}
		
		sendProgress(0, 0, CFSTR("Copying files..."));
		
		llinfos << "Starting copy..." << llendl;

		// Copy the new version from the disk image to the target location.
		err = FSCopyObjectSync(
				&sourceRef,
				&targetParentRef,
				appNameRef,
				&targetRef,
				kFSFileOperationDefaultOptions);
		
		// Grab the path for later use.
		err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target));
		if(err != noErr)
			throw 0;

		llinfos << "Copy complete. Target = " << target << llendl;

		if(err != noErr)
		{
			// Something went wrong during the copy.  Attempt to put the old version back and bail.
			(void)FSDeleteObject(&targetRef);
			if(replacingTarget)
			{
				(void)FSMoveObject(&asideRef, &targetParentRef, NULL);
			}
			throw 0;
		}
		else
		{
			// The update has succeeded.  Clear the cache directory.

			sendProgress(0, 0, CFSTR("Clearing cache..."));
	
			llinfos << "Clearing cache..." << llendl;
			
			char mask[LL_MAX_PATH];		/* Flawfinder: ignore */
			snprintf(mask, LL_MAX_PATH, "%s*.*", gDirUtilp->getDirDelimiter().c_str());		
			gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
			
			llinfos << "Clear complete." << llendl;

		}
	}
	catch(...)
	{
		if(!gCancelled)
			if(gFailure == noErr)
				gFailure = -1;
	}

	// Failures from here on out are all non-fatal and not reported.
	sendProgress(0, 3, CFSTR("Cleaning up..."));

	// Close disk image file if necessary
	if(downloadFile != NULL)
	{
		llinfos << "Closing download file." << llendl;

		fclose(downloadFile);
		downloadFile = NULL;
	}

	sendProgress(1, 3);
	// Unmount image
	if(deviceNode[0] != 0)
	{
		llinfos << "Detaching disk image." << llendl;

		snprintf(temp, sizeof(temp), "hdiutil detach '%s'", deviceNode);		
		system(temp);		/* Flawfinder: ignore */
	}

	sendProgress(2, 3);

	// Move work directory to the trash
	if(tempDir[0] != 0)
	{
//		chdir("/");
//		FSDeleteObjects(tempDirRef);

		llinfos << "Moving work directory to the trash." << llendl;

		err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL);
		if(err != noErr) {
			llwarns << "failed to move files to trash, (error code " <<
				err << ")" << llendl;
		}

//		snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir);
//		printf("%s\n", temp);
//		system(temp);
	}
	
	if(!gCancelled  && !gFailure && (target[0] != 0))
	{
		llinfos << "Touching application bundle." << llendl;

		snprintf(temp, sizeof(temp), "touch '%s'", target);		
		system(temp);		/* Flawfinder: ignore */

		llinfos << "Launching updated application." << llendl;

		snprintf(temp, sizeof(temp), "open '%s'", target);		
		system(temp);		/* Flawfinder: ignore */
	}

	sendDone();
	
	return(NULL);
}
Exemplo n.º 3
0
OSErr FSExchangeObjectsEmulate(const FSRef *sourceRef, const FSRef *destRef, FSRef *newSourceRef, FSRef *newDestRef) {

	enum {
		/* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
		kGetCatInformationMask = (kFSCatInfoSettableInfo |
								  kFSCatInfoVolume |
								  kFSCatInfoParentDirID) &
		~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
		/* set everything possible except for mod dates */
		kSetCatinformationMask = kFSCatInfoSettableInfo &
		~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
	};

	OSErr          result;
	FSCatalogInfo      sourceCatalogInfo;  /* source file's catalog information */
	FSCatalogInfo      destCatalogInfo;  /* destination file's catalog information */
	HFSUniStr255      sourceName;      /* source file's Unicode name */
	HFSUniStr255      destName;      /* destination file's Unicode name */
	FSRef          sourceCurrentRef;  /* FSRef to current location of source file throughout this function */
	FSRef          destCurrentRef;    /* FSRef to current location of destination file throughout this function */
	FSRef          sourceParentRef;  /* FSRef to parent directory of source file */
	FSRef          destParentRef;    /* FSRef to parent directory of destination file */
	HFSUniStr255      sourceUniqueName;  /* unique name given to source file while exchanging it with destination */
	HFSUniStr255      destUniqueName;    /* unique name given to destination file while exchanging it with source */
	long          theSeed;      /* the seed for generating unique names */
	Boolean          sameParentDirs;    /* true if source and destinatin parent directory is the same */

	/* check parameters */
	require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);

	/* output refs and current refs = input refs to start with */
	memcpy(newSourceRef, sourceRef, sizeof(FSRef));
	memcpy(&sourceCurrentRef, sourceRef, sizeof(FSRef));

	memcpy(newDestRef, destRef, sizeof(FSRef));
	memcpy(&destCurrentRef, destRef, sizeof(FSRef));

	/* Note: The compatibility case won't work for files with *Btree control blocks. */
	/* Right now the only *Btree files are created by the system. */

	/* get all catalog information and Unicode names for each file */
	result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
	require_noerr(result, SourceFSGetCatalogInfoFailed);

	result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
	require_noerr(result, DestFSGetCatalogInfoFailed);

	/* make sure source and destination are on same volume */
	require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);

	/* make sure both files are *really* files */
	require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
				   (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);

	/* generate 2 names that are unique in both directories */
	theSeed = 0x4a696d4c;  /* a fine unlikely filename */

	result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
	require_noerr(result, GenerateUniqueHFSUniStr1Failed);

	result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
	require_noerr(result, GenerateUniqueHFSUniStr2Failed);

	/* rename sourceCurrentRef to sourceUniqueName */
	result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
	require_noerr(result, FSRenameUnicode1Failed);
	memcpy(&sourceCurrentRef, newSourceRef, sizeof(FSRef));

	/* rename destCurrentRef to destUniqueName */
	result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
	require_noerr(result, FSRenameUnicode2Failed);
	memcpy(&destCurrentRef, newDestRef, sizeof(FSRef));

	/* are the source and destination parent directories the same? */
	sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
	if ( !sameParentDirs )
	{
		/* move source file to dest parent directory */
		result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
		require_noerr(result, FSMoveObject1Failed);
		memcpy(&sourceCurrentRef, newSourceRef, sizeof(FSRef));

		/* move dest file to source parent directory */
		result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
		require_noerr(result, FSMoveObject2Failed);
		memcpy(&destCurrentRef, newDestRef, sizeof(FSRef));
	}

	/* At this point, the files are in their new locations (if they were moved). */
	/* The source file is named sourceUniqueName and is in the directory referred to */
	/* by destParentRef. The destination file is named destUniqueName and is in the */
	/* directory referred to by sourceParentRef. */

	/* give source file the dest file's catalog information except for mod dates */
	result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
	require_noerr(result, FSSetCatalogInfo1Failed);

	/* give dest file the source file's catalog information except for mod dates */
	result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
	require_noerr(result, FSSetCatalogInfo2Failed);

	/* rename source file with dest file's name */
	result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
	require_noerr(result, FSRenameUnicode3Failed);
	memcpy(&sourceCurrentRef, newSourceRef, sizeof(FSRef));

	/* rename dest file with source file's name */
	result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
	require_noerr(result, FSRenameUnicode4Failed);

	/* we're done with no errors, so swap newSourceRef and newDestRef */
	memcpy(newSourceRef, newDestRef, sizeof(FSRef));
	memcpy(newDestRef, &sourceCurrentRef, sizeof(FSRef));

	return ( result );

	/**********************/

	/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
	/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
	/* state and location they ended up in so that both files can be found by the calling code. */

FSRenameUnicode4Failed:

		/* attempt to rename source file to sourceUniqueName */
		if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
		{
			memcpy(&sourceCurrentRef, newSourceRef, sizeof(FSRef));
		}

FSRenameUnicode3Failed:

		/* attempt to restore dest file's catalog information */
		verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));

FSSetCatalogInfo2Failed:

		/* attempt to restore source file's catalog information */
		verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));

FSSetCatalogInfo1Failed:

		if ( !sameParentDirs )
		{
			/* attempt to move dest file back to dest directory */
			if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
			{
				memcpy(&destCurrentRef, newDestRef, sizeof(FSRef));
			}
		}

FSMoveObject2Failed:

		if ( !sameParentDirs )
		{
			/* attempt to move source file back to source directory */
			if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
			{
				memcpy(&sourceCurrentRef, newSourceRef, sizeof(FSRef));
			}
		}

FSMoveObject1Failed:

		/* attempt to rename dest file to original name */
		verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));

FSRenameUnicode2Failed:

		/* attempt to rename source file to original name */
		verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));

FSRenameUnicode1Failed:
GenerateUniqueHFSUniStr2Failed:
GenerateUniqueHFSUniStr1Failed:
NotAFile:
NotSameVolume:
DestFSGetCatalogInfoFailed:
SourceFSGetCatalogInfoFailed:
BadParameter:

		return ( result );
}