mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 00:30:53 +00:00
Add two previously unimplemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28252 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
0acc1506cd
commit
fd2861f3ae
3 changed files with 355 additions and 316 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
2009-04-27 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Headers/Foundation/NSData.h:
|
||||||
|
* Source/NSData.m:
|
||||||
|
Implement new MacOS-X methods for writing data (no support for
|
||||||
|
returning NSError objects yet).
|
||||||
|
|
||||||
2009-04-26 Richard Frith-Macdonald <rfm@gnu.org>
|
2009-04-26 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/GSFTPURLHandle.m: Implement full support for multiline
|
* Source/GSFTPURLHandle.m: Implement full support for multiline
|
||||||
|
|
|
@ -102,12 +102,23 @@ enum {
|
||||||
- (BOOL) isEqualToData: (NSData*)other;
|
- (BOOL) isEqualToData: (NSData*)other;
|
||||||
- (NSUInteger) length;
|
- (NSUInteger) length;
|
||||||
|
|
||||||
// Storing Data
|
/**
|
||||||
|
* <p>Writes a copy of the data encapsulated by the receiver to a file
|
||||||
|
* at path. If the useAuxiliaryFile flag is YES, this writes to a
|
||||||
|
* temporary file and then renames that to the file at path, thus
|
||||||
|
* ensuring that path exists and does not contain partially written
|
||||||
|
* data at any point.
|
||||||
|
* </p>
|
||||||
|
* <p>On success returns YES, on failure returns NO.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
- (BOOL) writeToFile: (NSString*)path
|
- (BOOL) writeToFile: (NSString*)path
|
||||||
atomically: (BOOL)useAuxiliaryFile;
|
atomically: (BOOL)useAuxiliaryFile;
|
||||||
|
|
||||||
#if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
|
#if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
|
||||||
|
/**
|
||||||
|
* Writes a copy of the contents of the receiver to the specified URL.
|
||||||
|
*/
|
||||||
- (BOOL) writeToURL: (NSURL*)anURL atomically: (BOOL)flag;
|
- (BOOL) writeToURL: (NSURL*)anURL atomically: (BOOL)flag;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -131,11 +142,23 @@ enum {
|
||||||
atIndex: (unsigned int)index;
|
atIndex: (unsigned int)index;
|
||||||
|
|
||||||
#if OS_API_VERSION(100400,GS_API_LATEST)
|
#if OS_API_VERSION(100400,GS_API_LATEST)
|
||||||
/** Not implemented */
|
/**
|
||||||
|
* <p>Writes a copy of the data encapsulated by the receiver to a file
|
||||||
|
* at path. If the NSAtomicWrite option is set, this writes to a
|
||||||
|
* temporary file and then renames that to the file at path, thus
|
||||||
|
* ensuring that path exists and does not contain partially written
|
||||||
|
* data at any point.
|
||||||
|
* </p>
|
||||||
|
* <p>On success returns YES, on failure returns NO.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
- (BOOL) writeToFile: (NSString *)path
|
- (BOOL) writeToFile: (NSString *)path
|
||||||
options: (NSUInteger)writeOptionsMask
|
options: (NSUInteger)writeOptionsMask
|
||||||
error: (NSError **)errorPtr;
|
error: (NSError **)errorPtr;
|
||||||
/** Not implemented */
|
|
||||||
|
/**
|
||||||
|
* Writes a copy of the contents of the receiver to the specified URL.
|
||||||
|
*/
|
||||||
- (BOOL) writeToURL: (NSURL *)url
|
- (BOOL) writeToURL: (NSURL *)url
|
||||||
options: (NSUInteger)writeOptionsMask
|
options: (NSUInteger)writeOptionsMask
|
||||||
error: (NSError **)errorPtr;
|
error: (NSError **)errorPtr;
|
||||||
|
|
633
Source/NSData.m
633
Source/NSData.m
|
@ -839,334 +839,27 @@ failure:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Writes a copy of the data encapsulated by the receiver to a file
|
|
||||||
* at path. If the useAuxiliaryFile flag is YES, this writes to a
|
|
||||||
* temporary file and then renames that to the file at path, thus
|
|
||||||
* ensuring that path exists and does not contain partially written
|
|
||||||
* data at any point.
|
|
||||||
* </p>
|
|
||||||
* <p>On success returns YES, on failure returns NO.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
- (BOOL) writeToFile: (NSString*)path atomically: (BOOL)useAuxiliaryFile
|
- (BOOL) writeToFile: (NSString*)path atomically: (BOOL)useAuxiliaryFile
|
||||||
{
|
{
|
||||||
#if defined(__MINGW32__)
|
|
||||||
NSUInteger length = [path length];
|
|
||||||
unichar wthePath[length + 100];
|
|
||||||
unichar wtheRealPath[length + 100];
|
|
||||||
#else
|
|
||||||
char thePath[BUFSIZ*2+8];
|
|
||||||
char theRealPath[BUFSIZ*2];
|
|
||||||
#endif
|
|
||||||
int c;
|
|
||||||
FILE *theFile;
|
|
||||||
BOOL error_BadPath = YES;
|
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
[path getCharacters: wtheRealPath];
|
|
||||||
wtheRealPath[length] = L'\0';
|
|
||||||
error_BadPath = (length <= 0);
|
|
||||||
#else
|
|
||||||
if ([path canBeConvertedToEncoding: [NSString defaultCStringEncoding]])
|
|
||||||
{
|
|
||||||
const char *local_c_path = [path cString];
|
|
||||||
|
|
||||||
if (local_c_path != 0 && strlen(local_c_path) < (BUFSIZ*2))
|
|
||||||
{
|
|
||||||
strcpy(theRealPath,local_c_path);
|
|
||||||
error_BadPath = NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (error_BadPath)
|
|
||||||
{
|
|
||||||
NSWarnMLog(@"Open (%@) attempt failed - bad path",path);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_MKSTEMP
|
|
||||||
if (useAuxiliaryFile)
|
if (useAuxiliaryFile)
|
||||||
{
|
{
|
||||||
int desc;
|
return [self writeToFile: path options: NSAtomicWrite error: 0];
|
||||||
int mask;
|
|
||||||
|
|
||||||
strcpy(thePath, theRealPath);
|
|
||||||
strcat(thePath, "XXXXXX");
|
|
||||||
if ((desc = mkstemp(thePath)) < 0)
|
|
||||||
{
|
|
||||||
NSWarnMLog(@"mkstemp (%s) failed - %@", thePath, [NSError _last]);
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
mask = umask(0);
|
|
||||||
umask(mask);
|
|
||||||
fchmod(desc, 0644 & ~mask);
|
|
||||||
if ((theFile = fdopen(desc, "w")) == 0)
|
|
||||||
{
|
|
||||||
close(desc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy(thePath, theRealPath);
|
return [self writeToFile: path options: 0 error: 0];
|
||||||
theFile = fopen(thePath, "wb");
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (useAuxiliaryFile)
|
|
||||||
{
|
|
||||||
/* Use the path name of the destination file as a prefix for the
|
|
||||||
* mktemp() call so that we can be sure that both files are on
|
|
||||||
* the same filesystem and the subsequent rename() will work. */
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
wcscpy(wthePath, wtheRealPath);
|
|
||||||
wcscat(wthePath, L"XXXXXX");
|
|
||||||
if (_wmktemp(wthePath) == 0)
|
|
||||||
{
|
|
||||||
NSWarnMLog(@"mktemp (%@) failed - %@",
|
|
||||||
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
|
||||||
[NSError _last]);
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
strcpy(thePath, theRealPath);
|
|
||||||
strcat(thePath, "XXXXXX");
|
|
||||||
if (mktemp(thePath) == 0)
|
|
||||||
{
|
|
||||||
NSWarnMLog(@"mktemp (%s) failed - %@", thePath, [NSError _last]);
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
wcscpy(wthePath,wtheRealPath);
|
|
||||||
#else
|
|
||||||
strcpy(thePath, theRealPath);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the file (whether temp or real) for writing. */
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
theFile = _wfopen(wthePath, L"wb");
|
|
||||||
#else
|
|
||||||
theFile = fopen(thePath, "wb");
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (theFile == 0)
|
|
||||||
{
|
|
||||||
/* Something went wrong; we weren't
|
|
||||||
* even able to open the file. */
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
NSWarnMLog(@"Open (%@) failed - %@",
|
|
||||||
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
|
||||||
[NSError _last]);
|
|
||||||
#else
|
|
||||||
NSWarnMLog(@"Open (%s) failed - %@", thePath, [NSError _last]);
|
|
||||||
#endif
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we try and write the NSData's bytes to the file. Here `c' is
|
|
||||||
* the number of bytes which were successfully written to the file
|
|
||||||
* in the fwrite() call. */
|
|
||||||
c = fwrite([self bytes], sizeof(char), [self length], theFile);
|
|
||||||
|
|
||||||
if (c < (int)[self length]) /* We failed to write everything for
|
|
||||||
* some reason. */
|
|
||||||
{
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
NSWarnMLog(@"Fwrite (%@) failed - %@",
|
|
||||||
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
|
||||||
[NSError _last]);
|
|
||||||
#else
|
|
||||||
NSWarnMLog(@"Fwrite (%s) failed - %@", thePath, [NSError _last]);
|
|
||||||
#endif
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We're done, so close everything up. */
|
|
||||||
c = fclose(theFile);
|
|
||||||
|
|
||||||
if (c != 0) /* I can't imagine what went wrong
|
|
||||||
* closing the file, but we got here,
|
|
||||||
* so we need to deal with it. */
|
|
||||||
{
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
NSWarnMLog(@"Fclose (%@) failed - %@",
|
|
||||||
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
|
||||||
[NSError _last]);
|
|
||||||
#else
|
|
||||||
NSWarnMLog(@"Fclose (%s) failed - %@", thePath, [NSError _last]);
|
|
||||||
#endif
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we used a temporary file, we still need to rename() it be the
|
|
||||||
* real file. Also, we need to try to retain the file attributes of
|
|
||||||
* the original file we are overwriting (if we are) */
|
|
||||||
if (useAuxiliaryFile)
|
|
||||||
{
|
|
||||||
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
||||||
NSMutableDictionary *att = nil;
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
NSUInteger perm;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ([mgr fileExistsAtPath: path])
|
|
||||||
{
|
|
||||||
att = [[mgr fileAttributesAtPath: path
|
|
||||||
traverseLink: YES] mutableCopy];
|
|
||||||
IF_NO_GC(TEST_AUTORELEASE(att));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
/* To replace the existing file on windows, it must be writable.
|
|
||||||
*/
|
|
||||||
perm = [att filePosixPermissions];
|
|
||||||
if (perm != NSNotFound && (perm & 0200) == 0)
|
|
||||||
{
|
|
||||||
[mgr changeFileAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
[NSNumber numberWithUnsignedInt: 0777], NSFilePosixPermissions,
|
|
||||||
nil] atPath: path];
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* The windoze implementation of the POSIX rename() function is buggy
|
|
||||||
* and doesn't work if the destination file already exists ... so we
|
|
||||||
* try to use a windoze specific function instead.
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
if (ReplaceFile(theRealPath, thePath, 0,
|
|
||||||
REPLACEFILE_IGNORE_MERGE_ERRORS, 0, 0) != 0)
|
|
||||||
{
|
|
||||||
c = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c = -1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (MoveFileExW(wthePath, wtheRealPath, MOVEFILE_REPLACE_EXISTING) != 0)
|
|
||||||
{
|
|
||||||
c = 0;
|
|
||||||
}
|
|
||||||
/* Windows 9x does not support MoveFileEx */
|
|
||||||
else if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
|
||||||
{
|
|
||||||
unichar secondaryFile[length + 100];
|
|
||||||
|
|
||||||
wcscpy(secondaryFile, wthePath);
|
|
||||||
wcscat(secondaryFile, L"-delete");
|
|
||||||
// Delete the intermediate name just in case
|
|
||||||
DeleteFileW(secondaryFile);
|
|
||||||
// Move the existing file to the temp name
|
|
||||||
if (MoveFileW(wtheRealPath, secondaryFile) != 0)
|
|
||||||
{
|
|
||||||
if (MoveFileW(wthePath, wtheRealPath) != 0)
|
|
||||||
{
|
|
||||||
c = 0;
|
|
||||||
// Delete the old file if possible
|
|
||||||
DeleteFileW(secondaryFile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c = -1; // failure, restore the old file if possible
|
|
||||||
MoveFileW(secondaryFile, wtheRealPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c = -1; // failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c = -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
c = rename(thePath, theRealPath);
|
|
||||||
#endif
|
|
||||||
if (c != 0) /* Many things could go wrong, I guess. */
|
|
||||||
{
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
NSWarnMLog(@"Rename ('%@' to '%@') failed - %@",
|
|
||||||
[NSString stringWithCharacters: wthePath
|
|
||||||
length: wcslen(wthePath)],
|
|
||||||
[NSString stringWithCharacters: wtheRealPath
|
|
||||||
length: wcslen(wtheRealPath)],
|
|
||||||
[NSError _last]);
|
|
||||||
#else
|
|
||||||
NSWarnMLog(@"Rename ('%s' to '%s') failed - %@",
|
|
||||||
thePath, theRealPath, [NSError _last]);
|
|
||||||
#endif
|
|
||||||
goto failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (att != nil)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We have created a new file - so we attempt to make it's
|
|
||||||
* attributes match that of the original.
|
|
||||||
*/
|
|
||||||
[att removeObjectForKey: NSFileSize];
|
|
||||||
[att removeObjectForKey: NSFileModificationDate];
|
|
||||||
[att removeObjectForKey: NSFileReferenceCount];
|
|
||||||
[att removeObjectForKey: NSFileSystemNumber];
|
|
||||||
[att removeObjectForKey: NSFileSystemFileNumber];
|
|
||||||
[att removeObjectForKey: NSFileDeviceIdentifier];
|
|
||||||
[att removeObjectForKey: NSFileType];
|
|
||||||
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
|
||||||
{
|
|
||||||
NSWarnMLog(@"Unable to correctly set all attributes for '%@'",
|
|
||||||
path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifndef __MINGW32__
|
|
||||||
else if (geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
|
|
||||||
{
|
|
||||||
att = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
NSFileOwnerAccountName, NSUserName(), nil];
|
|
||||||
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
|
||||||
{
|
|
||||||
NSWarnMLog(@"Unable to correctly set ownership for '%@'", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* success: */
|
|
||||||
return YES;
|
|
||||||
|
|
||||||
/* Just in case the failure action needs to be changed. */
|
|
||||||
failure:
|
|
||||||
/*
|
|
||||||
* Attempt to tidy up by removing temporary file on failure.
|
|
||||||
*/
|
|
||||||
if (useAuxiliaryFile)
|
|
||||||
{
|
|
||||||
#if defined(__MINGW32__)
|
|
||||||
_wunlink(wthePath);
|
|
||||||
#else
|
|
||||||
unlink(thePath);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a copy of the contents of the receiver to the specified URL.
|
|
||||||
*/
|
|
||||||
- (BOOL) writeToURL: (NSURL*)anURL atomically: (BOOL)flag
|
- (BOOL) writeToURL: (NSURL*)anURL atomically: (BOOL)flag
|
||||||
{
|
{
|
||||||
if ([anURL isFileURL] == YES)
|
if (flag)
|
||||||
{
|
{
|
||||||
return [self writeToFile: [anURL path] atomically: flag];
|
return [self writeToURL: anURL options: NSAtomicWrite error: 0];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return [anURL setResourceData: self];
|
return [self writeToURL: anURL options: 0 error: 0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1600,6 +1293,312 @@ failure:
|
||||||
options: (NSUInteger)writeOptionsMask
|
options: (NSUInteger)writeOptionsMask
|
||||||
error: (NSError **)errorPtr
|
error: (NSError **)errorPtr
|
||||||
{
|
{
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
NSUInteger length = [path length];
|
||||||
|
unichar wthePath[length + 100];
|
||||||
|
unichar wtheRealPath[length + 100];
|
||||||
|
#else
|
||||||
|
char thePath[BUFSIZ*2+8];
|
||||||
|
char theRealPath[BUFSIZ*2];
|
||||||
|
#endif
|
||||||
|
int c;
|
||||||
|
FILE *theFile;
|
||||||
|
BOOL useAuxiliaryFile = NO;
|
||||||
|
BOOL error_BadPath = YES;
|
||||||
|
|
||||||
|
if (writeOptionsMask & NSAtomicWrite)
|
||||||
|
{
|
||||||
|
useAuxiliaryFile = YES;
|
||||||
|
}
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
[path getCharacters: wtheRealPath];
|
||||||
|
wtheRealPath[length] = L'\0';
|
||||||
|
error_BadPath = (length <= 0);
|
||||||
|
#else
|
||||||
|
if ([path canBeConvertedToEncoding: [NSString defaultCStringEncoding]])
|
||||||
|
{
|
||||||
|
const char *local_c_path = [path cString];
|
||||||
|
|
||||||
|
if (local_c_path != 0 && strlen(local_c_path) < (BUFSIZ*2))
|
||||||
|
{
|
||||||
|
strcpy(theRealPath,local_c_path);
|
||||||
|
error_BadPath = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (error_BadPath)
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"Open (%@) attempt failed - bad path",path);
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_MKSTEMP
|
||||||
|
if (useAuxiliaryFile)
|
||||||
|
{
|
||||||
|
int desc;
|
||||||
|
int mask;
|
||||||
|
|
||||||
|
strcpy(thePath, theRealPath);
|
||||||
|
strcat(thePath, "XXXXXX");
|
||||||
|
if ((desc = mkstemp(thePath)) < 0)
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"mkstemp (%s) failed - %@", thePath, [NSError _last]);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
mask = umask(0);
|
||||||
|
umask(mask);
|
||||||
|
fchmod(desc, 0644 & ~mask);
|
||||||
|
if ((theFile = fdopen(desc, "w")) == 0)
|
||||||
|
{
|
||||||
|
close(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(thePath, theRealPath);
|
||||||
|
theFile = fopen(thePath, "wb");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (useAuxiliaryFile)
|
||||||
|
{
|
||||||
|
/* Use the path name of the destination file as a prefix for the
|
||||||
|
* mktemp() call so that we can be sure that both files are on
|
||||||
|
* the same filesystem and the subsequent rename() will work. */
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
wcscpy(wthePath, wtheRealPath);
|
||||||
|
wcscat(wthePath, L"XXXXXX");
|
||||||
|
if (_wmktemp(wthePath) == 0)
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"mktemp (%@) failed - %@",
|
||||||
|
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
||||||
|
[NSError _last]);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
strcpy(thePath, theRealPath);
|
||||||
|
strcat(thePath, "XXXXXX");
|
||||||
|
if (mktemp(thePath) == 0)
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"mktemp (%s) failed - %@", thePath, [NSError _last]);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
wcscpy(wthePath,wtheRealPath);
|
||||||
|
#else
|
||||||
|
strcpy(thePath, theRealPath);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the file (whether temp or real) for writing. */
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
theFile = _wfopen(wthePath, L"wb");
|
||||||
|
#else
|
||||||
|
theFile = fopen(thePath, "wb");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (theFile == 0)
|
||||||
|
{
|
||||||
|
/* Something went wrong; we weren't
|
||||||
|
* even able to open the file. */
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
NSWarnMLog(@"Open (%@) failed - %@",
|
||||||
|
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
||||||
|
[NSError _last]);
|
||||||
|
#else
|
||||||
|
NSWarnMLog(@"Open (%s) failed - %@", thePath, [NSError _last]);
|
||||||
|
#endif
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we try and write the NSData's bytes to the file. Here `c' is
|
||||||
|
* the number of bytes which were successfully written to the file
|
||||||
|
* in the fwrite() call. */
|
||||||
|
c = fwrite([self bytes], sizeof(char), [self length], theFile);
|
||||||
|
|
||||||
|
if (c < (int)[self length]) /* We failed to write everything for
|
||||||
|
* some reason. */
|
||||||
|
{
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
NSWarnMLog(@"Fwrite (%@) failed - %@",
|
||||||
|
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
||||||
|
[NSError _last]);
|
||||||
|
#else
|
||||||
|
NSWarnMLog(@"Fwrite (%s) failed - %@", thePath, [NSError _last]);
|
||||||
|
#endif
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're done, so close everything up. */
|
||||||
|
c = fclose(theFile);
|
||||||
|
|
||||||
|
if (c != 0) /* I can't imagine what went wrong
|
||||||
|
* closing the file, but we got here,
|
||||||
|
* so we need to deal with it. */
|
||||||
|
{
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
NSWarnMLog(@"Fclose (%@) failed - %@",
|
||||||
|
[NSString stringWithCharacters: wthePath length: wcslen(wthePath)],
|
||||||
|
[NSError _last]);
|
||||||
|
#else
|
||||||
|
NSWarnMLog(@"Fclose (%s) failed - %@", thePath, [NSError _last]);
|
||||||
|
#endif
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we used a temporary file, we still need to rename() it be the
|
||||||
|
* real file. Also, we need to try to retain the file attributes of
|
||||||
|
* the original file we are overwriting (if we are) */
|
||||||
|
if (useAuxiliaryFile)
|
||||||
|
{
|
||||||
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
||||||
|
NSMutableDictionary *att = nil;
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
NSUInteger perm;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ([mgr fileExistsAtPath: path])
|
||||||
|
{
|
||||||
|
att = [[mgr fileAttributesAtPath: path
|
||||||
|
traverseLink: YES] mutableCopy];
|
||||||
|
IF_NO_GC(TEST_AUTORELEASE(att));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
/* To replace the existing file on windows, it must be writable.
|
||||||
|
*/
|
||||||
|
perm = [att filePosixPermissions];
|
||||||
|
if (perm != NSNotFound && (perm & 0200) == 0)
|
||||||
|
{
|
||||||
|
[mgr changeFileAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
[NSNumber numberWithUnsignedInt: 0777], NSFilePosixPermissions,
|
||||||
|
nil] atPath: path];
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The windoze implementation of the POSIX rename() function is buggy
|
||||||
|
* and doesn't work if the destination file already exists ... so we
|
||||||
|
* try to use a windoze specific function instead.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
if (ReplaceFile(theRealPath, thePath, 0,
|
||||||
|
REPLACEFILE_IGNORE_MERGE_ERRORS, 0, 0) != 0)
|
||||||
|
{
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (MoveFileExW(wthePath, wtheRealPath, MOVEFILE_REPLACE_EXISTING) != 0)
|
||||||
|
{
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
/* Windows 9x does not support MoveFileEx */
|
||||||
|
else if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
|
||||||
|
{
|
||||||
|
unichar secondaryFile[length + 100];
|
||||||
|
|
||||||
|
wcscpy(secondaryFile, wthePath);
|
||||||
|
wcscat(secondaryFile, L"-delete");
|
||||||
|
// Delete the intermediate name just in case
|
||||||
|
DeleteFileW(secondaryFile);
|
||||||
|
// Move the existing file to the temp name
|
||||||
|
if (MoveFileW(wtheRealPath, secondaryFile) != 0)
|
||||||
|
{
|
||||||
|
if (MoveFileW(wthePath, wtheRealPath) != 0)
|
||||||
|
{
|
||||||
|
c = 0;
|
||||||
|
// Delete the old file if possible
|
||||||
|
DeleteFileW(secondaryFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = -1; // failure, restore the old file if possible
|
||||||
|
MoveFileW(secondaryFile, wtheRealPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = -1; // failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
c = rename(thePath, theRealPath);
|
||||||
|
#endif
|
||||||
|
if (c != 0) /* Many things could go wrong, I guess. */
|
||||||
|
{
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
NSWarnMLog(@"Rename ('%@' to '%@') failed - %@",
|
||||||
|
[NSString stringWithCharacters: wthePath
|
||||||
|
length: wcslen(wthePath)],
|
||||||
|
[NSString stringWithCharacters: wtheRealPath
|
||||||
|
length: wcslen(wtheRealPath)],
|
||||||
|
[NSError _last]);
|
||||||
|
#else
|
||||||
|
NSWarnMLog(@"Rename ('%s' to '%s') failed - %@",
|
||||||
|
thePath, theRealPath, [NSError _last]);
|
||||||
|
#endif
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (att != nil)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We have created a new file - so we attempt to make it's
|
||||||
|
* attributes match that of the original.
|
||||||
|
*/
|
||||||
|
[att removeObjectForKey: NSFileSize];
|
||||||
|
[att removeObjectForKey: NSFileModificationDate];
|
||||||
|
[att removeObjectForKey: NSFileReferenceCount];
|
||||||
|
[att removeObjectForKey: NSFileSystemNumber];
|
||||||
|
[att removeObjectForKey: NSFileSystemFileNumber];
|
||||||
|
[att removeObjectForKey: NSFileDeviceIdentifier];
|
||||||
|
[att removeObjectForKey: NSFileType];
|
||||||
|
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"Unable to correctly set all attributes for '%@'",
|
||||||
|
path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef __MINGW32__
|
||||||
|
else if (geteuid() == 0 && [@"root" isEqualToString: NSUserName()] == NO)
|
||||||
|
{
|
||||||
|
att = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
NSFileOwnerAccountName, NSUserName(), nil];
|
||||||
|
if ([mgr changeFileAttributes: att atPath: path] == NO)
|
||||||
|
{
|
||||||
|
NSWarnMLog(@"Unable to correctly set ownership for '%@'", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success: */
|
||||||
|
return YES;
|
||||||
|
|
||||||
|
/* Just in case the failure action needs to be changed. */
|
||||||
|
failure:
|
||||||
|
/*
|
||||||
|
* Attempt to tidy up by removing temporary file on failure.
|
||||||
|
*/
|
||||||
|
if (useAuxiliaryFile)
|
||||||
|
{
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
_wunlink(wthePath);
|
||||||
|
#else
|
||||||
|
unlink(thePath);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1607,6 +1606,16 @@ failure:
|
||||||
options: (NSUInteger)writeOptionsMask
|
options: (NSUInteger)writeOptionsMask
|
||||||
error: (NSError **)errorPtr
|
error: (NSError **)errorPtr
|
||||||
{
|
{
|
||||||
|
if ([url isFileURL] == YES)
|
||||||
|
{
|
||||||
|
return [self writeToFile: [url path]
|
||||||
|
options: writeOptionsMask
|
||||||
|
error: errorPtr];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return [url setResourceData: self];
|
||||||
|
}
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue