1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* filestat.c */ |
4 | /* */ |
5 | /* Replacement for Windows code */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2012, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
13 | /* */ |
14 | /* */ |
15 | /* This software is provided 'as-is', without any expressed or implied */ |
16 | /* warranty. In no event will the authors be held liable for any damages */ |
17 | /* arising from the use of this software. */ |
18 | /* */ |
19 | /* Permission is granted to anyone to use this software for any purpose, */ |
20 | /* including commercial applications, and to alter it and redistribute it */ |
21 | /* freely, subject to the following restrictions: */ |
22 | /* */ |
23 | /* 1. The origin of this software must not be misrepresented; you must not */ |
24 | /* claim that you wrote the original software. If you use this software */ |
25 | /* in a product, an acknowledgment in the product documentation would be */ |
26 | /* appreciated but is not required. */ |
27 | /* 2. Altered source versions must be plainly marked as such, and must not */ |
28 | /* be misrepresented as being the original software. */ |
29 | /* 3. This notice may not be removed or altered from any source */ |
30 | /* distribution. */ |
31 | /* */ |
32 | /*****************************************************************************/ |
33 | |
34 | |
35 | |
36 | /* This module works around bugs in the time conversion code supplied by |
37 | ** Microsoft. See here for a description of the problem: |
38 | ** http://www.codeproject.com/KB/datetime/dstbugs.aspx |
39 | ** Please let me note that I find it absolutely unacceptable to just declare |
40 | ** buggy behaviour like this "works as designed" as Microsoft does. The |
41 | ** problems did even make it into .NET, where the DateTime builtin data type |
42 | ** has exactly the same problems as described in the article above. |
43 | */ |
44 | |
45 | |
46 | |
47 | #include <sys/types.h> |
48 | #include <sys/stat.h> |
49 | #if defined(_WIN32) |
50 | # include <errno.h> |
51 | # include <windows.h> |
52 | #endif |
53 | |
54 | /* common */ |
55 | #include "filestat.h" |
56 | |
57 | |
58 | |
59 | /*****************************************************************************/ |
60 | /* Code */ |
61 | /*****************************************************************************/ |
62 | |
63 | |
64 | |
65 | #if defined(_WIN32) |
66 | |
67 | |
68 | |
69 | static time_t FileTimeToUnixTime (const FILETIME* T) |
70 | /* Calculate a unix time_t value from a FILETIME. FILETIME contains a 64 bit |
71 | ** value with point zero at 1600-01-01 00:00:00 and counting 100ns intervals. |
72 | ** time_t is in seconds since 1970-01-01 00:00:00. |
73 | */ |
74 | { |
75 | /* Offset between 1600-01-01 and the Epoch in seconds. Watcom C has no |
76 | ** way to express a number > 32 bit (known to me) but is able to do |
77 | ** calculations with 64 bit integers, so we need to do it this way. |
78 | */ |
79 | static const ULARGE_INTEGER Offs = { { 0xB6109100UL, 0x00000020UL } }; |
80 | ULARGE_INTEGER V; |
81 | V.LowPart = T->dwLowDateTime; |
82 | V.HighPart = T->dwHighDateTime; |
83 | return (V.QuadPart / 10000000U) - Offs.QuadPart; |
84 | } |
85 | |
86 | |
87 | |
88 | int FileStat (const char* Path, struct stat* Buf) |
89 | /* Replacement function for stat() */ |
90 | { |
91 | |
92 | HANDLE H; |
93 | BY_HANDLE_FILE_INFORMATION Info; |
94 | |
95 | /* First call stat() */ |
96 | int Error = stat (Path, Buf); |
97 | if (Error != 0) { |
98 | return Error; |
99 | } |
100 | |
101 | /* Open the file using backup semantics, so we won't change atime. Then |
102 | ** retrieve the correct times in UTC and replace the ones in Buf. Return |
103 | ** EACCES in case of errors to avoid the hassle of translating windows |
104 | ** error codes to standard ones. |
105 | */ |
106 | H = CreateFile (Path, |
107 | GENERIC_READ, |
108 | FILE_SHARE_READ, |
109 | 0, /* Security attributes */ |
110 | OPEN_EXISTING, |
111 | FILE_FLAG_BACKUP_SEMANTICS, |
112 | 0); /* Template file */ |
113 | if (H != INVALID_HANDLE_VALUE) { |
114 | if (GetFileInformationByHandle (H, &Info)) { |
115 | Buf->st_ctime = FileTimeToUnixTime (&Info.ftCreationTime); |
116 | Buf->st_atime = FileTimeToUnixTime (&Info.ftLastAccessTime); |
117 | Buf->st_mtime = FileTimeToUnixTime (&Info.ftLastWriteTime); |
118 | } else { |
119 | Error = EACCES; |
120 | } |
121 | (void) CloseHandle (H); |
122 | } else { |
123 | Error = EACCES; |
124 | } |
125 | |
126 | /* Done */ |
127 | return Error; |
128 | } |
129 | |
130 | |
131 | |
132 | #else |
133 | |
134 | |
135 | |
136 | int FileStat (const char* Path, struct stat* Buf) |
137 | /* Replacement function for stat() */ |
138 | { |
139 | /* Just call the function which works without errors */ |
140 | return stat (Path, Buf); |
141 | } |
142 | |
143 | |
144 | |
145 | #endif |
146 | |