Exemple #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;
}
void	HLFileSystemObject::SetName(CFStringRef inName)
{
	//	the FSRef for a file can change after renaming,
	//	so don't allow it to be done while the file is open
	ThrowIf(IsOpenForReading() || IsOpenForWriting(), CAException(fBsyErr), "HLFileSystemObject::SetName: can't change the name of an open file");
	
	//	make a raw unicode string out of the CFString
	CACFString theFileName(inName, false);
	UInt32 theFileNameLength = 255;
	UniChar	theFileNameString[255];
	theFileName.GetUnicodeString(theFileNameString, theFileNameLength);
	
	//	save off the current FSRef, since it may change
	FSRef theOldFSRef;
	memcpy(&theOldFSRef, &mFSRef, sizeof(FSRef));
	
	//	rename the file, getting us the new FSRef
	OSStatus theError = FSRenameUnicode(&theOldFSRef, theFileNameLength, theFileNameString, kTextEncodingUnknown, &mFSRef);
	ThrowIfError(theError, CAException(theError), "HLFileSystemObject::SetName: couldn't rename the file");
}
void	HLFileSystemObject::SetNameExtension(CFStringRef inNameExtension)
{
	//	the FSRef for a file can change after renaming,
	//	so don't allow it to be done while the file is open
	ThrowIf(IsOpenForReading() || IsOpenForWriting(), CAException(fBsyErr), "HLFileSystemObject::SetNameExtension: can't change the file name extension of an open file");
	
	//	make a raw unicode string out of the CFString containing the new extension
	CACFString theExtension(inNameExtension, false);
	UInt32 theExtensionLength = 255;
	UniChar	theExtensionString[255];
	theExtension.GetUnicodeString(theExtensionString, theExtensionLength);

	//	get the file name from the catalog info
	HFSUniStr255 theNameString;
	OSStatus theError = FSGetCatalogInfo(&mFSRef, kFSCatInfoNone, NULL, &theNameString, NULL, NULL);
	ThrowIfError(theError, CAException(theError), "HLFileSystemObject::SetNameExtension: couldn't get the catalog information");
	
	//	use Launch Services to find the start of the extension
	UniCharCount theExtensionStart = 0;
	LSGetExtensionInfo(theNameString.length, theNameString.unicode, &theExtensionStart);
	
	UInt32 theCharsToCopy;
	if(theExtensionStart != kLSInvalidExtensionIndex)
	{
		//	there already was an extension, so replace it
		
		//	figure out how many characters worth of extension can fit
		theCharsToCopy = 255UL - theExtensionStart;
		
		//	range it against the actual length of the extension
		theCharsToCopy = theExtensionLength < theCharsToCopy ? theExtensionLength : theCharsToCopy;
		
		//	copy the extension
		memcpy(&theNameString.unicode[theExtensionStart], theExtensionString, theCharsToCopy * sizeof(UniChar));
		
		//	update the length of the name string
		theNameString.length = theExtensionStart + theCharsToCopy;

		//	save off the current FSRef, since it may change
		FSRef theOldFSRef;
		memcpy(&theOldFSRef, &mFSRef, sizeof(FSRef));

		//	rename the file, getting us the new FSRef
		theError = FSRenameUnicode(&theOldFSRef, theNameString.length, theNameString.unicode, kTextEncodingUnknown, &mFSRef);
		ThrowIfError(theError, CAException(theError), "HLFileSystemObject::SetName: couldn't rename the file");
	}
	else if(theNameString.length < 254)
	{
		//	there isn't an extension yet, and there's room for at least two characters
		
		//	make a raw unicode string with the period
		CFRange thePeriodRange = { 0, 1 };
		UniChar	thePeriodString[255];
		CFStringGetCharacters(HLFileSystemCFStringConstants::sNameExtensionDelimiter, thePeriodRange, thePeriodString);
		
		//	copy it at the end of the string
		theNameString.unicode[theNameString.length] = thePeriodString[0];
		
		//	update the length
		theNameString.length += 1;
		
		//	figure out how many characters worth of extension can fit
		theCharsToCopy = 255UL - theNameString.length;

		//	range it against the actual length of the extension
		theCharsToCopy = theExtensionLength < theCharsToCopy ? theExtensionLength : theCharsToCopy;

		//	copy the extension
		memcpy(&theNameString.unicode[theNameString.length], theExtensionString, theCharsToCopy * sizeof(UniChar));

		//	update the length of the name string
		theNameString.length += theCharsToCopy;

		//	save off the current FSRef, since it may change
		FSRef theOldFSRef;
		memcpy(&theOldFSRef, &mFSRef, sizeof(FSRef));

		//	rename the file, getting us the new FSRef
		theError = FSRenameUnicode(&theOldFSRef, theNameString.length, theNameString.unicode, kTextEncodingUnknown, &mFSRef);
		ThrowIfError(theError, CAException(theError), "HLFileSystemObject::SetName: couldn't rename the file");
	}
}
Exemple #4
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 );
}