Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -192,20 +192,24 @@ */ + (void)copyItemAtPath: (OFString*)source toPath: (OFString*)destination; /*! - * @brief Renames an item. + * @brief Moves an item. * * The destination path must be a full path, which means it must include the * name of the item. * + * If the destination is on a different logical device, the source will be + * copied to the destination using @ref copyItemAtPath:toPath: and the source + * removed using @ref removeItemAtPath:. + * * @param source The item to rename * @param destination The new name for the item */ -+ (void)renameItemAtPath: (OFString*)source - toPath: (OFString*)destination; ++ (void)moveItemAtPath: (OFString*)source + toPath: (OFString*)destination; /*! * @brief Removes the item at the specified path. * * If the item at the specified path is a directory, it is removed recursively. Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -65,15 +65,15 @@ #import "OFCreateSymbolicLinkFailedException.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFLinkFailedException.h" #import "OFLockFailedException.h" +#import "OFMoveItemFailedException.h" #import "OFOpenFileFailedException.h" #import "OFOutOfMemoryException.h" #import "OFReadFailedException.h" #import "OFRemoveItemFailedException.h" -#import "OFRenameItemFailedException.h" #import "OFSeekFailedException.h" #import "OFUnlockFailedException.h" #import "OFWriteFailedException.h" #import "autorelease.h" @@ -663,29 +663,66 @@ destinationPath: destination]; objc_autoreleasePoolPop(pool); } -+ (void)renameItemAtPath: (OFString*)source - toPath: (OFString*)destination ++ (void)moveItemAtPath: (OFString*)source + toPath: (OFString*)destination { void *pool; +#ifndef _WIN32 + struct stat s; +#else + struct _stat s; +#endif if (source == nil || destination == nil) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); #ifndef _WIN32 - if (rename([source cStringWithEncoding: OF_STRING_ENCODING_NATIVE], - [destination cStringWithEncoding: OF_STRING_ENCODING_NATIVE])) + if (lstat([destination + cStringWithEncoding: OF_STRING_ENCODING_NATIVE], &s) == 0) { #else - if (_wrename([source UTF16String], [destination UTF16String])) + if (_wstat([destination UTF16String], &s) == 0) { #endif - @throw [OFRenameItemFailedException + errno = EEXIST; + @throw [OFCopyItemFailedException exceptionWithSourcePath: source destinationPath: destination]; + } + +#ifndef _WIN32 + if (rename([source cStringWithEncoding: OF_STRING_ENCODING_NATIVE], + [destination cStringWithEncoding: OF_STRING_ENCODING_NATIVE])) { +#else + if (_wrename([source UTF16String], [destination UTF16String])) { +#endif + if (errno != EXDEV) + @throw [OFMoveItemFailedException + exceptionWithSourcePath: source + destinationPath: destination]; + + @try { + [OFFile copyItemAtPath: source + toPath: destination]; + } @catch (OFCopyItemFailedException *e) { + [OFFile removeItemAtPath: destination]; + @throw [OFMoveItemFailedException + exceptionWithSourcePath: source + destinationPath: destination]; + } + + @try { + [OFFile removeItemAtPath: source]; + } @catch (OFRemoveItemFailedException *e) { + @throw [OFMoveItemFailedException + exceptionWithSourcePath: source + destinationPath: destination]; + } + } objc_autoreleasePoolPop(pool); } + (void)removeItemAtPath: (OFString*)path Index: src/exceptions/Makefile ================================================================== --- src/exceptions/Makefile +++ src/exceptions/Makefile @@ -22,18 +22,18 @@ OFInvalidServerReplyException.m \ OFLinkFailedException.m \ OFLockFailedException.m \ OFMalformedXMLException.m \ OFMemoryNotPartOfObjectException.m \ + OFMoveItemFailedException.m \ OFNotImplementedException.m \ OFOpenFileFailedException.m \ OFOutOfMemoryException.m \ OFOutOfRangeException.m \ OFReadFailedException.m \ OFReadOrWriteFailedException.m \ OFRemoveItemFailedException.m \ - OFRenameItemFailedException.m \ OFSeekFailedException.m \ OFSetOptionFailedException.m \ OFStillLockedException.m \ OFTruncatedDataException.m \ OFUnboundNamespaceException.m \ ADDED src/exceptions/OFMoveItemFailedException.h Index: src/exceptions/OFMoveItemFailedException.h ================================================================== --- src/exceptions/OFMoveItemFailedException.h +++ src/exceptions/OFMoveItemFailedException.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include + +#import "OFException.h" + +/*! + * @brief An exception indicating that moving an item failed. + */ +@interface OFMoveItemFailedException: OFException +{ + OFString *_sourcePath, *_destinationPath; + int _errNo; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly, copy) OFString *sourcePath, *destinationPath; +@property (readonly) int errNo; +#endif + +/*! + * @brief Creates a new, autoreleased move item failed exception. + * + * @param sourcePath The original path + * @param destinationPath The new path + * @return A new, autoreleased move item failed exception + */ ++ (instancetype)exceptionWithSourcePath: (OFString*)sourcePath + destinationPath: (OFString*)destinationPath; + +/*! + * @brief Initializes an already allocated move item failed exception. + * + * @param sourcePath The original path + * @param destinationPath The new path + * @return An initialized move item failed exception + */ +- initWithSourcePath: (OFString*)sourcePath + destinationPath: (OFString*)destinationPath; + +/*! + * @brief Returns the original path. + * + * @return The original path + */ +- (OFString*)sourcePath; + +/*! + * @brief Returns the new path. + * + * @return The new path + */ +- (OFString*)destinationPath; + +/*! + * @brief Returns the errno from when the exception was created. + * + * @return The errno from when the exception was created + */ +- (int)errNo; +@end ADDED src/exceptions/OFMoveItemFailedException.m Index: src/exceptions/OFMoveItemFailedException.m ================================================================== --- src/exceptions/OFMoveItemFailedException.m +++ src/exceptions/OFMoveItemFailedException.m @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFMoveItemFailedException.h" +#import "OFString.h" + +#import "common.h" +#import "macros.h" + +@implementation OFMoveItemFailedException ++ (instancetype)exceptionWithSourcePath: (OFString*)sourcePath + destinationPath: (OFString*)destinationPath +{ + return [[[self alloc] initWithSourcePath: sourcePath + destinationPath: destinationPath] autorelease]; +} + +- init +{ + OF_INVALID_INIT_METHOD +} + +- initWithSourcePath: (OFString*)sourcePath + destinationPath: (OFString*)destinationPath +{ + self = [super init]; + + @try { + _sourcePath = [sourcePath copy]; + _destinationPath = [destinationPath copy]; + _errNo = GET_ERRNO; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_sourcePath release]; + [_destinationPath release]; + + [super dealloc]; +} + +- (OFString*)description +{ + return [OFString stringWithFormat: + @"Failed to move item at path %@ to %@! " ERRFMT, _sourcePath, + _destinationPath, ERRPARAM]; +} + +- (OFString*)sourcePath +{ + OF_GETTER(_sourcePath, true) +} + +- (OFString*)destinationPath +{ + OF_GETTER(_destinationPath, true) +} + +- (int)errNo +{ + return _errNo; +} +@end DELETED src/exceptions/OFRenameItemFailedException.h Index: src/exceptions/OFRenameItemFailedException.h ================================================================== --- src/exceptions/OFRenameItemFailedException.h +++ src/exceptions/OFRenameItemFailedException.h @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include - -#import "OFException.h" - -/*! - * @brief An exception indicating that renaming an item failed. - */ -@interface OFRenameItemFailedException: OFException -{ - OFString *_sourcePath, *_destinationPath; - int _errNo; -} - -#ifdef OF_HAVE_PROPERTIES -@property (readonly, copy) OFString *sourcePath, *destinationPath; -@property (readonly) int errNo; -#endif - -/*! - * @brief Creates a new, autoreleased rename failed exception. - * - * @param sourcePath The original path - * @param destinationPath The new path - * @return A new, autoreleased rename failed exception - */ -+ (instancetype)exceptionWithSourcePath: (OFString*)sourcePath - destinationPath: (OFString*)destinationPath; - -/*! - * @brief Initializes an already allocated rename failed exception. - * - * @param sourcePath The original path - * @param destinationPath The new path - * @return An initialized rename failed exception - */ -- initWithSourcePath: (OFString*)sourcePath - destinationPath: (OFString*)destinationPath; - -/*! - * @brief Returns the original path. - * - * @return The original path - */ -- (OFString*)sourcePath; - -/*! - * @brief Returns the new path. - * - * @return The new path - */ -- (OFString*)destinationPath; - -/*! - * @brief Returns the errno from when the exception was created. - * - * @return The errno from when the exception was created - */ -- (int)errNo; -@end DELETED src/exceptions/OFRenameItemFailedException.m Index: src/exceptions/OFRenameItemFailedException.m ================================================================== --- src/exceptions/OFRenameItemFailedException.m +++ src/exceptions/OFRenameItemFailedException.m @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "OFRenameItemFailedException.h" -#import "OFString.h" - -#import "common.h" -#import "macros.h" - -@implementation OFRenameItemFailedException -+ (instancetype)exceptionWithSourcePath: (OFString*)sourcePath - destinationPath: (OFString*)destinationPath -{ - return [[[self alloc] initWithSourcePath: sourcePath - destinationPath: destinationPath] autorelease]; -} - -- init -{ - OF_INVALID_INIT_METHOD -} - -- initWithSourcePath: (OFString*)sourcePath - destinationPath: (OFString*)destinationPath -{ - self = [super init]; - - @try { - _sourcePath = [sourcePath copy]; - _destinationPath = [destinationPath copy]; - _errNo = GET_ERRNO; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_sourcePath release]; - [_destinationPath release]; - - [super dealloc]; -} - -- (OFString*)description -{ - return [OFString stringWithFormat: - @"Failed to rename item at path %@ to %@! " ERRFMT, _sourcePath, - _destinationPath, ERRPARAM]; -} - -- (OFString*)sourcePath -{ - OF_GETTER(_sourcePath, true) -} - -- (OFString*)destinationPath -{ - OF_GETTER(_destinationPath, true) -} - -- (int)errNo -{ - return _errNo; -} -@end