Index: src/OFFileURLHandler.m ================================================================== --- src/OFFileURLHandler.m +++ src/OFFileURLHandler.m @@ -22,12 +22,17 @@ #ifdef HAVE_DIRENT_H # include #endif #include "unistd_wrapper.h" +#import "platform.h" #ifdef HAVE_SYS_STAT_H # include +#endif +#include +#ifdef OF_WINDOWS +# include #endif #ifdef HAVE_PWD_H # include #endif @@ -107,10 +112,11 @@ #if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) && !defined(OF_WINDOWS) static OFMutex *readdirMutex; #endif #ifdef OF_WINDOWS +static int (*func__wutime64)(const wchar_t *, struct __utimbuf64 *); static WINAPI BOOLEAN (*func_CreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD); static WINAPI BOOLEAN (*func_CreateHardLinkW)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); #endif @@ -511,10 +517,14 @@ #if !defined(HAVE_READDIR_R) && !defined(OF_WINDOWS) && defined(OF_HAVE_THREADS) readdirMutex = [[OFMutex alloc] init]; #endif #ifdef OF_WINDOWS + if ((module = LoadLibrary("msvcrt.dll")) != NULL) + func__wutime64 = (int (*)(const wchar_t *, + struct __utimbuf64 *))GetProcAddress(module, "_wutime64"); + if ((module = LoadLibrary("kernel32.dll")) != NULL) { func_CreateSymbolicLinkW = (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, DWORD)) GetProcAddress(module, "CreateSymbolicLinkW"); func_CreateHardLinkW = @@ -595,10 +605,82 @@ objc_autoreleasePoolPop(pool); return ret; } + +- (void)of_setLastAccessDate: (OFDate *)lastAccessDate + andModificationDate: (OFDate *)modificationDate + ofItemAtURL: (OFURL *)URL + attributeKey: (of_file_attribute_key_t)attributeKey + attributes: (of_file_attributes_t)attributes +{ + OFString *path = URL.fileSystemRepresentation; + +#ifdef OF_WINDOWS + if (func__wutime64 != NULL) { + struct __utimbuf64 times = { + .actime = + (__time64_t)lastAccessDate.timeIntervalSince1970, + .modtime = + (__time64_t)modificationDate.timeIntervalSince1970 + }; + + if (func__wutime64([path UTF16String], ×) != 0) + @throw [OFSetItemAttributesFailedException + exceptionWithURL: URL + attributes: attributes + failedAttribute: attributeKey + errNo: errno]; + } else { + struct _utimbuf times = { + .actime = (time_t)lastAccessDate.timeIntervalSince1970, + .modtime = + (time_t)modificationDate.timeIntervalSince1970 + }; + int status; + + if ([OFSystemInfo isWindowsNT]) + status = _wutime([path UTF16String], ×); + else + status = _utime( + [path cStringWithEncoding: [OFLocale encoding]], + ×); + + if (status != 0) + @throw [OFSetItemAttributesFailedException + exceptionWithURL: URL + attributes: attributes + failedAttribute: attributeKey + errNo: errno]; + } +#else + of_time_interval_t lastAccessTime = + lastAccessDate.timeIntervalSince1970; + of_time_interval_t modificationTime = + modificationDate.timeIntervalSince1970; + struct timeval times[2] = { + { + .tv_sec = (time_t)lastAccessTime, + .tv_usec = + (int)((lastAccessTime - times[0].tv_sec) * 1000) + }, + { + .tv_sec = (time_t)modificationTime, + .tv_usec = + (int)((modificationTime - times[1].tv_sec) * 1000) + }, + }; + + if (utimes([path cStringWithEncoding: [OFLocale encoding]], times) != 0) + @throw [OFSetItemAttributesFailedException + exceptionWithURL: URL + attributes: attributes + failedAttribute: attributeKey + errNo: errno]; +#endif +} - (void)of_setPOSIXPermissions: (OFNumber *)permissions ofItemAtURL: (OFURL *)URL attributes: (of_file_attributes_t)attributes { @@ -697,10 +779,11 @@ void *pool = objc_autoreleasePoolPush(); OFEnumerator OF_GENERIC(of_file_attribute_key_t) *keyEnumerator; OFEnumerator *objectEnumerator; of_file_attribute_key_t key; id object; + OFDate *lastAccessDate, *modificationDate; if (URL == nil) @throw [OFInvalidArgumentException exception]; if (![URL.scheme isEqual: _scheme]) @@ -709,11 +792,14 @@ keyEnumerator = [attributes keyEnumerator]; objectEnumerator = [attributes objectEnumerator]; while ((key = [keyEnumerator nextObject]) != nil && (object = [objectEnumerator nextObject]) != nil) { - if ([key isEqual: of_file_attribute_key_posix_permissions]) + if ([key isEqual: of_file_attribute_key_modification_date] || + [key isEqual: of_file_attribute_key_last_access_date]) + continue; + else if ([key isEqual: of_file_attribute_key_posix_permissions]) [self of_setPOSIXPermissions: object ofItemAtURL: URL attributes: attributes]; else if ([key isEqual: of_file_attribute_key_owner]) [self of_setOwner: object @@ -730,10 +816,35 @@ else @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; } + + lastAccessDate = [attributes + objectForKey: of_file_attribute_key_last_access_date]; + modificationDate = [attributes + objectForKey: of_file_attribute_key_modification_date]; + + if (lastAccessDate != nil || modificationDate != nil) { + of_file_attribute_key_t attributeKey; + + if (modificationDate != nil) + attributeKey = of_file_attribute_key_modification_date; + else + attributeKey = of_file_attribute_key_last_access_date; + + if (lastAccessDate == nil) + lastAccessDate = modificationDate; + if (modificationDate == nil) + modificationDate = lastAccessDate; + + [self of_setLastAccessDate: lastAccessDate + andModificationDate: modificationDate + ofItemAtURL: URL + attributeKey: attributeKey + attributes: attributes]; + } objc_autoreleasePoolPop(pool); } - (bool)fileExistsAtURL: (OFURL *)URL