/src/CMake/Source/cmFileTimes.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmFileTimes.h" |
4 | | |
5 | | #include <utility> |
6 | | |
7 | | #include <cm/memory> |
8 | | |
9 | | #include "cmsys/Status.hxx" |
10 | | |
11 | | #include "cm_sys_stat.h" |
12 | | |
13 | | #if defined(_WIN32) |
14 | | # include <windows.h> |
15 | | |
16 | | # include "cmSystemTools.h" |
17 | | #else |
18 | | # include <cerrno> |
19 | | |
20 | | # include <utime.h> |
21 | | #endif |
22 | | |
23 | | #if defined(_WIN32) && \ |
24 | | (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__)) |
25 | | # include <io.h> |
26 | | #endif |
27 | | |
28 | | #ifdef _WIN32 |
29 | | class cmFileTimes::WindowsHandle |
30 | | { |
31 | | public: |
32 | | WindowsHandle(HANDLE h) |
33 | | : handle_(h) |
34 | | { |
35 | | } |
36 | | ~WindowsHandle() |
37 | | { |
38 | | if (this->handle_ != INVALID_HANDLE_VALUE) { |
39 | | CloseHandle(this->handle_); |
40 | | } |
41 | | } |
42 | | explicit operator bool() const |
43 | | { |
44 | | return this->handle_ != INVALID_HANDLE_VALUE; |
45 | | } |
46 | | bool operator!() const { return this->handle_ == INVALID_HANDLE_VALUE; } |
47 | | operator HANDLE() const { return this->handle_; } |
48 | | |
49 | | private: |
50 | | HANDLE handle_; |
51 | | }; |
52 | | #endif |
53 | | |
54 | | class cmFileTimes::Times |
55 | | { |
56 | | public: |
57 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
58 | | FILETIME timeCreation; |
59 | | FILETIME timeLastAccess; |
60 | | FILETIME timeLastWrite; |
61 | | #else |
62 | | struct utimbuf timeBuf; |
63 | | #endif |
64 | | }; |
65 | | |
66 | 0 | cmFileTimes::cmFileTimes() = default; |
67 | | cmFileTimes::cmFileTimes(std::string const& fileName) |
68 | 0 | { |
69 | 0 | this->Load(fileName); |
70 | 0 | } |
71 | 0 | cmFileTimes::~cmFileTimes() = default; |
72 | | |
73 | | cmsys::Status cmFileTimes::Load(std::string const& fileName) |
74 | 0 | { |
75 | 0 | std::unique_ptr<Times> ptr; |
76 | 0 | if (this->IsValid()) { |
77 | | // Invalidate this and reuse times |
78 | 0 | ptr.swap(this->times); |
79 | 0 | } else { |
80 | 0 | ptr = cm::make_unique<Times>(); |
81 | 0 | } |
82 | |
|
83 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
84 | | cmFileTimes::WindowsHandle handle = |
85 | | CreateFileW(cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(), |
86 | | GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, |
87 | | FILE_FLAG_BACKUP_SEMANTICS, 0); |
88 | | if (!handle) { |
89 | | return cmsys::Status::Windows_GetLastError(); |
90 | | } |
91 | | if (!GetFileTime(handle, &ptr->timeCreation, &ptr->timeLastAccess, |
92 | | &ptr->timeLastWrite)) { |
93 | | return cmsys::Status::Windows_GetLastError(); |
94 | | } |
95 | | #else |
96 | 0 | struct stat st; |
97 | 0 | if (stat(fileName.c_str(), &st) < 0) { |
98 | 0 | return cmsys::Status::POSIX_errno(); |
99 | 0 | } |
100 | 0 | ptr->timeBuf.actime = st.st_atime; |
101 | 0 | ptr->timeBuf.modtime = st.st_mtime; |
102 | 0 | #endif |
103 | | // Accept times |
104 | 0 | this->times = std::move(ptr); |
105 | 0 | return cmsys::Status::Success(); |
106 | 0 | } |
107 | | |
108 | | cmsys::Status cmFileTimes::Store(std::string const& fileName) const |
109 | 0 | { |
110 | 0 | if (!this->IsValid()) { |
111 | 0 | return cmsys::Status::POSIX(EINVAL); |
112 | 0 | } |
113 | | |
114 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
115 | | cmFileTimes::WindowsHandle handle = CreateFileW( |
116 | | cmSystemTools::ConvertToWindowsExtendedPath(fileName).c_str(), |
117 | | FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); |
118 | | if (!handle) { |
119 | | return cmsys::Status::Windows_GetLastError(); |
120 | | } |
121 | | if (SetFileTime(handle, &this->times->timeCreation, |
122 | | &this->times->timeLastAccess, |
123 | | &this->times->timeLastWrite) == 0) { |
124 | | return cmsys::Status::Windows_GetLastError(); |
125 | | } |
126 | | #else |
127 | 0 | if (utime(fileName.c_str(), &this->times->timeBuf) < 0) { |
128 | 0 | return cmsys::Status::POSIX_errno(); |
129 | 0 | } |
130 | 0 | #endif |
131 | 0 | return cmsys::Status::Success(); |
132 | 0 | } |
133 | | |
134 | | cmsys::Status cmFileTimes::Copy(std::string const& fromFile, |
135 | | std::string const& toFile) |
136 | 0 | { |
137 | 0 | cmFileTimes fileTimes; |
138 | 0 | cmsys::Status load_status = fileTimes.Load(fromFile); |
139 | 0 | if (!load_status) { |
140 | 0 | return load_status; |
141 | 0 | } |
142 | 0 | return fileTimes.Store(toFile); |
143 | 0 | } |