@@ -48,10 +48,11 @@ #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFLinkFailedException.h" #import "OFLockFailedException.h" #import "OFMoveItemFailedException.h" +#import "OFNotImplementedException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfMemoryException.h" #import "OFReadFailedException.h" #import "OFRemoveItemFailedException.h" #import "OFStatItemFailedException.h" @@ -84,10 +85,14 @@ static OFMutex *passwdMutex; #endif #if !defined(HAVE_READDIR_R) && !defined(OF_WINDOWS) && defined(OF_HAVE_THREADS) static OFMutex *readdirMutex; #endif + +#ifdef OF_WINDOWS +static WINAPI BOOLEAN (*func_CreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD); +#endif int of_stat(OFString *path, of_stat_t *buffer) { #if defined(OF_WINDOWS) @@ -126,10 +131,14 @@ } @implementation OFFileManager + (void)initialize { +#ifdef OF_WINDOWS + HMODULE module; +#endif + if (self != [OFFileManager class]) return; /* * Make sure OFFile is initialized. @@ -141,10 +150,17 @@ passwdMutex = [[OFMutex alloc] init]; #endif #if !defined(HAVE_READDIR_R) && !defined(OF_WINDOWS) && defined(OF_HAVE_THREADS) readdirMutex = [[OFMutex alloc] init]; #endif + +#ifdef OF_WINDOWS + if ((module = LoadLibrary("kernel32.dll")) != NULL) + func_CreateSymbolicLinkW = + (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, DWORD)) + GetProcAddress(module, "CreateSymbolicLinkW"); +#endif defaultManager = [[OFFileManager alloc] init]; } + (OFFileManager*)defaultManager @@ -873,11 +889,11 @@ } objc_autoreleasePoolPop(pool); } -#ifdef OF_HAVE_LINK +#if defined(OF_HAVE_LINK) - (void)linkItemAtPath: (OFString*)source toPath: (OFString*)destination { void *pool; of_string_encoding_t encoding; @@ -895,13 +911,32 @@ destinationPath: destination errNo: errno]; objc_autoreleasePoolPop(pool); } +#else +- (void)linkItemAtPath: (OFString*)source + toPath: (OFString*)destination +{ + void *pool; + + if (source == nil || destination == nil) + @throw [OFInvalidArgumentException exception]; + + pool = objc_autoreleasePoolPush(); + + if (!CreateHardLinkW([destination UTF16String], + [source UTF16String], NULL)) + @throw [OFLinkFailedException + exceptionWithSourcePath: source + destinationPath: destination]; + + objc_autoreleasePoolPop(pool); +} #endif -#ifdef OF_HAVE_SYMLINK +#if defined(OF_HAVE_SYMLINK) - (void)createSymbolicLinkAtPath: (OFString*)destination withDestinationPath: (OFString*)source { void *pool; of_string_encoding_t encoding; @@ -919,11 +954,36 @@ destinationPath: destination errNo: errno]; objc_autoreleasePoolPop(pool); } +#elif defined(OF_WINDOWS) +- (void)createSymbolicLinkAtPath: (OFString*)destination + withDestinationPath: (OFString*)source +{ + void *pool; + + if (func_CreateSymbolicLinkW == NULL) + @throw [OFNotImplementedException exceptionWithSelector: _cmd + object: self]; + + if (source == nil || destination == nil) + @throw [OFInvalidArgumentException exception]; + + pool = objc_autoreleasePoolPush(); + + if (!func_CreateSymbolicLinkW([destination UTF16String], + [source UTF16String], 0)) + @throw [OFCreateSymbolicLinkFailedException + exceptionWithSourcePath: source + destinationPath: destination]; + + objc_autoreleasePoolPop(pool); +} +#endif +#ifdef OF_HAVE_READLINK - (OFString*)destinationOfSymbolicLinkAtPath: (OFString*)path { char destination[PATH_MAX]; ssize_t length; of_string_encoding_t encoding;