ObjFW  Check-in [7eb995ad11]

Overview
Comment:Don't use _wutime64 on Windows

It seems to be buggy in some MinGW distributions and doesn't handle DST
correctly.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7eb995ad117084321e97f78ee306a3a189f7461cb8ed17c0cc7d08b749d2cbe2
User & Date: js on 2024-04-21 11:16:37
Other Links: manifest | tags
Context
2024-04-21
19:15
Use RtlGenRandom on Windows if available check-in: 2bcb2bd40f user: js tags: trunk
11:16
Don't use _wutime64 on Windows check-in: 7eb995ad11 user: js tags: trunk
2024-04-20
17:50
Update ChangeLog for 1.1.2 check-in: dca251a2b9 user: js tags: trunk
Changes

Modified src/OFFileIRIHandler.m from [d9639e50f4] to [ae11241b71].

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
41
42
43
44
45
46
47



48
49
50
51
52
53
54







-
-
-







#endif
#if defined(OF_FREEBSD) || defined(OF_NETBSD)
# include <sys/extattr.h>
#endif
#ifdef OF_HAIKU
# include <kernel/fs_attr.h>
#endif
#ifdef OF_WINDOWS
# include <utime.h>
#endif
#ifdef OF_DJGPP
# include <syslimits.h>
#endif

#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171













172
173
174
175
176
177
178
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187







-

















+
+
+
+
+
+
+
+
+
+
+
+
+







releaseReaddirMutex(void)
{
	[readdirMutex release];
}
#endif

#ifdef OF_WINDOWS
static int (*_wutime64FuncPtr)(const wchar_t *, struct __utimbuf64 *);
static WINAPI BOOLEAN (*createSymbolicLinkWFuncPtr)(LPCWSTR, LPCWSTR, DWORD);
static WINAPI BOOLEAN (*createHardLinkWFuncPtr)(LPCWSTR, LPCWSTR,
    LPSECURITY_ATTRIBUTES);
#endif

#ifdef OF_FREEBSD
static const char *namespaces[] = EXTATTR_NAMESPACE_NAMES;
static int numNamespaces = sizeof(namespaces) / sizeof(*namespaces);
#endif

#ifdef OF_WINDOWS
static OFTimeInterval
filetimeToTimeInterval(const FILETIME *filetime)
{
	return (double)((int64_t)filetime->dwHighDateTime << 32 |
	    filetime->dwLowDateTime) / 10000000.0 - 11644473600.0;
}

static FILETIME
timeIntervalToFiletime(OFTimeInterval timeInterval)
{
	uint64_t timestamp =
	    (uint64_t)((timeInterval + 11644473600.0) * 10000000.0);
	FILETIME filetime = {
		.dwHighDateTime = timestamp >> 32,
		.dwLowDateTime = timestamp & 0xFFFFFFFF
	};

	return filetime;
}

static int
lastError(void)
{
	switch (GetLastError()) {
	case ERROR_FILE_NOT_FOUND:
	case ERROR_PATH_NOT_FOUND:
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
786
787
788
789
790
791
792




793
794
795
796
797
798
799







-
-
-
-







#endif
#if defined(OF_HAVE_THREADS) && !defined(__GLIBC__) && !defined(OF_WINDOWS)
	readdirMutex = [[OFMutex alloc] init];
	atexit(releaseReaddirMutex);
#endif

#ifdef OF_WINDOWS
	if ((module = GetModuleHandle("msvcrt.dll")) != NULL)
		_wutime64FuncPtr = (int (*)(const wchar_t *,
		    struct __utimbuf64 *))GetProcAddress(module, "_wutime64");

	if ((module = GetModuleHandleA("kernel32.dll")) != NULL) {
		createSymbolicLinkWFuncPtr =
		    (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR, DWORD))
		    GetProcAddress(module, "CreateSymbolicLinkW");
		createHardLinkWFuncPtr =
		    (WINAPI BOOLEAN (*)(LPCWSTR, LPCWSTR,
		    LPSECURITY_ATTRIBUTES))
895
896
897
898
899
900
901
902
903
904
905
906
907
908















909






910
911



912
913
914

915
916
917
918
919
920
921






922
923
924
925
926
927
928
929
930
931
932
933
934
935
936

937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
900
901
902
903
904
905
906







907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928


929
930
931
932


933
934






935
936
937
938
939
940







941







942













943
944
945
946
947
948
949







-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
-
-
+
+
+

-
-
+

-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-

-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-








	if (lastAccessDate == nil)
		lastAccessDate = modificationDate;
	if (modificationDate == nil)
		modificationDate = lastAccessDate;

#if defined(OF_WINDOWS)
	if (_wutime64FuncPtr != NULL) {
		struct __utimbuf64 times = {
			.actime =
			    (__time64_t)lastAccessDate.timeIntervalSince1970,
			.modtime =
			    (__time64_t)modificationDate.timeIntervalSince1970
		};
	FILETIME accessTime = timeIntervalToFiletime(
	    lastAccessDate.timeIntervalSince1970);
	FILETIME modificationTime = timeIntervalToFiletime(
	    modificationDate.timeIntervalSince1970);
	HANDLE handle;

	if ([OFSystemInfo isWindowsNT])
		handle = CreateFileW(path.UTF16String, FILE_WRITE_ATTRIBUTES,
		    FILE_SHARE_READ, NULL, OPEN_EXISTING,
		    FILE_ATTRIBUTE_NORMAL, NULL);
	else
		handle = CreateFileA(
		    [path cStringWithEncoding: [OFLocale encoding]],
		    FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL,
		    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (handle == NULL)
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  attributes: attributes
		     failedAttribute: attributeKey
			       errNo: lastError()];
		if (_wutime64FuncPtr([path UTF16String], &times) != 0) {
			int errNo = errno;

	if (!SetFileTime(handle, NULL, &accessTime, &modificationTime)) {
		int errNo = lastError();

			if (errNo == EACCES && [self directoryExistsAtIRI: IRI])
				errNo = EISDIR;
		CloseHandle(handle);

			@throw [OFSetItemAttributesFailedException
			    exceptionWithIRI: IRI
				  attributes: attributes
			     failedAttribute: attributeKey
				       errNo: errNo];
		}
		@throw [OFSetItemAttributesFailedException
		    exceptionWithIRI: IRI
			  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], &times);
		else
			status = _utime(
			    [path cStringWithEncoding: [OFLocale encoding]],
			    &times);

	CloseHandle(handle);
		if (status != 0) {
			int errNo = errno;

			if (errNo == EACCES && [self directoryExistsAtIRI: IRI])
				errNo = EISDIR;

			@throw [OFSetItemAttributesFailedException
			    exceptionWithIRI: IRI
				  attributes: attributes
			     failedAttribute: attributeKey
				       errNo: errNo];
		}
	}
#elif defined(OF_AMIGAOS)
	/* AmigaOS does not support access time. */
	OFTimeInterval modificationTime =
	    modificationDate.timeIntervalSince1970;
	struct Locale *locale;
	struct DateStamp date;