• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 #include "tool_filetime.h"
25 #include "tool_cfgable.h"
26 #include "tool_msgs.h"
27 #include "curlx.h"
28 
29 #ifdef HAVE_UTIME_H
30 #  include <utime.h>
31 #elif defined(HAVE_SYS_UTIME_H)
32 #  include <sys/utime.h>
33 #endif
34 
getfiletime(const char * filename,struct GlobalConfig * global)35 curl_off_t getfiletime(const char *filename, struct GlobalConfig *global)
36 {
37   curl_off_t result = -1;
38 
39 /* Windows stat() may attempt to adjust the unix GMT file time by a daylight
40    saving time offset and since it's GMT that is bad behavior. When we have
41    access to a 64-bit type we can bypass stat and get the times directly. */
42 #if defined(WIN32)
43   HANDLE hfile;
44   TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);
45 
46   hfile = CreateFile(tchar_filename, FILE_READ_ATTRIBUTES,
47                       (FILE_SHARE_READ | FILE_SHARE_WRITE |
48                        FILE_SHARE_DELETE),
49                       NULL, OPEN_EXISTING, 0, NULL);
50   curlx_unicodefree(tchar_filename);
51   if(hfile != INVALID_HANDLE_VALUE) {
52     FILETIME ft;
53     if(GetFileTime(hfile, NULL, NULL, &ft)) {
54       curl_off_t converted = (curl_off_t)ft.dwLowDateTime
55           | ((curl_off_t)ft.dwHighDateTime) << 32;
56 
57       if(converted < CURL_OFF_T_C(116444736000000000)) {
58         warnf(global, "Failed to get filetime: underflow\n");
59       }
60       else {
61         result = (converted - CURL_OFF_T_C(116444736000000000)) / 10000000;
62       }
63     }
64     else {
65       warnf(global, "Failed to get filetime: "
66             "GetFileTime failed: GetLastError %u\n",
67             (unsigned int)GetLastError());
68     }
69     CloseHandle(hfile);
70   }
71   else if(GetLastError() != ERROR_FILE_NOT_FOUND) {
72     warnf(global, "Failed to get filetime: "
73           "CreateFile failed: GetLastError %u\n",
74           (unsigned int)GetLastError());
75   }
76 #else
77   struct_stat statbuf;
78   if(-1 != stat(filename, &statbuf)) {
79     result = (curl_off_t)statbuf.st_mtime;
80   }
81   else if(errno != ENOENT) {
82     warnf(global, "Failed to get filetime: %s\n", strerror(errno));
83   }
84 #endif
85   return result;
86 }
87 
88 #if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || defined(WIN32)
setfiletime(curl_off_t filetime,const char * filename,struct GlobalConfig * global)89 void setfiletime(curl_off_t filetime, const char *filename,
90                  struct GlobalConfig *global)
91 {
92   if(filetime >= 0) {
93 /* Windows utime() may attempt to adjust the unix GMT file time by a daylight
94    saving time offset and since it's GMT that is bad behavior. When we have
95    access to a 64-bit type we can bypass utime and set the times directly. */
96 #if defined(WIN32)
97     HANDLE hfile;
98     TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);
99 
100     /* 910670515199 is the maximum unix filetime that can be used as a
101        Windows FILETIME without overflow: 30827-12-31T23:59:59. */
102     if(filetime > CURL_OFF_T_C(910670515199)) {
103       warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
104             " on outfile: overflow\n", filetime);
105       curlx_unicodefree(tchar_filename);
106       return;
107     }
108 
109     hfile = CreateFile(tchar_filename, FILE_WRITE_ATTRIBUTES,
110                        (FILE_SHARE_READ | FILE_SHARE_WRITE |
111                         FILE_SHARE_DELETE),
112                        NULL, OPEN_EXISTING, 0, NULL);
113     curlx_unicodefree(tchar_filename);
114     if(hfile != INVALID_HANDLE_VALUE) {
115       curl_off_t converted = ((curl_off_t)filetime * 10000000) +
116         CURL_OFF_T_C(116444736000000000);
117       FILETIME ft;
118       ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF);
119       ft.dwHighDateTime = (DWORD)(converted >> 32);
120       if(!SetFileTime(hfile, NULL, &ft, &ft)) {
121         warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
122               " on outfile: SetFileTime failed: GetLastError %u\n",
123               filetime, (unsigned int)GetLastError());
124       }
125       CloseHandle(hfile);
126     }
127     else {
128       warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
129             " on outfile: CreateFile failed: GetLastError %u\n",
130             filetime, (unsigned int)GetLastError());
131     }
132 
133 #elif defined(HAVE_UTIMES)
134     struct timeval times[2];
135     times[0].tv_sec = times[1].tv_sec = (time_t)filetime;
136     times[0].tv_usec = times[1].tv_usec = 0;
137     if(utimes(filename, times)) {
138       warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
139             " on '%s': %s\n", filetime, filename, strerror(errno));
140     }
141 
142 #elif defined(HAVE_UTIME)
143     struct utimbuf times;
144     times.actime = (time_t)filetime;
145     times.modtime = (time_t)filetime;
146     if(utime(filename, &times)) {
147       warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
148             " on '%s': %s\n", filetime, filename, strerror(errno));
149     }
150 #endif
151   }
152 }
153 #endif /* defined(HAVE_UTIME) || defined(HAVE_UTIMES) ||        \
154           defined(WIN32) */
155