/******************************************************************** * 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"); } }
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 ); }