diff --git a/ChangeLog b/ChangeLog index 69db3ac8a..966c8c973 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +Thu Feb 5 10:12:00 1998 Richard Frith-Macdonald + + * src/NSConcreteNumber.m: Defined preprocessor values to handle + 'promotion' of numeric types and added private methods to support + this. Modified ([-compare:]) to promote numeric values so that + comparisons work as expected. Implemented ([-isEqualToNumber:]), + Implemented ([-description]) and partially ([-descriptionWithLocale:]) + Implemented ([-hash]) so that numbers which compare the same also + has the same (so we can use NSNumbers as dictionary keys). + + * src/NSData.m: Added non-openstep method ([-relinquishAllocatedBytes]) + to ask a data object to hand over it's malloced buffer. + + * src/NSNumber.m: Added initialisation methods specified in Rhapsody + documentation. + + * src/NSString.m: ([-dataUsingEncoding:allowLossyConversion:]) made + tiny change for efficiency - moving test outside loop - perhaps the + compiler would have optimised it anyway. + + * src/Port.m: Modified initialisaers to test for failure to create + NSData objects and return nil as appropriate. + + * src/TcpPort.m: ([+newForReceivingFromPortNumber:]) release newly + created port before raising exceptions. + In both ([-invalidate]) methods we remove the port from the various + maps before doing anything else so that invalid ports can't be found + by accident during the invalidation process. + + * src/UnixFileHandle.m: ([-readDataOfLength:]) fixed problem with + data object causing read value to be overwritten with nuls. + + * src/include/NSData.h: Added ([-relinquishAllocatedBytes]) + + * src/NSValue.h: Added initialisation methods for NSNumber and + ([-isEqualToNumber:]) method. + Thu Feb 5 10:48:35 1998 Adam Fedor * GNUmakefile (GNUSTEP_MAKEFILE_DIR): New variable. Use it to diff --git a/Headers/gnustep/base/NSData.h b/Headers/gnustep/base/NSData.h index d4a4a2277..29e63cfc2 100644 --- a/Headers/gnustep/base/NSData.h +++ b/Headers/gnustep/base/NSData.h @@ -94,6 +94,16 @@ + (id) dataWithShmID: (int)anID length: (unsigned) length; + (id) dataWithSharedBytes: (const void*)bytes length: (unsigned) length; + (id) dataWithStaticBytes: (const void*)bytes length: (unsigned) length; +/* + * -relinquishAllocatedBytes + * For an NSData object with a malloced buffer, returns that buffer and + * removes it from the NSData object, otherwise returns a nul pointer. + * Use with care, preferably when no-one else has retained the NSData + * object - or they will find it's buffer disappearing unexpectedly. + * Once you have used this method, you own the malloced data and are + * responsible for freeing it. + */ +- (void*) relinquishAllocatedBytes; @end diff --git a/Headers/gnustep/base/NSValue.h b/Headers/gnustep/base/NSValue.h index 31ccc9fac..8ea837f23 100644 --- a/Headers/gnustep/base/NSValue.h +++ b/Headers/gnustep/base/NSValue.h @@ -1,4 +1,4 @@ -/* Interface for NSArray for GNUStep +/* Interface for NSValue for GNUStep Copyright (C) 1995, 1996 Free Software Foundation, Inc. Written by: Adam Fedor @@ -74,6 +74,20 @@ + (NSNumber*) numberWithUnsignedLongLong: (unsigned long long)value; + (NSNumber*) numberWithUnsignedShort: (unsigned short)value; +- (id)initWithBool:(BOOL)value; +- (id)initWithChar:(char)value; +- (id)initWithDouble:(double)value; +- (id)initWithFloat:(float)value; +- (id)initWithInt:(int)value; +- (id)initWithLong:(long)value; +- (id)initWithLongLong:(long long)value; +- (id)initWithShort:(short)value; +- (id)initWithUnsignedChar:(unsigned char)value; +- (id)initWithUnsignedInt:(unsigned int)value; +- (id)initWithUnsignedLong:(unsigned long)value; +- (id)initWithUnsignedLongLong:(unsigned long long)value; +- (id)initWithUnsignedShort:(unsigned short)value; + // Accessing Data - (BOOL) boolValue; @@ -91,7 +105,11 @@ - (unsigned long) unsignedLongValue; - (unsigned short) unsignedShortValue; +- (NSString*) description; +- (NSString*) descriptionWithLocale: (NSDictionary*)locale; + - (NSComparisonResult) compare: (NSNumber*)otherNumber; +- (BOOL) isEqualToNumber: (NSNumber*)otherNumber; @end diff --git a/Source/NSConcreteNumber.m b/Source/NSConcreteNumber.m index 5b0f678c7..fabb5d64e 100644 --- a/Source/NSConcreteNumber.m +++ b/Source/NSConcreteNumber.m @@ -36,56 +36,124 @@ # define NumberTemplate NSBoolNumber # define TYPE_METHOD boolValue # define TYPE_FORMAT @"%uc" +# define NEXT_ORDER 4 +# define NEXT_METHOD shortValue +# define NEXT_CTYPE short #elif TYPE_ORDER == 1 # define NumberTemplate NSUCharNumber # define TYPE_METHOD unsignedCharValue # define TYPE_FORMAT @"%uc" +# define NEXT_ORDER 4 +# define NEXT_METHOD shortValue +# define NEXT_CTYPE short #elif TYPE_ORDER == 2 # define NumberTemplate NSCharNumber # define TYPE_METHOD charValue # define TYPE_FORMAT @"%c" +# define NEXT_ORDER 4 +# define NEXT_METHOD shortValue +# define NEXT_CTYPE short #elif TYPE_ORDER == 3 # define NumberTemplate NSUShortNumber # define TYPE_METHOD unsignedShortValue # define TYPE_FORMAT @"%hu" +# define NEXT_ORDER 6 +# define NEXT_METHOD intValue +# define NEXT_CTYPE int #elif TYPE_ORDER == 4 # define NumberTemplate NSShortNumber # define TYPE_METHOD shortValue # define TYPE_FORMAT @"%hd" +# define NEXT_ORDER 6 +# define NEXT_METHOD intValue +# define NEXT_CTYPE int #elif TYPE_ORDER == 5 # define NumberTemplate NSUIntNumber # define TYPE_METHOD unsignedIntValue # define TYPE_FORMAT @"%u" +# define NEXT_ORDER 8 +# define NEXT_METHOD longValue +# define NEXT_CTYPE long #elif TYPE_ORDER == 6 # define NumberTemplate NSIntNumber # define TYPE_METHOD intValue # define TYPE_FORMAT @"%d" +# define NEXT_ORDER 8 +# define NEXT_METHOD longValue +# define NEXT_CTYPE long #elif TYPE_ORDER == 7 # define NumberTemplate NSULongNumber # define TYPE_METHOD unsignedLongValue # define TYPE_FORMAT @"%lu" +# define NEXT_ORDER 10 +# define NEXT_METHOD longLongValue +# define NEXT_CTYPE long long #elif TYPE_ORDER == 8 # define NumberTemplate NSLongNumber # define TYPE_METHOD longValue # define TYPE_FORMAT @"%ld" +# define NEXT_ORDER 10 +# define NEXT_METHOD longLongValue +# define NEXT_CTYPE long long #elif TYPE_ORDER == 9 # define NumberTemplate NSULongLongNumber # define TYPE_METHOD unsignedLongLongValue # define TYPE_FORMAT @"%llu" +# define NEXT_ORDER 12 +# define NEXT_METHOD doubleValue +# define NEXT_CTYPE double #elif TYPE_ORDER == 10 # define NumberTemplate NSLongLongNumber # define TYPE_METHOD longLongValue # define TYPE_FORMAT @"%lld" +# define NEXT_ORDER 12 +# define NEXT_METHOD doubleValue +# define NEXT_CTYPE double #elif TYPE_ORDER == 11 # define NumberTemplate NSFloatNumber # define TYPE_METHOD floatValue # define TYPE_FORMAT @"%f" +# define NEXT_ORDER 12 +# define NEXT_METHOD doubleValue +# define NEXT_CTYPE double #elif TYPE_ORDER == 12 # define NumberTemplate NSDoubleNumber # define TYPE_METHOD doubleValue # define TYPE_FORMAT @"%g" +# define NEXT_ORDER 12 +# define NEXT_METHOD doubleValue +# define NEXT_CTYPE double #endif +@interface NSNumber (Private) +- (int)_nextOrder; +- (NSComparisonResult) _promotedCompare: (NSNumber*)other; +- (int)_typeOrder; +@end + +@implementation NumberTemplate (Private) +- (int)_nextOrder +{ + return NEXT_ORDER; +} +- (NSComparisonResult) _promotedCompare: (NSNumber*)other +{ + NEXT_CTYPE v0, v1; + + v0 = [self NEXT_METHOD]; + v1 = [other NEXT_METHOD]; + + if (v0 == v1) + return NSOrderedSame; + else + return (v0 < v1) ? NSOrderedAscending : NSOrderedDescending; +} +- (int)_typeOrder +{ + return TYPE_ORDER; +} +@end + @implementation NumberTemplate - initValue:(const void *)value withObjCType:(const char *)type; @@ -136,11 +204,6 @@ return data; } -- (NSString *)stringValue -{ - return [NSString stringWithFormat:TYPE_FORMAT, data]; -} - - (unsigned char)unsignedCharValue { return data; @@ -166,15 +229,84 @@ return data; } -- (NSComparisonResult)compare:(NSNumber *)otherNumber +- (NSComparisonResult)compare:(NSNumber *)other { - typedef _dt = data; - _dt other_data = [otherNumber TYPE_METHOD]; + int o = [self _typeOrder]; + + if (o == [other _typeOrder] || o >= [other _nextOrder]) { + typedef _dt = data; + _dt other_data = [other TYPE_METHOD]; - if (data == other_data) - return NSOrderedSame; - else - return (data < other_data) ? NSOrderedAscending : NSOrderedDescending; + if (data == other_data) + return NSOrderedSame; + else + return (data < other_data) ? + NSOrderedAscending : NSOrderedDescending; + } + o = [self _nextOrder]; + if (o <= [other _typeOrder]) { + NSComparisonResult r = [other compare: self]; + if (r == NSOrderedAscending) { + return NSOrderedDescending; + } + if (r == NSOrderedDescending) { + return NSOrderedAscending; + } + return r; + } + if (o >= [other _nextOrder]) { + return [self _promotedCompare: other]; + } + else { + NSComparisonResult r = [other _promotedCompare: self]; + if (r == NSOrderedAscending) { + return NSOrderedDescending; + } + if (r == NSOrderedDescending) { + return NSOrderedAscending; + } + return r; + } +} + +/* Because of the rule that two numbers which are the same according to + * [-isEqual:] must generate the same hash, we must generate the hash + * from the most general representation of the number. + */ +- (unsigned) hash +{ + union { + double d; + unsigned char c[sizeof(double)]; + } val; + unsigned hash = 0; + int i; + + val.d = [self doubleValue]; + for (i = 0; i < sizeof(double); i++) { + hash += val.c[i]; + } + return hash; +} + +- (BOOL) isEqualToNumber: (NSNumber*)o +{ + if ([self compare: o] == NSOrderedSame) + return YES; + return NO; +} + +- (BOOL) isEqual: o +{ + if ([o isKindOf: [NSNumber class]]) + return [self isEqualToNumber: (NSNumber*)o]; + else + return [super isEqual: o]; +} + +- (NSString *)descriptionWithLocale: (NSDictionary*)locale +{ + return [NSString stringWithFormat:TYPE_FORMAT, data]; } // Override these from NSValue @@ -194,18 +326,6 @@ return @encode(_dt); } -- (unsigned) hash -{ - return (unsigned)data; -} - -- (BOOL) isEqual: o -{ - if ([o isKindOf: [NSValue class]]) - return ((unsigned)data == [o unsignedIntValue]) ? YES : NO; - return NO; -} - // NSCoding - classForCoder { diff --git a/Source/NSData.m b/Source/NSData.m index bdd549738..1bf05ba2d 100644 --- a/Source/NSData.m +++ b/Source/NSData.m @@ -800,6 +800,11 @@ readContentsOfFile(NSString* path, void** buf, unsigned* len) return [[[NSDataStatic alloc] initWithBytesNoCopy:(void*)bytes length:length] autorelease]; } + +- (void*) relinquishAllocatedBytes +{ + return 0; /* No data from malloc - return nul pointer */ +} @end @@ -1312,6 +1317,15 @@ readContentsOfFile(NSString* path, void** buf, unsigned* len) length: length]; } +- (void*) relinquishAllocatedBytes +{ + void *buf = bytes; + + bytes = 0; + length = 0; + return buf; +} + @end #if HAVE_MMAP @@ -1732,6 +1746,12 @@ readContentsOfFile(NSString* path, void** buf, unsigned* len) length = size; } +- (void*) relinquishAllocatedBytes +{ + capacity = 0; + return [super relinquishAllocatedBytes]; +} + @end diff --git a/Source/NSFileManager.m b/Source/NSFileManager.m index d1f4dd63c..80712baa0 100644 --- a/Source/NSFileManager.m +++ b/Source/NSFileManager.m @@ -31,6 +31,8 @@ #include #include +#include + /* determine directory reading files */ #if defined(HAVE_DIRENT_H) @@ -91,12 +93,22 @@ # include #endif +#if HAVE_SYS_FILE_H +#include +#endif + #include #ifdef HAVE_SYS_STAT_H #include #endif +#include + +#if HAVE_UTIME_H +# include +#endif + /* include usual headers */ #include @@ -108,6 +120,19 @@ #include #include +@interface NSFileManager (PrivateMethods) + +/* Copies the contents of source file to destination file. Assumes source + and destination are regular files or symbolic links. */ +- (BOOL)_copyFile:(NSString*)source toFile:(NSString*)destination + handler:handler; + +/* Recursively copies the contents of source directory to destination. */ +- (BOOL)_copyPath:(NSString*)source toPath:(NSString*)destination + handler:handler; + +@end /* NSFileManager (PrivateMethods) */ + /* * NSFileManager implementation */ @@ -237,44 +262,139 @@ static NSFileManager* defaultManager = nil; - (BOOL)copyPath:(NSString*)source toPath:(NSString*)destination handler:handler { - // TODO + BOOL sourceIsDir, fileExists; + NSDictionary* attributes; + + fileExists = [self fileExistsAtPath:source isDirectory:&sourceIsDir]; + if (!fileExists) + return NO; + + fileExists = [self fileExistsAtPath:destination]; + if (fileExists) + return NO; + + attributes = [self fileAttributesAtPath:source traverseLink:NO]; + + if (sourceIsDir) { + /* If destination directory is a descendant of source directory copying + isn't possible. */ + if ([[destination stringByAppendingString:@"/"] + hasPrefix:[source stringByAppendingString:@"/"]]) + return NO; + + [handler fileManager:self willProcessPath:destination]; + if (![self createDirectoryAtPath:destination attributes:attributes]) { + if (handler) { + NSDictionary* errorInfo + = [NSDictionary dictionaryWithObjectsAndKeys: + destination, @"Path", + @"cannot create directory", @"Error", + nil]; + return [handler fileManager:self + shouldProceedAfterError:errorInfo]; + } + else + return NO; + } + } + + if (sourceIsDir) { + if (![self _copyPath:source toPath:destination handler:handler]) + return NO; + else { + [self changeFileAttributes:attributes atPath:destination]; + return YES; + } + } + else { + [handler fileManager:self willProcessPath:source]; + if (![self _copyFile:source toFile:destination handler:handler]) + return NO; + else { + [self changeFileAttributes:attributes atPath:destination]; + return YES; + } + } + return NO; } - (BOOL)movePath:(NSString*)source toPath:(NSString*)destination handler:handler { - BOOL sourceIsDir; + BOOL sourceIsDir, fileExists; const char* sourcePath = [self fileSystemRepresentationWithPath:source]; const char* destPath = [self fileSystemRepresentationWithPath:destination]; + NSString* destinationParent; + unsigned int sourceDevice, destinationDevice; - if ([self fileExistsAtPath:source isDirectory:&sourceIsDir] - && !sourceIsDir) { - /* `source' is file so simply move it to destination. */ + fileExists = [self fileExistsAtPath:source isDirectory:&sourceIsDir]; + if (!fileExists) + return NO; + + fileExists = [self fileExistsAtPath:destination]; + if (fileExists) + return NO; + + /* Check to see if the source and destination's parent are on the same + physical device so we can perform a rename syscall directly. */ + sourceDevice = [[[self fileSystemAttributesAtPath:source] + objectForKey:NSFileSystemNumber] + unsignedIntValue]; + destinationParent = [destination stringByDeletingLastPathComponent]; + if ([destinationParent isEqual:@""]) + destinationParent = @"."; + destinationDevice + = [[[self fileSystemAttributesAtPath:destinationParent] + objectForKey:NSFileSystemNumber] + unsignedIntValue]; + + if (sourceDevice != destinationDevice) { + /* If destination directory is a descendant of source directory moving + isn't possible. */ + if (sourceIsDir && [[destination stringByAppendingString:@"/"] + hasPrefix:[source stringByAppendingString:@"/"]]) + return NO; + + if ([self copyPath:source toPath:destination handler:handler]) { + NSDictionary* attributes; + + attributes = [self fileAttributesAtPath:source traverseLink:NO]; + [self changeFileAttributes:attributes atPath:destination]; + return [self removeFileAtPath:source handler:handler]; + } + else + return NO; + } + else { + /* source and destination are on the same device so we can simply + invoke rename on source. */ [handler fileManager:self willProcessPath:source]; - if (rename(sourcePath, destPath) == -1) { + if (rename (sourcePath, destPath) == -1) { if (handler) { - NSDictionary* dict + NSDictionary* errorInfo = [NSDictionary dictionaryWithObjectsAndKeys: source, @"Path", - [NSString stringWithCString:strerror(errno)], @"Error", destination, @"ToPath", + @"cannot move file", @"Error", nil]; - if ([handler fileManager:self shouldProceedAfterError:dict]) + if ([handler fileManager:self + shouldProceedAfterError:errorInfo]) return YES; } return NO; } + return YES; } - // TODO: handle directories - return YES; + return NO; } - (BOOL)linkPath:(NSString*)source toPath:(NSString*)destination handler:handler { // TODO + [self notImplemented:_cmd]; return NO; } @@ -361,8 +481,26 @@ static NSFileManager* defaultManager = nil; - (BOOL)createFileAtPath:(NSString*)path contents:(NSData*)contents attributes:(NSDictionary*)attributes { - // TODO - return NO; + int fd, len, written; + + fd = open ([self fileSystemRepresentationWithPath:path], + O_WRONLY|O_TRUNC|O_CREAT, 0644); + if (fd < 0) + return NO; + + if (![self changeFileAttributes:attributes atPath:path]) { + close (fd); + return NO; + } + + len = [contents length]; + if (len) + written = write (fd, [contents bytes], len); + else + written = 0; + close (fd); + + return written == len; } // Getting and comparing file contents @@ -370,12 +508,14 @@ static NSFileManager* defaultManager = nil; - (NSData*)contentsAtPath:(NSString*)path { // TODO + [self notImplemented:_cmd]; return nil; } - (BOOL)contentsEqualAtPath:(NSString*)path1 andPath:(NSString*)path2 { // TODO + [self notImplemented:_cmd]; return NO; } @@ -495,12 +635,16 @@ static NSFileManager* defaultManager = nil; values[8] = NSFileTypeCharacterSpecial; else if (mode == S_IFBLK) values[8] = NSFileTypeBlockSpecial; +#ifdef S_IFLNK else if (mode == S_IFLNK) values[8] = NSFileTypeSymbolicLink; +#endif else if (mode == S_IFIFO) values[8] = NSFileTypeFifo; +#ifdef S_IFSOCK else if (mode == S_IFSOCK) values[8] = NSFileTypeSocket; +#endif else values[8] = NSFileTypeUnknown; @@ -963,4 +1107,185 @@ static NSFileManager* defaultManager = nil; {return [self objectForKey:NSFileModificationDate];} - (NSNumber*)filePosixPermissions; {return [self objectForKey:NSFilePosixPermissions];} + + +@implementation NSFileManager (PrivateMethods) + +- (BOOL)_copyFile:(NSString*)source toFile:(NSString*)destination + handler:handler +{ + NSDictionary* attributes; + int i, bufsize = 8096; + int sourceFd, destFd, fileSize, fileMode; + int rbytes, wbytes; + char buffer[bufsize]; + + /* Assumes source is a file and exists! */ + NSAssert1 ([self fileExistsAtPath:source], + @"source file '%@' does not exist!", source); + + attributes = [self fileAttributesAtPath:source traverseLink:NO]; + NSAssert1 (attributes, @"could not get the attributes for file '%@'", + source); + + fileSize = [[attributes objectForKey:NSFileSize] intValue]; + fileMode = [[attributes objectForKey:NSFilePosixPermissions] intValue]; + + /* Open the source file. In case of error call the handler. */ + sourceFd = open ([self fileSystemRepresentationWithPath:source], O_RDONLY); + if (sourceFd < 0) { + if (handler) { + NSDictionary* errorInfo + = [NSDictionary dictionaryWithObjectsAndKeys: + source, @"Path", + @"cannot open file for reading", @"Error", + nil]; + return [handler fileManager:self + shouldProceedAfterError:errorInfo]; + } + else + return NO; + } + + /* Open the destination file. In case of error call the handler. */ + destFd = open ([self fileSystemRepresentationWithPath:destination], + O_WRONLY|O_CREAT|O_TRUNC, fileMode); + if (destFd < 0) { + if (handler) { + NSDictionary* errorInfo + = [NSDictionary dictionaryWithObjectsAndKeys: + destination, @"ToPath", + @"cannot open file for writing", @"Error", + nil]; + close (sourceFd); + return [handler fileManager:self + shouldProceedAfterError:errorInfo]; + } + else + return NO; + } + + /* Read bufsize bytes from source file and write them into the destination + file. In case of errors call the handler and abort the operation. */ + for (i = 0; i < fileSize; i += rbytes) { + rbytes = read (sourceFd, buffer, bufsize); + if (rbytes < 0) { + if (handler) { + NSDictionary* errorInfo + = [NSDictionary dictionaryWithObjectsAndKeys: + source, @"Path", + @"cannot read from file", @"Error", + nil]; + close (sourceFd); + close (destFd); + return [handler fileManager:self + shouldProceedAfterError:errorInfo]; + } + else + return NO; + } + + wbytes = write (destFd, buffer, rbytes); + if (wbytes != rbytes) { + if (handler) { + NSDictionary* errorInfo + = [NSDictionary dictionaryWithObjectsAndKeys: + source, @"Path", + destination, @"ToPath", + @"cannot write to file", @"Error", + nil]; + close (sourceFd); + close (destFd); + return [handler fileManager:self + shouldProceedAfterError:errorInfo]; + } + else + return NO; + } + } + close (sourceFd); + close (destFd); + + return YES; +} + +- (BOOL)_copyPath:(NSString*)source + toPath:(NSString*)destination + handler:handler +{ + NSDirectoryEnumerator* enumerator; + NSString* dirEntry; + NSString* sourceFile; + NSString* fileType; + NSString* destinationFile; + NSDictionary* attributes; + NSAutoreleasePool* pool; + + pool = [NSAutoreleasePool new]; + enumerator = [self enumeratorAtPath:source]; + while ((dirEntry = [enumerator nextObject])) { + attributes = [enumerator fileAttributes]; + fileType = [attributes objectForKey:NSFileType]; + sourceFile = [source stringByAppendingPathComponent:dirEntry]; + destinationFile + = [destination stringByAppendingPathComponent:dirEntry]; + + [handler fileManager:self willProcessPath:sourceFile]; + if ([fileType isEqual:NSFileTypeDirectory]) { + if (![self createDirectoryAtPath:destinationFile + attributes:attributes]) { + if (handler) { + NSDictionary* errorInfo + = [NSDictionary dictionaryWithObjectsAndKeys: + destinationFile, @"Path", + @"cannot create directory", @"Error", + nil]; + if (![handler fileManager:self + shouldProceedAfterError:errorInfo]) + return NO; + } + else + return NO; + } + else { + [enumerator skipDescendents]; + if (![self _copyPath:sourceFile toPath:destinationFile + handler:handler]) + return NO; + } + } + else if ([fileType isEqual:NSFileTypeRegular]) { + if (![self _copyFile:sourceFile toFile:destinationFile + handler:handler]) + return NO; + } + else if ([fileType isEqual:NSFileTypeSymbolicLink]) { + if (![self createSymbolicLinkAtPath:destinationFile + pathContent:sourceFile]) { + if (handler) { + NSDictionary* errorInfo + = [NSDictionary dictionaryWithObjectsAndKeys: + sourceFile, @"Path", + destinationFile, @"ToPath", + @"cannot create symbolic link", @"Error", + nil]; + if (![handler fileManager:self + shouldProceedAfterError:errorInfo]) + return NO; + } + else + return NO; + } + } + else { + NSLog(@"cannot copy file '%@' of type '%@'", sourceFile, fileType); + } + [self changeFileAttributes:attributes atPath:destinationFile]; + } + [pool release]; + + return YES; +} + +@end /* NSFileManager (PrivateMethods) */ @end diff --git a/Source/NSNumber.m b/Source/NSNumber.m index 2e5b023ba..760c74506 100644 --- a/Source/NSNumber.m +++ b/Source/NSNumber.m @@ -182,6 +182,95 @@ return [NSNumber numberWithInt: 0]; } +- (id)initWithBool:(BOOL)value +{ + [self dealloc]; + return self=[[NSBoolNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithChar:(char)value +{ + [self dealloc]; + return self=[[NSCharNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithDouble:(double)value +{ + [self dealloc]; + return self=[[NSDoubleNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithFloat:(float)value +{ + [self dealloc]; + return self=[[NSFloatNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithInt:(int)value +{ + [self dealloc]; + return self=[[NSIntNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithLong:(long)value +{ + [self dealloc]; + return self=[[NSLongNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithLongLong:(long long)value +{ + [self dealloc]; + return self=[[NSLongLongNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithShort:(short)value +{ + [self dealloc]; + return self=[[NSShortNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithUnsignedChar:(unsigned char)value +{ + [self dealloc]; + return self=[[NSUCharNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithUnsignedInt:(unsigned int)value +{ + [self dealloc]; + return self=[[NSUIntNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithUnsignedLong:(unsigned long)value +{ + [self dealloc]; + return self=[[NSULongNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithUnsignedLongLong:(unsigned long long)value +{ + [self dealloc]; + return self=[[NSULongLongNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (id)initWithUnsignedShort:(unsigned short)value +{ + [self dealloc]; + return self=[[NSUShortNumber alloc] initValue:&value withObjCType:NULL]; +} + +- (NSString*) description +{ + return [self descriptionWithLocale: nil]; +} + +- (NSString*) descriptionWithLocale: (NSDictionary*)locale +{ + [self subclassResponsibility:_cmd]; + return nil; +} + /* All the rest of these methods must be implemented by a subclass */ - (BOOL)boolValue { @@ -233,8 +322,7 @@ - (NSString *)stringValue { - [self subclassResponsibility:_cmd]; - return 0; + return [self descriptionWithLocale: nil]; } - (unsigned char)unsignedCharValue @@ -273,6 +361,18 @@ return 0; } +- (unsigned) hash +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (BOOL)isEqualToNumber:(NSNumber *)otherNumber +{ + [self subclassResponsibility:_cmd]; + return NO; +} + // NSCoding (done by subclasses) - (void)encodeWithCoder:(NSCoder *)coder { @@ -286,9 +386,4 @@ return self; } -- description -{ - return [self stringValue]; -} - @end diff --git a/Source/NSString.m b/Source/NSString.m index 7260aa242..dac821649 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -2016,13 +2016,14 @@ else unsigned char *buff; char t; OBJC_MALLOC(buff, char, len+1); - for(count=0; count_port_socket = socket (AF_INET, SOCK_STREAM, 0); if (p->_port_socket < 0) { + [p release]; [NSException raise: NSInternalInconsistencyException format: @"[TcpInPort +newForReceivingFromPortNumber:] socket(): %s", strerror(errno)]; @@ -779,6 +780,7 @@ static NSMapTable* port_number_2_port; } } if (ok == NO) { + [p release]; [NSException raise: NSInternalInconsistencyException format: @"[TcpInPort +newForReceivingFromPortNumber:] bind(): %s", strerror(errno)]; @@ -796,6 +798,7 @@ static NSMapTable* port_number_2_port; &size) < 0) { + [p release]; [NSException raise: NSInternalInconsistencyException format: @"[TcpInPort +newForReceivingFromPortNumber:] getsockname(): %s", strerror(errno)]; @@ -811,6 +814,7 @@ static NSMapTable* port_number_2_port; unique host address that can identify us across the network. */ if (gethostname (hostname, len) < 0) { + [p release]; [NSException raise: NSInternalInconsistencyException format: @"[TcpInPort +newForReceivingFromPortNumber:] gethostname(): %s", strerror(errno)]; @@ -832,6 +836,7 @@ static NSMapTable* port_number_2_port; /* xxx Make this "10" a class variable? */ if (listen (p->_port_socket, 10) < 0) { + [p release]; [NSException raise: NSInternalInconsistencyException format: @"[TcpInPort +newForReceivingFromPortNumber:] listen(): %s", strerror(errno)]; @@ -860,7 +865,7 @@ static NSMapTable* port_number_2_port; if (p) { int port = [p portNumber]; - if (nameServer([name cStringNoCopy], 0, GDO_REGISTER, &sin, port, 1) == 0) { + if (nameServer([name cString], 0, GDO_REGISTER, &sin, port, 1) == 0) { [p release]; return nil; } @@ -868,7 +873,7 @@ static NSMapTable* port_number_2_port; return p; #else return [self newForReceivingFromPortNumber: - name_2_port_number ([name cStringNoCopy])]; + name_2_port_number ([name cString])]; #endif /* GDOMAP */ } @@ -990,7 +995,7 @@ static NSMapTable* port_number_2_port; fprintf (stderr, "%s: Accepted connection from\n %s.\n", object_get_class_name (self), - [[op description] cStringNoCopy]); + [[op description] cString]); [NotificationDispatcher postNotificationName: InPortAcceptedClientNotification object: self @@ -1154,7 +1159,7 @@ assert(type == ET_RPORT); fprintf (stderr, "%s: Closed connection from\n %s\n", object_get_class_name (self), - [[p description] cStringNoCopy]); + [[p description] cString]); packet = NSMapGet (_client_sock_2_packet, (void*)s); if (packet) @@ -1198,6 +1203,12 @@ assert(type == ET_RPORT); id out_ports[count]; int i; + /* These are here, and not in -dealloc, to prevent + +newForReceivingFromPortNumber: from returning invalid sockets. */ + NSMapRemove (socket_2_port, (void*)_port_socket); + NSMapRemove (port_number_2_port, + (void*)(int) ntohs(_listening_address.sin_port)); + for (i = 0; NSNextMapEnumeratorPair (&me, (void*)&sock, (void*)&out_port); i++) @@ -1213,17 +1224,14 @@ assert(type == ET_RPORT); getting it. This may help Connection invalidation confusion. However, then the process might run out of FD's if the close() was delayed too long. */ + if (_port_socket > 0) + { #ifdef __WIN32__ - closesocket (_port_socket); + closesocket (_port_socket); #else - close (_port_socket); + close (_port_socket); #endif /* __WIN32__ */ - - /* These are here, and not in -dealloc, to prevent - +newForReceivingFromPortNumber: from returning invalid sockets. */ - NSMapRemove (socket_2_port, (void*)_port_socket); - NSMapRemove (port_number_2_port, - (void*)(int) ntohs(_listening_address.sin_port)); + } /* This also posts a NSPortDidBecomeInvalidNotification. */ [super invalidate]; @@ -1414,15 +1422,20 @@ static NSMapTable *out_port_bag = NULL; != sockaddr->sin_addr.s_addr)) [self error:"Can't change reply port of an out port once set"]; #else - /* If someone is trying to change the port of this socket, the - old one must have died - invalidate it. */ if ((p->_remote_in_port_address.sin_port != sockaddr->sin_port) || (p->_remote_in_port_address.sin_addr.s_addr != sockaddr->sin_addr.s_addr)) { - [p invalidate]; - p = nil; + NSString *od = [p description]; + + NSMapRemove (out_port_bag, (void*)p); + memcpy (&(p->_remote_in_port_address), + sockaddr, + sizeof (p->_remote_in_port_address)); + NSMapInsert (out_port_bag, (void*)p, (void*)p); + NSLog(@"Out port changed from %@ to %@\n", od, + [p description]); } #endif } @@ -1434,7 +1447,7 @@ static NSMapTable *out_port_bag = NULL; sizeof (p->_remote_in_port_address)); if (debug_tcp_port) printf ("TcpOutPort setting remote address\n%s\n", - [[self description] cStringNoCopy]); + [[self description] cString]); } } if (p) @@ -1456,6 +1469,7 @@ static NSMapTable *out_port_bag = NULL; p->_port_socket = socket (AF_INET, SOCK_STREAM, 0); if (p->_port_socket < 0) { + [p release]; [NSException raise: NSInternalInconsistencyException format: @"[TcpInPort newForSendingToSockaddr:...] socket(): %s", strerror(errno)]; @@ -1478,9 +1492,7 @@ static NSMapTable *out_port_bag = NULL; time being, and may get set later by calling +newForSendingToSockaddr.. with a non-zero socket, and a non-NULL sockaddr. */ - p->_remote_in_port_address.sin_family = 0; - p->_remote_in_port_address.sin_port = 0; - p->_remote_in_port_address.sin_addr.s_addr = 0; + memset (&(p->_remote_in_port_address), '\0', sizeof(*sockaddr)); } /* xxx Do I need to bind(_port_socket) to this address? I don't think so. */ @@ -1494,18 +1506,12 @@ static NSMapTable *out_port_bag = NULL; if (connect (p->_port_socket, (struct sockaddr*)&(p->_remote_in_port_address), - sizeof(p->_remote_in_port_address)) - < 0) + sizeof(p->_remote_in_port_address)) < 0) { -#if 0 - close(p->_port_socket); - [NSException raise: NSInternalInconsistencyException + [p release]; + [NSException raise: NSInternalInconsistencyException format: @"[TcpInPort newForSendingToSockaddr:...] connect(): %s", strerror(errno)]; -#else - [p release]; - return nil; -#endif } /* @@ -1565,7 +1571,7 @@ static NSMapTable *out_port_bag = NULL; *first_dot = '\0'; } else - host_cstring = [hostname cStringNoCopy]; + host_cstring = [hostname cString]; hp = gethostbyname ((char*)host_cstring); if (!hp) [self error: "unknown host: \"%s\"", host_cstring]; @@ -1589,7 +1595,7 @@ static NSMapTable *out_port_bag = NULL; int i; id c = nil; - found = nameServer([name cStringNoCopy], [hostname cStringNoCopy], + found = nameServer([name cString], [hostname cString], GDO_LOOKUP, sin, 0, 100); for (i = 0; c == nil && i < found; i++) { @@ -1600,8 +1606,7 @@ static NSMapTable *out_port_bag = NULL; return c; #else return [self newForSendingToPortNumber: - name_2_port_number ([name cStringNoCopy]) - onHost: hostname];; + name_2_port_number ([name cString]) onHost: hostname];; #endif /* GDOMAP */ } @@ -1700,22 +1705,6 @@ static NSMapTable *out_port_bag = NULL; _polling_in_port = nil; - /* This also posts a NSPortDidBecomeInvalidNotification. */ - [super invalidate]; - - /* xxx Perhaps should delay this close() to keep another port from - getting it. This may help Connection invalidation confusion. */ - #ifdef __WIN32__ - if (closesocket (_port_socket) < 0) - #else - if (close (_port_socket) < 0) - #endif /* __WIN32 */ - { - [NSException raise: NSInternalInconsistencyException - format: @"[TcpOutPort -invalidate:] close(): %s", - strerror(errno)]; - } - /* This is here, and not in -dealloc, because invalidated but not dealloc'ed ports should not be returned from the out_port_bag in +newForSendingToSockaddr:... */ @@ -1725,6 +1714,25 @@ static NSMapTable *out_port_bag = NULL; the socket_2_port in +newForSendingToSockaddr:... */ NSMapRemove (socket_2_port, (void*)_port_socket); + /* This also posts a NSPortDidBecomeInvalidNotification. */ + [super invalidate]; + + /* xxx Perhaps should delay this close() to keep another port from + getting it. This may help Connection invalidation confusion. */ + if (_port_socket > 0) + { + #ifdef __WIN32__ + if (closesocket (_port_socket) < 0) + #else + if (close (_port_socket) < 0) + #endif /* __WIN32 */ + { + [NSException raise: NSInternalInconsistencyException + format: @"[TcpOutPort -invalidate:] close(): %s", + strerror(errno)]; + } + } + [port _connectedOutPortInvalidated: self]; [port release]; } diff --git a/Source/UnixFileHandle.m b/Source/UnixFileHandle.m index 96562bc51..39ce56ce1 100644 --- a/Source/UnixFileHandle.m +++ b/Source/UnixFileHandle.m @@ -631,9 +631,11 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin) { NSMutableData* d; int pos; + char *buf; [self checkRead]; - d = [NSMutableData dataWithCapacity:len]; + buf = objc_malloc(len); + d = [NSMutableData dataWithBytesNoCopy: buf length: len]; if ((pos = read(descriptor, [d mutableBytes], len)) < 0) { [NSException raise: NSFileHandleOperationException