xref: /reactos/sdk/lib/ucrt/time/utime.cpp (revision 04e0dc4a)
1 //
2 // utime.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // The utime and futime families of functions, which set the modification time
7 // for a file.
8 //
9 #include <corecrt_internal_lowio.h>
10 #include <corecrt_internal_time.h>
11 
12 
13 
14 // Sets the modification time for a file, where 'file_name' is the name of the
15 // file.  Returns zero on success; returns -1 and sets errno on failure.
16 template <typename TimeType, typename Character, typename TimeBufferType>
common_utime(Character const * const file_name,TimeBufferType * const times)17 static int __cdecl common_utime(
18     Character const* const file_name,
19     TimeBufferType*  const times
20     ) throw()
21 {
22     typedef __crt_time_traits<TimeType, Character> time_traits;
23 
24     _VALIDATE_RETURN(file_name != nullptr, EINVAL, -1)
25 
26     // Open the file, since the underlying system call needs a handle.  Note
27     // that the _utime definition says you must have write permission for the
28     // file to change its time, so we open the file for write only.  Also, we
29     // must force it to open in binary mode so that we don't remove ^Z's from
30     // binary files.
31     int fh;
32     if (time_traits::tsopen_s(&fh, file_name, _O_RDWR | _O_BINARY, _SH_DENYNO, 0) != 0)
33         return -1;
34 
35     int const result = time_traits::futime(fh, times);
36 
37     errno_t stored_errno = 0;
38     if (result == -1)
39         stored_errno = errno;
40 
41     _close(fh);
42 
43     if (result == -1)
44         errno = stored_errno;
45 
46     return result;
47 }
48 
_utime32(char const * const file_name,__utimbuf32 * const times)49 extern "C" int __cdecl _utime32(char const* const file_name, __utimbuf32* const times)
50 {
51     return common_utime<__time32_t>(file_name, times);
52 }
53 
_wutime32(wchar_t const * const file_name,__utimbuf32 * const times)54 extern "C" int __cdecl _wutime32(wchar_t const* const file_name, __utimbuf32* const times)
55 {
56     return common_utime<__time32_t>(file_name, times);
57 }
58 
_utime64(char const * const file_name,__utimbuf64 * const times)59 extern "C" int __cdecl _utime64(char const* const file_name, __utimbuf64* const times)
60 {
61     return common_utime<__time64_t>(file_name, times);
62 }
63 
_wutime64(wchar_t const * const file_name,__utimbuf64 * const times)64 extern "C" int __cdecl _wutime64(wchar_t const* const file_name, __utimbuf64* const times)
65 {
66     return common_utime<__time64_t>(file_name, times);
67 }
68 
69 
70 
71 // Sets the modification time for an open file, where the 'fh' is the lowio file
72 // handle of the open file.  Returns zero on success; returns -1 and sets errno
73 // on failure.
74 template <typename TimeType, typename TimeBufferType>
common_futime(int const fh,TimeBufferType * times)75 static int __cdecl common_futime(int const fh, TimeBufferType* times) throw()
76 {
77     typedef __crt_time_time_t_traits<TimeType> time_traits;
78 
79     _CHECK_FH_RETURN(fh, EBADF, -1);
80 
81     _VALIDATE_RETURN(fh >= 0 && static_cast<unsigned>(fh) < static_cast<unsigned>(_nhandle), EBADF, -1);
82     _VALIDATE_RETURN(_osfile(fh) & FOPEN, EBADF, -1);
83 
84     TimeBufferType default_times;
85 
86     if (times == nullptr)
87     {
88         time_traits::time(&default_times.modtime);
89         default_times.actime = default_times.modtime;
90         times = &default_times;
91     }
92 
93     tm tm_value;
94     if (time_traits::localtime_s(&tm_value, &times->modtime) != 0)
95     {
96         errno = EINVAL;
97         return -1;
98     }
99 
100     SYSTEMTIME local_time;
101     local_time.wYear   = static_cast<WORD>(tm_value.tm_year + 1900);
102     local_time.wMonth  = static_cast<WORD>(tm_value.tm_mon + 1);
103     local_time.wDay    = static_cast<WORD>(tm_value.tm_mday);
104     local_time.wHour   = static_cast<WORD>(tm_value.tm_hour);
105     local_time.wMinute = static_cast<WORD>(tm_value.tm_min);
106     local_time.wSecond = static_cast<WORD>(tm_value.tm_sec);
107     local_time.wMilliseconds = 0;
108 
109     SYSTEMTIME system_time;
110     FILETIME last_write_time;
111     if (!TzSpecificLocalTimeToSystemTime(nullptr, &local_time, &system_time) ||
112         !SystemTimeToFileTime(&system_time, &last_write_time))
113     {
114         errno = EINVAL;
115         return -1;
116     }
117 
118     if (time_traits::localtime_s(&tm_value, &times->actime) != 0)
119     {
120         errno = EINVAL;
121         return -1;
122     }
123 
124     local_time.wYear   = static_cast<WORD>(tm_value.tm_year + 1900);
125     local_time.wMonth  = static_cast<WORD>(tm_value.tm_mon + 1);
126     local_time.wDay    = static_cast<WORD>(tm_value.tm_mday);
127     local_time.wHour   = static_cast<WORD>(tm_value.tm_hour);
128     local_time.wMinute = static_cast<WORD>(tm_value.tm_min);
129     local_time.wSecond = static_cast<WORD>(tm_value.tm_sec);
130     local_time.wMilliseconds = 0;
131 
132     FILETIME last_access_time;
133     if (!TzSpecificLocalTimeToSystemTime(nullptr, &local_time, &system_time) ||
134         !SystemTimeToFileTime(&system_time, &last_access_time))
135     {
136         errno = EINVAL;
137         return -1;
138     }
139 
140     if (!SetFileTime(reinterpret_cast<HANDLE>(_get_osfhandle(fh)), nullptr, &last_access_time, &last_write_time))
141     {
142         errno = EINVAL;
143         return -1;
144     }
145 
146     return 0;
147 }
148 
_futime32(int const fh,__utimbuf32 * const times)149 extern "C" int __cdecl _futime32(int const fh, __utimbuf32* const times)
150 {
151     return common_futime<__time32_t>(fh, times);
152 }
153 
_futime64(int const fh,__utimbuf64 * const times)154 extern "C" int __cdecl _futime64(int const fh, __utimbuf64* const times)
155 {
156     return common_futime<__time64_t>(fh, times);
157 }
158