Mercurial > gnulib
annotate lib/utime.c @ 40235:5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
* lib/stat-w32.c et al.: Update URLs after most of msdn.microsoft.com
was moved to docs.microsoft.com.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Thu, 14 Mar 2019 09:49:24 +0100 |
parents | b06060465f09 |
children |
rev | line source |
---|---|
18832 | 1 /* Work around platform bugs in utime. |
40057
b06060465f09
maint: Run 'make update-copyright'
Paul Eggert <eggert@cs.ucla.edu>
parents:
19595
diff
changeset
|
2 Copyright (C) 2017-2019 Free Software Foundation, Inc. |
18832 | 3 |
4 This program is free software: you can redistribute it and/or modify | |
5 it under the terms of the GNU General Public License as published by | |
6 the Free Software Foundation; either version 3 of the License, or | |
7 (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, | |
10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 GNU General Public License for more details. | |
13 | |
14 You should have received a copy of the GNU General Public License | |
19190 | 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
18832 | 16 |
17 /* Written by Bruno Haible. */ | |
18 | |
19 #include <config.h> | |
20 | |
21 /* Specification. */ | |
22 #include <utime.h> | |
23 | |
19595
beb2ad957aca
Simplify code. Drop support for Borland C++ on Windows.
Bruno Haible <bruno@clisp.org>
parents:
19484
diff
changeset
|
24 #if defined _WIN32 && ! defined __CYGWIN__ |
18832 | 25 |
26 # include <errno.h> | |
27 # include <stdbool.h> | |
28 # include <windows.h> | |
29 # include "filename.h" | |
30 # include "malloca.h" | |
31 | |
32 int | |
18873
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
33 _gl_utimens_windows (const char *name, struct timespec ts[2]) |
18832 | 34 { |
35 /* POSIX <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13> | |
36 specifies: "More than two leading <slash> characters shall be treated as | |
37 a single <slash> character." */ | |
38 if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2])) | |
39 { | |
40 name += 2; | |
41 while (ISSLASH (name[1])) | |
42 name++; | |
43 } | |
44 | |
45 size_t len = strlen (name); | |
46 size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0); | |
47 | |
48 /* Remove trailing slashes (except the very first one, at position | |
49 drive_prefix_len), but remember their presence. */ | |
50 size_t rlen; | |
51 bool check_dir = false; | |
52 | |
53 rlen = len; | |
54 while (rlen > drive_prefix_len && ISSLASH (name[rlen-1])) | |
55 { | |
56 check_dir = true; | |
57 if (rlen == drive_prefix_len + 1) | |
58 break; | |
59 rlen--; | |
60 } | |
61 | |
62 const char *rname; | |
63 char *malloca_rname; | |
64 if (rlen == len) | |
65 { | |
66 rname = name; | |
67 malloca_rname = NULL; | |
68 } | |
69 else | |
70 { | |
71 malloca_rname = malloca (rlen + 1); | |
72 if (malloca_rname == NULL) | |
73 { | |
74 errno = ENOMEM; | |
75 return -1; | |
76 } | |
77 memcpy (malloca_rname, name, rlen); | |
78 malloca_rname[rlen] = '\0'; | |
79 rname = malloca_rname; | |
80 } | |
81 | |
82 DWORD error; | |
83 | |
84 /* Open a handle to the file. | |
85 CreateFile | |
40235
5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
Bruno Haible <bruno@clisp.org>
parents:
40057
diff
changeset
|
86 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea> |
5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
Bruno Haible <bruno@clisp.org>
parents:
40057
diff
changeset
|
87 <https://docs.microsoft.com/en-us/windows/desktop/FileIO/creating-and-opening-files> */ |
18832 | 88 HANDLE handle = |
89 CreateFile (rname, | |
90 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, | |
91 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
92 NULL, | |
93 OPEN_EXISTING, | |
94 /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only | |
95 in case as different) makes sense only when applied to *all* | |
96 filesystem operations. */ | |
97 FILE_FLAG_BACKUP_SEMANTICS /* | FILE_FLAG_POSIX_SEMANTICS */, | |
98 NULL); | |
99 if (handle == INVALID_HANDLE_VALUE) | |
100 { | |
101 error = GetLastError (); | |
102 goto failed; | |
103 } | |
104 | |
105 if (check_dir) | |
106 { | |
107 /* GetFileAttributes | |
40235
5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
Bruno Haible <bruno@clisp.org>
parents:
40057
diff
changeset
|
108 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileattributesa> */ |
18832 | 109 DWORD attributes = GetFileAttributes (rname); |
110 if (attributes == INVALID_FILE_ATTRIBUTES) | |
111 { | |
112 error = GetLastError (); | |
113 CloseHandle (handle); | |
114 goto failed; | |
115 } | |
116 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) | |
117 { | |
118 CloseHandle (handle); | |
119 if (malloca_rname != NULL) | |
120 freea (malloca_rname); | |
121 errno = ENOTDIR; | |
122 return -1; | |
123 } | |
124 } | |
125 | |
126 { | |
127 /* Use SetFileTime(). See | |
40235
5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
Bruno Haible <bruno@clisp.org>
parents:
40057
diff
changeset
|
128 <https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfiletime> |
5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
Bruno Haible <bruno@clisp.org>
parents:
40057
diff
changeset
|
129 <https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime> */ |
18832 | 130 FILETIME last_access_time; |
131 FILETIME last_write_time; | |
132 if (ts == NULL) | |
133 { | |
134 /* GetSystemTimeAsFileTime is the same as | |
135 GetSystemTime followed by SystemTimeToFileTime. | |
40235
5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
Bruno Haible <bruno@clisp.org>
parents:
40057
diff
changeset
|
136 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime>. |
18832 | 137 It would be overkill to use |
138 GetSystemTimePreciseAsFileTime | |
40235
5a52ef2d4772
all: Update URLs to msdn.microsoft.com.
Bruno Haible <bruno@clisp.org>
parents:
40057
diff
changeset
|
139 <https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime>. */ |
18832 | 140 FILETIME current_time; |
141 GetSystemTimeAsFileTime (¤t_time); | |
142 last_access_time = current_time; | |
143 last_write_time = current_time; | |
144 } | |
145 else | |
146 { | |
147 { | |
148 ULONGLONG time_since_16010101 = | |
18873
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
149 (ULONGLONG) ts[0].tv_sec * 10000000 + ts[0].tv_nsec / 100 + 116444736000000000LL; |
18832 | 150 last_access_time.dwLowDateTime = (DWORD) time_since_16010101; |
151 last_access_time.dwHighDateTime = time_since_16010101 >> 32; | |
152 } | |
153 { | |
154 ULONGLONG time_since_16010101 = | |
18873
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
155 (ULONGLONG) ts[1].tv_sec * 10000000 + ts[1].tv_nsec / 100 + 116444736000000000LL; |
18832 | 156 last_write_time.dwLowDateTime = (DWORD) time_since_16010101; |
157 last_write_time.dwHighDateTime = time_since_16010101 >> 32; | |
158 } | |
159 } | |
160 if (SetFileTime (handle, NULL, &last_access_time, &last_write_time)) | |
161 { | |
162 CloseHandle (handle); | |
163 if (malloca_rname != NULL) | |
164 freea (malloca_rname); | |
165 return 0; | |
166 } | |
167 else | |
168 { | |
169 #if 0 | |
170 DWORD sft_error = GetLastError (); | |
18873
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
171 fprintf (stderr, "utimens SetFileTime error 0x%x\n", (unsigned int) sft_error); |
18832 | 172 #endif |
173 CloseHandle (handle); | |
174 if (malloca_rname != NULL) | |
175 freea (malloca_rname); | |
176 errno = EINVAL; | |
177 return -1; | |
178 } | |
179 } | |
180 | |
181 failed: | |
182 { | |
183 #if 0 | |
18873
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
184 fprintf (stderr, "utimens CreateFile/GetFileAttributes error 0x%x\n", (unsigned int) error); |
18832 | 185 #endif |
186 if (malloca_rname != NULL) | |
187 freea (malloca_rname); | |
188 | |
189 switch (error) | |
190 { | |
191 /* Some of these errors probably cannot happen with the specific flags | |
192 that we pass to CreateFile. But who knows... */ | |
193 case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist. */ | |
194 case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist. */ | |
195 case ERROR_BAD_PATHNAME: /* rname is such as '\\server'. */ | |
18871
3c73d7ec23d2
utime: Handle more Windows error codes.
Bruno Haible <bruno@clisp.org>
parents:
18832
diff
changeset
|
196 case ERROR_BAD_NETPATH: /* rname is such as '\\nonexistentserver\share'. */ |
18832 | 197 case ERROR_BAD_NET_NAME: /* rname is such as '\\server\nonexistentshare'. */ |
198 case ERROR_INVALID_NAME: /* rname contains wildcards, misplaced colon, etc. */ | |
199 case ERROR_DIRECTORY: | |
200 errno = ENOENT; | |
201 break; | |
202 | |
203 case ERROR_ACCESS_DENIED: /* rname is such as 'C:\System Volume Information\foo'. */ | |
204 case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys'. */ | |
205 errno = (ts != NULL ? EPERM : EACCES); | |
206 break; | |
207 | |
208 case ERROR_OUTOFMEMORY: | |
209 errno = ENOMEM; | |
210 break; | |
211 | |
212 case ERROR_WRITE_PROTECT: | |
213 errno = EROFS; | |
214 break; | |
215 | |
216 case ERROR_WRITE_FAULT: | |
217 case ERROR_READ_FAULT: | |
218 case ERROR_GEN_FAILURE: | |
219 errno = EIO; | |
220 break; | |
221 | |
222 case ERROR_BUFFER_OVERFLOW: | |
223 case ERROR_FILENAME_EXCED_RANGE: | |
224 errno = ENAMETOOLONG; | |
225 break; | |
226 | |
227 case ERROR_DELETE_PENDING: /* XXX map to EACCESS or EPERM? */ | |
228 errno = EPERM; | |
229 break; | |
230 | |
231 default: | |
232 errno = EINVAL; | |
233 break; | |
234 } | |
235 | |
236 return -1; | |
237 } | |
238 } | |
239 | |
18873
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
240 int |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
241 utime (const char *name, const struct utimbuf *ts) |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
242 { |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
243 if (ts == NULL) |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
244 return _gl_utimens_windows (name, NULL); |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
245 else |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
246 { |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
247 struct timespec ts_with_nanoseconds[2]; |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
248 ts_with_nanoseconds[0].tv_sec = ts->actime; |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
249 ts_with_nanoseconds[0].tv_nsec = 0; |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
250 ts_with_nanoseconds[1].tv_sec = ts->modtime; |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
251 ts_with_nanoseconds[1].tv_nsec = 0; |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
252 return _gl_utimens_windows (name, ts_with_nanoseconds); |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
253 } |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
254 } |
626a5740518f
utimens: On native Windows, support 100ns resolution also if fd < 0.
Bruno Haible <bruno@clisp.org>
parents:
18871
diff
changeset
|
255 |
18832 | 256 #endif |