Index: src/OFExceptions.h ================================================================== --- src/OFExceptions.h +++ src/OFExceptions.h @@ -9,10 +9,11 @@ * the packaging of this file. */ #import "OFObject.h" #import "OFString.h" +#import "OFFile.h" /** * An exception indicating an object could not be allocated. * * This exception is preallocated, as if there's no memory, no exception can @@ -353,10 +354,202 @@ * An OFException indicating a write to the file failed. */ @interface OFWriteFailedException: OFReadOrWriteFailedException {} @end +/** + * An OFException indicating that changing the mode of the file failed. + */ +@interface OFChangeFileModeFailedException: OFException +{ + OFString *path; + mode_t mode; + int err; +} + +/** + * \param class_ The class of the object which caused the exception + * \param path The path of the file + * \param mode The new mode for the file + * \return An initialized change file mode failed exception + */ ++ newWithClass: (Class)class_ + path: (OFString*)path + mode: (mode_t)mode; + +/** + * Initializes an already allocated change file mode failed exception. + * + * \param class_ The class of the object which caused the exception + * \param path The path of the file + * \param mode The new mode for the file + * \return An initialized change file mode failed exception + */ +- initWithClass: (Class)class_ + path: (OFString*)path + mode: (mode_t)mode; + +/** + * \return The errno from when the exception was created + */ +- (int)errNo; + +/** + * \return The path of the file + */ +- (OFString*)path; + +/** + * \return The new mode for the file + */ +- (mode_t)mode; +@end + +/** + * An OFException indicating that changing the owner of the file failed. + */ +@interface OFChangeFileOwnerFailedException: OFException +{ + OFString *path; + uid_t owner; + gid_t group; + int err; +} + +/** + * \param class_ The class of the object which caused the exception + * \param path The path of the file + * \param owner The new owner for the file + * \param group The new group for the file + * \return An initialized change file owner failed exception + */ ++ newWithClass: (Class)class_ + path: (OFString*)path + owner: (uid_t)owner + group: (gid_t)group; + +/** + * Initializes an already allocated change file owner failed exception. + * + * \param class_ The class of the object which caused the exception + * \param path The path of the file + * \param owner The new owner for the file + * \param group The new group for the file + * \return An initialized change file owner failed exception + */ +- initWithClass: (Class)class_ + path: (OFString*)path + owner: (uid_t)owner + group: (gid_t)group; + +/** + * \return The errno from when the exception was created + */ +- (int)errNo; + +/** + * \return The path of the file + */ +- (OFString*)path; + +/** + * \return The new owner for the file + */ +- (uid_t)owner; + +/** + * \return The new group for the file + */ +- (gid_t)group; +@end + +/** + * An OFException indicating that renaming a file failed. + */ +@interface OFRenameFileFailedException: OFException +{ + OFString *from; + OFString *to; + int err; +} + +/** + * \param class_ The class of the object which caused the exception + * \param from The original path + * \param to The new path + * \return A new rename file failed exception + */ ++ newWithClass: (Class)class_ + from: (OFString*)from + to: (OFString*)to; + +/** + * Initializes an already allocated rename failed exception. + * + * \param class_ The class of the object which caused the exception + * \param from The original path + * \param to The new path + * \return An initialized rename file failed exception + */ +- initWithClass: (Class)class_ + from: (OFString*)from + to: (OFString*)to; + +/** + * \return The errno from when the exception was created + */ +- (int)errNo; + +/** + * \return The original path + */ +- (OFString*)from; + +/** + * \return The new path + */ +- (OFString*)to; +@end + +/** + * An OFException indicating that deleting a file failed. + */ +@interface OFDeleteFileFailedException: OFException +{ + OFString *path; + int err; +} + +/** + * \param class_ The class of the object which caused the exception + * \param path The path of the file + * \return A new delete file failed exception + */ ++ newWithClass: (Class)class_ + path: (OFString*)path; + +/** + * Initializes an already allocated delete file failed exception. + * + * \param class_ The class of the object which caused the exception + * \param path The path of the file + * \return An initialized delete file failed exception + */ +- initWithClass: (Class)class_ + path: (OFString*)path; + +/** + * \return The errno from when the exception was created + */ +- (int)errNo; + +/** + * \return The path of the file + */ +- (OFString*)path; +@end + /** * An OFException indicating that creating a link failed. */ @interface OFLinkFailedException: OFException { @@ -374,11 +567,11 @@ + newWithClass: (Class)class_ source: (OFString*)src destination: (OFString*)dest; /** - * Initializes an already allocated open file failed exception. + * Initializes an already allocated link failed exception. * * \param class_ The class of the object which caused the exception * \param source The source for the link * \param destination The destination for the link * \return An initialized link failed exception @@ -422,11 +615,11 @@ + newWithClass: (Class)class_ source: (OFString*)src destination: (OFString*)dest; /** - * Initializes an already allocated open file failed exception. + * Initializes an already allocated symlink failed exception. * * \param class_ The class of the object which caused the exception * \param source The source for the symlink * \param destination The destination for the symlink * \return An initialized symlink failed exception Index: src/OFExceptions.m ================================================================== --- src/OFExceptions.m +++ src/OFExceptions.m @@ -335,13 +335,13 @@ @implementation OFOpenFileFailedException + newWithClass: (Class)class__ path: (OFString*)path_ mode: (OFString*)mode_ { - return [[self alloc] initWithClass: class__ - path: path_ - mode: mode_]; + return [(OFOpenFileFailedException*)[self alloc] initWithClass: class__ + path: path_ + mode: mode_]; } - initWithClass: (Class)class__ { @throw [OFNotImplementedException newWithClass: isa @@ -511,10 +511,268 @@ [class_ className], ERRPARAM]; return string; } @end + +@implementation OFChangeFileModeFailedException ++ newWithClass: (Class)class__ + path: (OFString*)path_ + mode: (mode_t)mode_ +{ + return [(OFChangeFileModeFailedException*)[self alloc] + initWithClass: class__ + path: path_ + mode: mode_]; +} + +- initWithClass: (Class)class__ +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- initWithClass: (Class)class__ + path: (OFString*)path_ + mode: (mode_t)mode_ +{ + self = [super initWithClass: class__]; + + path = [path_ copy]; + mode = mode_; + err = GET_ERR; + + return self; +} + +- (void)dealloc +{ + [path release]; + + [super dealloc]; +} + +- (OFString*)string +{ + if (string != nil) + return string; + + string = [[OFString alloc] initWithFormat: + @"Failed to change mode for file %s to %d in class %s! " ERRFMT, + [path cString], mode, [class_ className], ERRPARAM]; + + return string; +} + +- (int)errNo +{ + return err; +} + +- (OFString*)path +{ + return path; +} + +- (mode_t)mode +{ + return mode; +} +@end + +@implementation OFChangeFileOwnerFailedException ++ newWithClass: (Class)class__ + path: (OFString*)path_ + owner: (uid_t)owner_ + group: (gid_t)group_ +{ + return [[self alloc] initWithClass: class__ + path: path_ + owner: owner_ + group: group_]; +} + +- initWithClass: (Class)class__ +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- initWithClass: (Class)class__ + path: (OFString*)path_ + owner: (uid_t)owner_ + group: (gid_t)group_ +{ + self = [super initWithClass: class__]; + + path = [path_ copy]; + owner = owner_; + group = group_; + err = GET_ERR; + + return self; +} + +- (void)dealloc +{ + [path release]; + + [super dealloc]; +} + +- (OFString*)string +{ + if (string != nil) + return string; + + string = [[OFString alloc] initWithFormat: + @"Failed to change owner for file %s to %d:%d in class %s! " ERRFMT, + [path cString], owner, group, [class_ className], ERRPARAM]; + + return string; +} + +- (int)errNo +{ + return err; +} + +- (OFString*)path +{ + return path; +} + +- (uid_t)owner +{ + return owner; +} + +- (gid_t)group +{ + return group; +} +@end + +@implementation OFRenameFileFailedException ++ newWithClass: (Class)class__ + from: (OFString*)from_ + to: (OFString*)to_ +{ + return [[self alloc] initWithClass: class__ + from: from_ + to: to_]; +} + +- initWithClass: (Class)class__ +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- initWithClass: (Class)class__ + from: (OFString*)from_ + to: (OFString*)to_ +{ + self = [super initWithClass: class__]; + + from = [from_ copy]; + to = [to_ copy]; + err = GET_ERR; + + return self; +} + +- (void)dealloc +{ + [from release]; + [to release]; + + [super dealloc]; +} + +- (OFString*)string +{ + if (string != nil) + return string; + + string = [[OFString alloc] initWithFormat: + @"Failed to rename file %s to %s in class %s! " ERRFMT, + [from cString], [to cString], [class_ className], ERRPARAM]; + + return string; +} + +- (int)errNo +{ + return err; +} + +- (OFString*)from +{ + return from; +} + +- (OFString*)to +{ + return to; +} +@end + +@implementation OFDeleteFileFailedException ++ newWithClass: (Class)class__ + path: (OFString*)path_ +{ + return [[self alloc] initWithClass: class__ + path: path_]; +} + +- initWithClass: (Class)class__ +{ + @throw [OFNotImplementedException newWithClass: isa + selector: _cmd]; +} + +- initWithClass: (Class)class__ + path: (OFString*)path_ +{ + self = [super initWithClass: class__]; + + path = [path_ copy]; + err = GET_ERR; + + return self; +} + +- (void)dealloc +{ + [path release]; + + [super dealloc]; +} + +- (OFString*)string +{ + if (string != nil) + return string; + + string = [[OFString alloc] initWithFormat: + @"Failed to delete file %s in class %s! " ERRFMT, [path cString], + [class_ className], ERRPARAM]; + + return string; +} + +- (int)errNo +{ + return err; +} + +- (OFString*)path +{ + return path; +} +@end @implementation OFLinkFailedException + newWithClass: (Class)class__ source: (OFString*)src_ destination: (OFString*)dest_ Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -43,36 +43,20 @@ * It is not closed when the OFFile object is deallocated! * \return A new autoreleased OFFile */ + fileWithFilePointer: (FILE*)fp; -/** - * \return An OFFile singleton for stdin - */ -+ standardInput; - -/** - * \return An OFFile singleton for stdout - */ -+ standardOutput; - -/** - * \return An OFFile singleton for stderr - */ -+ standardError; - /** * Changes the mode of a file. * * Not available on Windows. * * \param path The path to the file of which the mode should be changed as a * string * \param mode The new mode for the file - * \return A boolean whether the operation succeeded */ -+ (BOOL)changeModeOfFile: (OFString*)path ++ (void)changeModeOfFile: (OFString*)path toMode: (mode_t)mode; /** * Changes the owner of a file. * @@ -80,21 +64,28 @@ * * \param path The path to the file of which the owner should be changed as a * string * \param owner The new owner for the file * \param group The new group for the file - * \return A boolean whether the operation succeeded */ -+ (BOOL)changeOwnerOfFile: (OFString*)path - owner: (uid_t)owner ++ (void)changeOwnerOfFile: (OFString*)path + toOwner: (uid_t)owner group: (gid_t)group; +/** + * Renames a file. + * + * \param from The file to rename + * \param to The new name + */ ++ (void)rename: (OFString*)from + to: (OFString*)to; + /** * Deletes a file. * * \param path The path to the file of which should be deleted as a string - * \return A boolean whether the operation succeeded */ + (void)delete: (OFString*)path; /** * Hardlinks a file. @@ -101,11 +92,10 @@ * * Not available on Windows. * * \param src The path to the file of which should be linked as a string * \param dest The path to where the file should be linked as a string - * \return A boolean whether the operation succeeded */ + (void)link: (OFString*)src to: (OFString*)dest; /** @@ -113,11 +103,10 @@ * * Not available on Windows. * * \param src The path to the file of which should be symlinked as a string * \param dest The path to where the file should be symlinked as a string - * \return A boolean whether the operation succeeded */ + (void)symlink: (OFString*)src to: (OFString*)dest; /** @@ -165,5 +154,12 @@ fromBuffer: (const char*)buf; @end @interface OFFileSingleton: OFFile @end + +/// An OFFile object for stdin. +extern OFFile *of_stdin; +/// An OFFile object for stdout. +extern OFFile *of_stdout; +/// An OFFile object for stderr. +extern OFFile *of_stderr; Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -21,15 +21,29 @@ #endif #import "OFFile.h" #import "OFExceptions.h" -static OFFileSingleton *of_file_stdin = nil; -static OFFileSingleton *of_file_stdout = nil; -static OFFileSingleton *of_file_stderr = nil; +#ifdef _WIN32 +#import +#endif + +OFFile *of_stdin = nil; +OFFile *of_stdout = nil; +OFFile *of_stderr = nil; @implementation OFFile ++ (void)load +{ + if (self != [OFFile class]) + return; + + of_stdin = [[OFFileSingleton alloc] initWithFilePointer: stdin]; + of_stdout = [[OFFileSingleton alloc] initWithFilePointer: stdout]; + of_stderr = [[OFFileSingleton alloc] initWithFilePointer: stderr]; +} + + fileWithPath: (OFString*)path mode: (OFString*)mode { return [[[self alloc] initWithPath: path mode: mode] autorelease]; @@ -38,66 +52,73 @@ + fileWithFilePointer: (FILE*)fp_ { return [[[self alloc] initWithFilePointer: fp_] autorelease]; } -+ standardInput -{ - if (of_file_stdin == nil) - of_file_stdin = [[OFFileSingleton alloc] - initWithFilePointer: stdin]; - - return of_file_stdin; -} - -+ standardOutput -{ - if (of_file_stdout == nil) - of_file_stdout = [[OFFileSingleton alloc] - initWithFilePointer: stdout]; - - return of_file_stdout; -} - -+ standardError -{ - if (of_file_stderr == nil) - of_file_stderr = [[OFFileSingleton alloc] - initWithFilePointer: stderr]; - - return of_file_stderr; -} - -+ (BOOL)changeModeOfFile: (OFString*)path ++ (void)changeModeOfFile: (OFString*)path toMode: (mode_t)mode { #ifndef _WIN32 - return (chmod([path cString], mode) == 0 ? YES : NO); + if (chmod([path cString], mode)) + @throw [OFChangeFileModeFailedException newWithClass: self + path: path + mode: mode]; #else - /* - * FIXME: On Win32, change write access - */ - return NO; + DWORD attrs = GetFileAttributes([path cString]); + + if (attrs == INVALID_FILE_ATTRIBUTES) + @throw [OFChangeFileModeFailedException newWithClass: self + path: path + mode: mode]; + + if ((mode / 100) & 2) + attrs &= ~FILE_ATTRIBUTE_READONLY; + else + attrs |= FILE_ATTRIBUTE_READONLY; + + if (!SetFileAttributes([path cString], attrs)) + @throw [OFChangeFileModeFailedException newWithClass: self + path: path + mode: mode]; #endif } -+ (BOOL)changeOwnerOfFile: (OFString*)path - owner: (uid_t)owner ++ (void)changeOwnerOfFile: (OFString*)path + toOwner: (uid_t)owner group: (gid_t)group { - /* FIXME: On error, throw exception */ +#ifndef _WIN32 + if (chown([path cString], owner, group)) + @throw [OFChangeFileOwnerFailedException newWithClass: self + path: path + owner: owner + group: group]; +#endif +} + ++ (void)rename: (OFString*)from + to: (OFString*)to +{ #ifndef _WIN32 - return (chown([path cString], owner, group) == 0 ? YES : NO); + if (rename([from cString], [to cString])) #else - return NO; + if (!MoveFile([from cString], [to cString])) #endif + @throw [OFRenameFileFailedException newWithClass: self + from: from + to: to]; } + (void)delete: (OFString*)path { - /* FIXME: On error, throw exception */ - unlink([path cString]); +#ifndef _WIN32 + if (unlink([path cString])) +#else + if (!DeleteFile([path cString])) +#endif + @throw [OFDeleteFileFailedException newWithClass: self + path: path]; } + (void)link: (OFString*)src to: (OFString*)dest {