BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdls_filesystemutil_windowsimputil.h
Go to the documentation of this file.
1/// @file bdls_filesystemutil_windowsimputil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdls_filesystemutil_windowsimputil.h -*-C++-*-
8#ifndef INCLUDED_BDLS_FILESYSTEMUTIL_WINDOWSIMPUTIL
9#define INCLUDED_BDLS_FILESYSTEMUTIL_WINDOWSIMPUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdls_filesystemutil_windowsimputil bdls_filesystemutil_windowsimputil
15/// @brief Provide testable `bdls::FilesystemUtil` operations on Windows.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdls
19/// @{
20/// @addtogroup bdls_filesystemutil_windowsimputil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdls_filesystemutil_windowsimputil-purpose"> Purpose</a>
25/// * <a href="#bdls_filesystemutil_windowsimputil-classes"> Classes </a>
26/// * <a href="#bdls_filesystemutil_windowsimputil-description"> Description </a>
27///
28/// # Purpose {#bdls_filesystemutil_windowsimputil-purpose}
29/// Provide testable `bdls::FilesystemUtil` operations on Windows.
30///
31/// # Classes {#bdls_filesystemutil_windowsimputil-classes}
32///
33/// - bdls::FilesystemUtil_WindowsImpUtil: testable file-system utilities
34///
35/// @see bdls_filesystemutil
36///
37/// # Description {#bdls_filesystemutil_windowsimputil-description}
38/// This subordinate component to @ref bdls_filesystemutil provides a
39/// utility `struct` template, `bdls::FilesystemUtil_WindowsImpUtil` for
40/// implementing some of `bdls::FilesystemUtil`s functions on Windows
41/// platforms. `bdls::FilesystemUtil_WindowsImpUtil` accesses Windows functions
42/// and types through its template parameter, `WINDOWS_INTERFACE`, in order to
43/// allow tests to supply mock Windows interfaces.
44/// @}
45/** @} */
46/** @} */
47
48/** @addtogroup bdl
49 * @{
50 */
51/** @addtogroup bdls
52 * @{
53 */
54/** @addtogroup bdls_filesystemutil_windowsimputil
55 * @{
56 */
57
58#include <bdlt_datetime.h>
59#include <bdlt_epochutil.h>
60
61#include <bsls_assert.h>
62#include <bsls_types.h>
63
64#include <bslmt_once.h>
65
66
67namespace bdls {
68
69 // ====================================
70 // struct FilesystemUtil_WindowsImpUtil
71 // ====================================
72
73/// This component-private utility `struct` provides a namespace for a suite
74/// of functions that `FilesystemUtil` uses as implementation details.
75/// These functions have a `WINDOWS_INTERFACE` template parameter, which
76/// provides access to the entities that Windows systems declare, and that
77/// the function implementations need.
78///
79/// The program is ill-formed unless the specified `WINDOWS_INTERFACE` is
80/// a class type that meets the following requirements:
81///
82/// * `WINDOWS_INTERFACE::BOOL` is a type alias to the `BOOL`
83/// type provided by the `windows.h` header.
84/// * `WINDOWS_INTERFACE::DWORD` is a type alias to the `DWORD`
85/// type provided by the `windows.h` header.
86/// * `WINDOWS_INTERFACE::FILETIME` is a type alias to the `FILETIME`
87/// type provided by the `windows.h` header.
88/// * `WINDOWS_INTERFACE::HANDLE` is a type alias to the `HANDLE`
89/// type provided by the `windows.h` header.
90/// * `WINDOWS_INTERFACE::INT64` is a type alias to the `IN64` type
91/// provided by the `windows.h` header.
92/// * `WINDOWS_INTERFACE::LPFILETIME` is a type alias to the
93/// `LPFILETIME` type provided by the `windows.h` header.
94/// * `WINDOWS_INTERFACE::SYSTEMTIME` is a type alias to the
95/// `LPFILETIME` type provided by the `windows.h` header.
96/// * `WINDOWS_INTERFACE::ULARGE_INTEGER` is a type alias to the
97/// `ULARGE_INTEGER` type provided by the `windows.h` header.
98/// * `WINDOWS_INTERFACE::ULONG64` is a type alias to the `ULONG64`
99/// type provided by the `windows.h` header.
100/// * `WINDOWS_INTERFACE::ULONGLONG` is a type alias to the `ULONGLONG`
101/// type provided by the `windows.h` header.
102/// * `WINDOWS_INTERFACE::WORD` is a type alias to the `WORD`
103/// type provided by the `windows.h` header.
104/// * `WINDOWS_INTERFACE::FileTimeToSystemTime` is a public, static
105/// member function that has
106/// `BOOL (const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime)` type
107/// and whose contract is to return the result of
108/// `::FileTimeToSystemTime(lpFileTime, lpSystemTime)`, where
109/// `::FileTimeToSystemTime` is the corresponding function declared in
110/// the `windows.h` header.
111/// * `WINDOWS_INTERFACE::GetFileSize` is a public, static member
112/// function that has `DWORD (HANDLE hFile, LPDWORD lpFileSizeHigh)`
113/// type and whose contract is to return the result of
114/// `::GetFileSize(hFile, lpFileSizeHigh)`, where `::GetFileSize` is the
115/// corresponding function declared in the `windows.h` header.
116/// * `WINDOWS_INTERFACE::GetFileTime` is a public, static member
117/// function that has
118/// 'BOOL (HANDLE hFile, LPFILETIME lpCreationTime,
119/// LPFILETIME lpLastAccessTime, LPFILETIME, lpLastWriteTime)' type and
120/// whose contract is to return the result of
121/// '::GetFileTime(hFile, lpCreationTime, lpLastAccessTime,
122/// lpLastWriteTime)`, where `::GetFileTime' is the corresponding
123/// function declared in the `windows.h` header.
124/// * `WINDOWS_INTERFACE::GetLastError` is a public, static
125/// member function that has `DWORD ()` type and whose contract
126/// is to return the result of `::GetLastError()`, where
127/// `::GetLastError` is the corresponding function declared in the
128/// `windows.h` header.
129/// * `WINDOWS_INTERFACE::SystemTimeToFileTime` is a public, static
130/// member function that has
131/// `BOOL (const SYSTEMTIME *lpSystemTime, LPFILEMTIME lpFileTime)` type
132/// and whose contract is to return the result of
133/// `::SystemTimeToFileTime(lpSystemTime, lpFileTime)`, where
134/// `::SystemTimeToFileTime` is the corresponding function declared in
135/// the `windows.h` header.
136///
137/// See @ref bdls_filesystemutil_windowsimputil
138template <class WINDOWS_INTERFACE>
140
141 // TYPES
142
143 /// `FileDescriptor` is an alias for operating system's native file
144 /// descriptor / file handle type.
145 typedef typename WINDOWS_INTERFACE::HANDLE FileDescriptor;
146
147 /// `Offset` is an alias for a signed integral type, and represents the
148 /// offset of a location in a file.
149 typedef typename WINDOWS_INTERFACE::INT64 Offset;
150
151 private:
152 // PRIVATE TYPES
153
154 /// `BOOL` is an alias to the unsigned integral `BOOL` type provided
155 /// by the `windows.h` header.
156 typedef typename WINDOWS_INTERFACE::BOOL BOOL;
157
158 /// `DWORD` is an alias to the unsigned integral `DWORD` type provided
159 /// by the `windows.h` header.
160 typedef typename WINDOWS_INTERFACE::DWORD DWORD;
161
162 /// `FILETIME` is an alias to the `FILETIME` struct provided by the
163 /// `windows.h` header.
164 typedef typename WINDOWS_INTERFACE::FILETIME FILETIME;
165
166 /// `HANDLE` is an alias to the `HANDLE` type provided by the
167 /// `windows.h` header.
168 typedef typename WINDOWS_INTERFACE::HANDLE HANDLE;
169
170 /// `INT64` is an alias to the signed integral `INT64` type provided by
171 /// the `windows.h` header.
172 typedef typename WINDOWS_INTERFACE::INT64 INT64;
173
174 /// `LPDWORD` is an alias to the unsigned integral `LPDWORD` type
175 /// provided by the `windows.h` header.
176 typedef typename WINDOWS_INTERFACE::LPDWORD LPDWORD;
177
178 /// `LPFILETIME` is an alias to the `LPFILETIME` type provided by the
179 /// `windows.h` header.
180 typedef typename WINDOWS_INTERFACE::LPFILETIME LPFILETIME;
181
182 /// `LPSYSTEMTIME` is an alias to the `LPSYSTEMTIME` type provided by
183 /// the `windows.h` header.
184 typedef typename WINDOWS_INTERFACE::LPSYSTEMTIME LPSYSTEMTIME;
185
186 /// `SYSTEMTIME` is an alias to the `SYSTEMTIME` struct provided by the
187 /// `windows.h` header.
188 typedef typename WINDOWS_INTERFACE::SYSTEMTIME SYSTEMTIME;
189
190 /// `ULARGE_INTEGER` is an alias to the unsigned integral
191 /// `ULARGE_INTEGER` type provided by the `windows.h` header.
192 typedef typename WINDOWS_INTERFACE::ULARGE_INTEGER ULARGE_INTEGER;
193
194 /// `ULONG64` is an alias to the unsigned integral `ULONG64` type
195 /// provided by the `windows.h` header.
196 typedef typename WINDOWS_INTERFACE::ULONG64 ULONG64;
197
198 /// `ULONGLONG` is an alias to the unsigned integral `ULONGLONG` type
199 /// provided by the `windows.h` header.
200 typedef typename WINDOWS_INTERFACE::ULONGLONG ULONGLONG;
201
202 /// `WORD` is an alias to the unsigned integral `WORD` type provided by
203 /// the `windows.h` header.
204 typedef typename WINDOWS_INTERFACE::WORD WORD;
205
206 // PRIVATE CLASS METHODS
207
208 /// Invoke and return the result of
209 /// `::FileTimeToSystemTime(lpFileTime, lpSystemTime)` with the
210 /// specified `lpFileTime` and `lpSystemTime`, where
211 /// `::FileTimeToSystemTime` is the function provided by the `windows.h`
212 /// header.
213 static BOOL FileTimeToSystemTime(const FILETIME *lpFileTime,
214 LPSYSTEMTIME lpSystemTime);
215
216 /// Invoke and return the result of
217 /// `::GetFileSize(hFile, lpFileSizeHigh)` with the specified `hFile`
218 /// and `lpFileSizeHigh`, where `::GetFileSize` is the function provided
219 /// by the `windows.h` header.
220 static DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh);
221
222 /// Invoke and return the result of '::GetFileTime(hFile,
223 /// lpCreationTime, lpLastAccessTime, lpLastWriteTime)' with the
224 /// specified `hFile`, `lpCreationTime`, `lpLasAccessTime`, and
225 /// `lpLastWriteTime`, where `::GetFileTime` is the function provided by
226 /// the `windows.h` header.
227 static BOOL GetFileTime(HANDLE hFile,
228 LPFILETIME lpCreationTime,
229 LPFILETIME lpLastAccessTime,
230 LPFILETIME lpLastWriteTime);
231
232 /// Invoke and return the result of `::GetLastError()`, where
233 /// `::GetLastError` is the function provided by the `windows.h` header.
234 static DWORD GetLastError();
235
236 /// Invoke and return the result of
237 /// `::SystemTimeToFileTime(lpSystemTime, lpFileTime)` with the
238 /// specified `lpFileTime` and `lpSystemTime`, where
239 /// `::SystemTimeToFileTime` is the function provided by the `windows.h`
240 /// header.
241 static BOOL SystemTimeToFileTime(const SYSTEMTIME *lpSystemTime,
242 LPFILETIME lpFileTime);
243
244 public:
245 // PUBLIC CLASS DATA
247
251
252 // CLASS METHODS
253
254 /// Load into the specified `time` the time in the specified
255 /// `lpFileTime`. Return 0 on success, and a non-zero value otherwise.
256 ///
257 /// \note Note that the time is reported in UTC.
259 const LPFILETIME lpFileTime);
260
261 /// Return the size, in bytes, of the file with the specified
262 /// `descriptor`, or a negative value if an error occurs.
263 static Offset getFileSize(FileDescriptor descriptor);
264
265 /// Load into the specified `time` the last modification time of the
266 /// file with the specified `descriptor`, as reported by the filesystem. Return 0 on success, and a non-zero value otherwise.
267 ///
268 /// \note Note that the
269 /// time is reported in UTC.
271 FileDescriptor descriptor);
272};
273
274// ============================================================================
275// INLINE DEFINITIONS
276// ============================================================================
277
278 // ------------------------------------
279 // struct FilesystemUtil_WindowsImpUtil
280 // ------------------------------------
281
282// PRIVATE CLASS METHODS
283template <class WINDOWS_INTERFACE>
284typename WINDOWS_INTERFACE::BOOL
286 const FILETIME *lpFileTime,
287 LPSYSTEMTIME lpSystemTime)
288{
289 return WINDOWS_INTERFACE::FileTimeToSystemTime(lpFileTime, lpSystemTime);
290}
291
292template <class WINDOWS_INTERFACE>
293typename WINDOWS_INTERFACE::DWORD
294FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::GetFileSize(
295 HANDLE hFile,
296 LPDWORD lpFileSizeHigh)
297{
298 return WINDOWS_INTERFACE::GetFileSize(hFile, lpFileSizeHigh);
299}
300
301template <class WINDOWS_INTERFACE>
302typename WINDOWS_INTERFACE::BOOL
303FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::GetFileTime(
304 HANDLE hFile,
305 LPFILETIME lpCreationTime,
306 LPFILETIME lpLastAccessTime,
307 LPFILETIME lpLastWriteTime)
308{
309 return WINDOWS_INTERFACE::GetFileTime(
310 hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
311}
312
313template <class WINDOWS_INTERFACE>
314typename WINDOWS_INTERFACE::DWORD
315FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::GetLastError()
316{
317 return WINDOWS_INTERFACE::GetLastError();
318}
319
320template <class WINDOWS_INTERFACE>
321typename WINDOWS_INTERFACE::BOOL
322FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::SystemTimeToFileTime(
323 const SYSTEMTIME *lpSystemTime,
324 LPFILETIME lpFileTime)
325{
326 return WINDOWS_INTERFACE::SystemTimeToFileTime(lpSystemTime, lpFileTime);
327}
328
329// CLASS METHODS
330template <class WINDOWS_INTERFACE>
331int
333 bdlt::Datetime *time,
334 const LPFILETIME lpFileTime)
335{
336 BSLS_ASSERT(time);
337 BSLS_ASSERT(lpFileTime);
338
339 // We avoid unneccesary system calls by storing the offset between the
340 // Windows 'FILETIME' epoch and the unix epoch, in microseconds, as
341 // calculated using Windows system calls. Note that this differs from the
342 // actual number of microseconds between 1601-01-01 and
343 // 1970-01-01 as the Windows system calls do not correctly consider
344 // the conversion, in 1752, from the Julian to the Gregorian calendar,
345 // hence the prefix 'adjusted'.
346 static ULONGLONG adjustedFiletimeEpochToUnixEpochInMicros;
347
349 {
350 const SYSTEMTIME unixEpochSystemTimeUtc =
351 {
352 1970, // year
353 1, // month
354 4, // day of week (4=Thursday)
355 1, // day of month
356 0, // hour
357 0, // minute
358 0, // second
359 0 // microsecond
360 };
361
362 FILETIME unixEpochFileTimeUtc;
363 const BOOL systemTimeToFileTimeStatus = SystemTimeToFileTime(
364 &unixEpochSystemTimeUtc,
365 &unixEpochFileTimeUtc);
366 if (!systemTimeToFileTimeStatus) {
367 return -1; // RETURN
368 }
369
370 // Copy the individual parts per the Microsoft recommendation at
371 // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
372 ULARGE_INTEGER unixEpochFileTimeInTicks;
373 unixEpochFileTimeInTicks.u.HighPart =
374 unixEpochFileTimeUtc.dwHighDateTime;
375 unixEpochFileTimeInTicks.u.LowPart =
376 unixEpochFileTimeUtc.dwLowDateTime;
377
378 adjustedFiletimeEpochToUnixEpochInMicros =
379 unixEpochFileTimeInTicks.QuadPart /
380 k_WINDOWS_TICKS_PER_MICROSECOND;
381 }
382
383 // Copy the individual parts per the Microsoft recommendation.
384 ULARGE_INTEGER lastWriteTimeInTicks;
385 lastWriteTimeInTicks.u.HighPart = lpFileTime->dwHighDateTime;
386 lastWriteTimeInTicks.u.LowPart = lpFileTime->dwLowDateTime;
387
388 ULONGLONG lastWriteTimeInMicroseconds = lastWriteTimeInTicks.QuadPart /
389 k_WINDOWS_TICKS_PER_MICROSECOND;
390
391 if (lastWriteTimeInMicroseconds <
392 adjustedFiletimeEpochToUnixEpochInMicros) {
393 // Timestamps prior to the unix epoch are not currently supported.
394 return -1; // RETURN
395 }
396
398
399 int rc = result.addMicrosecondsIfValid(lastWriteTimeInMicroseconds -
400 adjustedFiletimeEpochToUnixEpochInMicros);
401
402 if (0 != rc) {
403 return -1; // RETURN
404 }
405
406 *time = result;
407 return 0;
408}
409
410template <class WINDOWS_INTERFACE>
413 FileDescriptor descriptor)
414{
416 BSLS_ASSERT(0 == bsl::numeric_limits<DWORD>::min());
417 BSLS_ASSERT(0xFFFFFFFFul == bsl::numeric_limits<DWORD>::max());
418
420 BSLS_ASSERT(0 == bsl::numeric_limits<ULONG64>::min());
421 BSLS_ASSERT(0xFFFFFFFFFFFFFFFFull == bsl::numeric_limits<ULONG64>::max());
422
423 // The Windows implementation of this function uses 'GetFileSize' on
424 // purpose, even though the Win32 API documentation instructs the reader to
425 // use 'GetFileSizeEx' instead. 'GetFileSizeEx' returns a 'LARGE_INTEGER',
426 // which is a union of two or more layout-incompatible, 64-bit integer
427 // representations, and there is no way to know which member is active.
428 // This forces the programmer to do "union type punning," which is jargon
429 // for invoking undefined behavior by accessing an inactive union member
430 // that is not layout-compatible with the active member.
431 //
432 // 'GetFileSize' has an awkward interface, but it requires no type punning
433 // and isn't deprecated.
434
435 DWORD sizeHigh32Bits;
436 const DWORD sizeLow32Bits = GetFileSize(descriptor, &sizeHigh32Bits);
437 // 'GetFileSize' returns the maximum unsigned, 32-bit integer to indicate
438 // that it could not get the file size. However, this is also a legal
439 // value for the file size's low 32-bits. To remove the ambiguity,
440 // this function calls 'GetLastError', which returns non-zero to indicate
441 // the last system call had an error, and 0 otherwise.
442
443 static const DWORD k_INVALID_FILE_SIZE = 0xFFFFFFFFul;
444 if (k_INVALID_FILE_SIZE == sizeLow32Bits) {
445 const DWORD lastError = GetLastError();
446
447 static const DWORD k_NO_ERROR = 0;
448 if (k_NO_ERROR != lastError) {
449 return -1; // RETURN
450 }
451 }
452
453 const ULONG64 uSizeHigh32Bits = static_cast<ULONG64>(sizeHigh32Bits);
454 const ULONG64 uSizeLow32Bits = static_cast<ULONG64>(sizeLow32Bits);
455 const ULONG64 uSize64Bits = (uSizeHigh32Bits << 32) | uSizeLow32Bits;
456
457 return static_cast<Offset>(uSize64Bits);
458}
459
460template <class WINDOWS_INTERFACE>
462 bdlt::Datetime *time,
463 FileDescriptor descriptor)
464{
465 static const LPFILETIME s_IGNORED_CREATION_TIME = 0;
466 static const LPFILETIME s_IGNORED_LAST_ACCESS_TIME = 0;
467
468 FILETIME lastWriteTime;
469 const BOOL getFileTimeSuccessFlag = GetFileTime(descriptor,
470 s_IGNORED_CREATION_TIME,
471 s_IGNORED_LAST_ACCESS_TIME,
472 &lastWriteTime);
473 if (!getFileTimeSuccessFlag) {
474 return -1; // RETURN
475 }
476
477 return convertFileTimeToDatetime(time, &lastWriteTime);
478}
479
480} // close package namespace
481
482
483#endif
484
485// ----------------------------------------------------------------------------
486// Copyright 2020 Bloomberg Finance L.P.
487//
488// Licensed under the Apache License, Version 2.0 (the "License");
489// you may not use this file except in compliance with the License.
490// You may obtain a copy of the License at
491//
492// http://www.apache.org/licenses/LICENSE-2.0
493//
494// Unless required by applicable law or agreed to in writing, software
495// distributed under the License is distributed on an "AS IS" BASIS,
496// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
497// See the License for the specific language governing permissions and
498// limitations under the License.
499// ----------------------------- END-OF-FILE ----------------------------------
500
501/** @} */
502/** @} */
503/** @} */
Definition bdlt_datetime.h:330
int addMicrosecondsIfValid(bsls::Types::Int64 microseconds)
Definition bdlt_datetime.h:2173
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLMT_ONCE_DO
Definition bslmt_once.h:427
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdls_fdstreambuf.h:412
Definition bdls_filesystemutil_windowsimputil.h:139
static int getLastModificationTime(bdlt::Datetime *time, FileDescriptor descriptor)
Definition bdls_filesystemutil_windowsimputil.h:461
static const bsls::Types::Int64 k_WINDOWS_TICKS_PER_MICROSECOND
Definition bdls_filesystemutil_windowsimputil.h:248
static const bsls::Types::Int64 k_NANOSECONDS_PER_WINDOWS_TICK
Definition bdls_filesystemutil_windowsimputil.h:246
WINDOWS_INTERFACE::HANDLE FileDescriptor
Definition bdls_filesystemutil_windowsimputil.h:145
WINDOWS_INTERFACE::INT64 Offset
Definition bdls_filesystemutil_windowsimputil.h:149
static Offset getFileSize(FileDescriptor descriptor)
Definition bdls_filesystemutil_windowsimputil.h:412
static int convertFileTimeToDatetime(bdlt::Datetime *time, const LPFILETIME lpFileTime)
Definition bdls_filesystemutil_windowsimputil.h:332
static const Datetime & epoch()
Definition bdlt_epochutil.h:397
static const bsls::Types::Int64 k_NANOSECONDS_PER_MICROSECOND
Definition bdlt_timeunitratio.h:207
Definition bslmf_isintegral.h:140
long long Int64
Definition bsls_types.h:134