BDE 4.14.0 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.
136template <class WINDOWS_INTERFACE>
138
139 // TYPES
140
141 /// `FileDescriptor` is an alias for operating system's native file
142 /// descriptor / file handle type.
143 typedef typename WINDOWS_INTERFACE::HANDLE FileDescriptor;
144
145 /// `Offset` is an alias for a signed integral type, and represents the
146 /// offset of a location in a file.
147 typedef typename WINDOWS_INTERFACE::INT64 Offset;
148
149 private:
150 // PRIVATE TYPES
151
152 /// `BOOL` is an alias to the unsigned integral `BOOL` type provided
153 /// by the `windows.h` header.
154 typedef typename WINDOWS_INTERFACE::BOOL BOOL;
155
156 /// `DWORD` is an alias to the unsigned integral `DWORD` type provided
157 /// by the `windows.h` header.
158 typedef typename WINDOWS_INTERFACE::DWORD DWORD;
159
160 /// `FILETIME` is an alias to the `FILETIME` struct provided by the
161 /// `windows.h` header.
162 typedef typename WINDOWS_INTERFACE::FILETIME FILETIME;
163
164 /// `HANDLE` is an alias to the `HANDLE` type provided by the
165 /// `windows.h` header.
166 typedef typename WINDOWS_INTERFACE::HANDLE HANDLE;
167
168 /// `INT64` is an alias to the signed integral `INT64` type provided by
169 /// the `windows.h` header.
170 typedef typename WINDOWS_INTERFACE::INT64 INT64;
171
172 /// `LPDWORD` is an alias to the unsigned integral `LPDWORD` type
173 /// provided by the `windows.h` header.
174 typedef typename WINDOWS_INTERFACE::LPDWORD LPDWORD;
175
176 /// `LPFILETIME` is an alias to the `LPFILETIME` type provided by the
177 /// `windows.h` header.
178 typedef typename WINDOWS_INTERFACE::LPFILETIME LPFILETIME;
179
180 /// `LPSYSTEMTIME` is an alias to the `LPSYSTEMTIME` type provided by
181 /// the `windows.h` header.
182 typedef typename WINDOWS_INTERFACE::LPSYSTEMTIME LPSYSTEMTIME;
183
184 /// `SYSTEMTIME` is an alias to the `SYSTEMTIME` struct provided by the
185 /// `windows.h` header.
186 typedef typename WINDOWS_INTERFACE::SYSTEMTIME SYSTEMTIME;
187
188 /// `ULARGE_INTEGER` is an alias to the unsigned integral
189 /// `ULARGE_INTEGER` type provided by the `windows.h` header.
190 typedef typename WINDOWS_INTERFACE::ULARGE_INTEGER ULARGE_INTEGER;
191
192 /// `ULONG64` is an alias to the unsigned integral `ULONG64` type
193 /// provided by the `windows.h` header.
194 typedef typename WINDOWS_INTERFACE::ULONG64 ULONG64;
195
196 /// `ULONGLONG` is an alias to the unsigned integral `ULONGLONG` type
197 /// provided by the `windows.h` header.
198 typedef typename WINDOWS_INTERFACE::ULONGLONG ULONGLONG;
199
200 /// `WORD` is an alias to the unsigned integral `WORD` type provided by
201 /// the `windows.h` header.
202 typedef typename WINDOWS_INTERFACE::WORD WORD;
203
204 // PRIVATE CLASS METHODS
205
206 /// Invoke and return the result of
207 /// `::FileTimeToSystemTime(lpFileTime, lpSystemTime)` with the
208 /// specified `lpFileTime` and `lpSystemTime`, where
209 /// `::FileTimeToSystemTime` is the function provided by the `windows.h`
210 /// header.
211 static BOOL FileTimeToSystemTime(const FILETIME *lpFileTime,
212 LPSYSTEMTIME lpSystemTime);
213
214 /// Invoke and return the result of
215 /// `::GetFileSize(hFile, lpFileSizeHigh)` with the specified `hFile`
216 /// and `lpFileSizeHigh`, where `::GetFileSize` is the function provided
217 /// by the `windows.h` header.
218 static DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh);
219
220 /// Invoke and return the result of '::GetFileTime(hFile,
221 /// lpCreationTime, lpLastAccessTime, lpLastWriteTime)' with the
222 /// specified `hFile`, `lpCreationTime`, `lpLasAccessTime`, and
223 /// `lpLastWriteTime`, where `::GetFileTime` is the function provided by
224 /// the `windows.h` header.
225 static BOOL GetFileTime(HANDLE hFile,
226 LPFILETIME lpCreationTime,
227 LPFILETIME lpLastAccessTime,
228 LPFILETIME lpLastWriteTime);
229
230 /// Invoke and return the result of `::GetLastError()`, where
231 /// `::GetLastError` is the function provided by the `windows.h` header.
232 static DWORD GetLastError();
233
234 /// Invoke and return the result of
235 /// `::SystemTimeToFileTime(lpSystemTime, lpFileTime)` with the
236 /// specified `lpFileTime` and `lpSystemTime`, where
237 /// `::SystemTimeToFileTime` is the function provided by the `windows.h`
238 /// header.
239 static BOOL SystemTimeToFileTime(const SYSTEMTIME *lpSystemTime,
240 LPFILETIME lpFileTime);
241
242 public:
243 // PUBLIC CLASS DATA
245
249
250 // CLASS METHODS
251
252 /// Load into the specified `time` the time in the specified
253 /// `lpFileTime`. Return 0 on success, and a non-zero value otherwise.
254 /// Note that the time is reported in UTC.
256 const LPFILETIME lpFileTime);
257
258 /// Return the size, in bytes, of the file with the specified
259 /// `descriptor`, or a negative value if an error occurs.
260 static Offset getFileSize(FileDescriptor descriptor);
261
262 /// Load into the specified `time` the last modification time of the
263 /// file with the specified `descriptor`, as reported by the filesystem.
264 /// Return 0 on success, and a non-zero value otherwise. Note that the
265 /// time is reported in UTC.
267 FileDescriptor descriptor);
268};
269
270// ============================================================================
271// INLINE DEFINITIONS
272// ============================================================================
273
274 // ------------------------------------
275 // struct FilesystemUtil_WindowsImpUtil
276 // ------------------------------------
277
278// PRIVATE CLASS METHODS
279template <class WINDOWS_INTERFACE>
280typename WINDOWS_INTERFACE::BOOL
282 const FILETIME *lpFileTime,
283 LPSYSTEMTIME lpSystemTime)
284{
285 return WINDOWS_INTERFACE::FileTimeToSystemTime(lpFileTime, lpSystemTime);
286}
287
288template <class WINDOWS_INTERFACE>
289typename WINDOWS_INTERFACE::DWORD
290FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::GetFileSize(
291 HANDLE hFile,
292 LPDWORD lpFileSizeHigh)
293{
294 return WINDOWS_INTERFACE::GetFileSize(hFile, lpFileSizeHigh);
295}
296
297template <class WINDOWS_INTERFACE>
298typename WINDOWS_INTERFACE::BOOL
299FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::GetFileTime(
300 HANDLE hFile,
301 LPFILETIME lpCreationTime,
302 LPFILETIME lpLastAccessTime,
303 LPFILETIME lpLastWriteTime)
304{
305 return WINDOWS_INTERFACE::GetFileTime(
306 hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
307}
308
309template <class WINDOWS_INTERFACE>
310typename WINDOWS_INTERFACE::DWORD
311FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::GetLastError()
312{
313 return WINDOWS_INTERFACE::GetLastError();
314}
315
316template <class WINDOWS_INTERFACE>
317typename WINDOWS_INTERFACE::BOOL
318FilesystemUtil_WindowsImpUtil<WINDOWS_INTERFACE>::SystemTimeToFileTime(
319 const SYSTEMTIME *lpSystemTime,
320 LPFILETIME lpFileTime)
321{
322 return WINDOWS_INTERFACE::SystemTimeToFileTime(lpSystemTime, lpFileTime);
323}
324
325// CLASS METHODS
326template <class WINDOWS_INTERFACE>
327int
329 bdlt::Datetime *time,
330 const LPFILETIME lpFileTime)
331{
332 BSLS_ASSERT(time);
333 BSLS_ASSERT(lpFileTime);
334
335 // We avoid unneccesary system calls by storing the offset between the
336 // Windows 'FILETIME' epoch and the unix epoch, in microseconds, as
337 // calculated using Windows system calls. Note that this differs from the
338 // actual number of microseconds between 1601-01-01 and
339 // 1970-01-01 as the Windows system calls do not correctly consider
340 // the conversion, in 1752, from the Julian to the Gregorian calendar,
341 // hence the prefix 'adjusted'.
342 static ULONGLONG adjustedFiletimeEpochToUnixEpochInMicros;
343
345 {
346 const SYSTEMTIME unixEpochSystemTimeUtc =
347 {
348 1970, // year
349 1, // month
350 4, // day of week (4=Thursday)
351 1, // day of month
352 0, // hour
353 0, // minute
354 0, // second
355 0 // microsecond
356 };
357
358 FILETIME unixEpochFileTimeUtc;
359 const BOOL systemTimeToFileTimeStatus = SystemTimeToFileTime(
360 &unixEpochSystemTimeUtc,
361 &unixEpochFileTimeUtc);
362 if (!systemTimeToFileTimeStatus) {
363 return -1; // RETURN
364 }
365
366 // Copy the individual parts per the Microsoft recommendation at
367 // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
368 ULARGE_INTEGER unixEpochFileTimeInTicks;
369 unixEpochFileTimeInTicks.u.HighPart =
370 unixEpochFileTimeUtc.dwHighDateTime;
371 unixEpochFileTimeInTicks.u.LowPart =
372 unixEpochFileTimeUtc.dwLowDateTime;
373
374 adjustedFiletimeEpochToUnixEpochInMicros =
375 unixEpochFileTimeInTicks.QuadPart /
376 k_WINDOWS_TICKS_PER_MICROSECOND;
377 }
378
379 // Copy the individual parts per the Microsoft recommendation.
380 ULARGE_INTEGER lastWriteTimeInTicks;
381 lastWriteTimeInTicks.u.HighPart = lpFileTime->dwHighDateTime;
382 lastWriteTimeInTicks.u.LowPart = lpFileTime->dwLowDateTime;
383
384 ULONGLONG lastWriteTimeInMicroseconds = lastWriteTimeInTicks.QuadPart /
385 k_WINDOWS_TICKS_PER_MICROSECOND;
386
387 if (lastWriteTimeInMicroseconds <
388 adjustedFiletimeEpochToUnixEpochInMicros) {
389 // Timestamps prior to the unix epoch are not currently supported.
390 return -1; // RETURN
391 }
392
394
395 int rc = result.addMicrosecondsIfValid(lastWriteTimeInMicroseconds -
396 adjustedFiletimeEpochToUnixEpochInMicros);
397
398 if (0 != rc) {
399 return -1; // RETURN
400 }
401
402 *time = result;
403 return 0;
404}
405
406template <class WINDOWS_INTERFACE>
409 FileDescriptor descriptor)
410{
412 BSLS_ASSERT(0 == bsl::numeric_limits<DWORD>::min());
413 BSLS_ASSERT(0xFFFFFFFFul == bsl::numeric_limits<DWORD>::max());
414
416 BSLS_ASSERT(0 == bsl::numeric_limits<ULONG64>::min());
417 BSLS_ASSERT(0xFFFFFFFFFFFFFFFFull == bsl::numeric_limits<ULONG64>::max());
418
419 // The Windows implementation of this function uses 'GetFileSize' on
420 // purpose, even though the Win32 API documentation instructs the reader to
421 // use 'GetFileSizeEx' instead. 'GetFileSizeEx' returns a 'LARGE_INTEGER',
422 // which is a union of two or more layout-incompatible, 64-bit integer
423 // representations, and there is no way to know which member is active.
424 // This forces the programmer to do "union type punning," which is jargon
425 // for invoking undefined behavior by accessing an inactive union member
426 // that is not layout-compatible with the active member.
427 //
428 // 'GetFileSize' has an awkward interface, but it requires no type punning
429 // and isn't deprecated.
430
431 DWORD sizeHigh32Bits;
432 const DWORD sizeLow32Bits = GetFileSize(descriptor, &sizeHigh32Bits);
433 // 'GetFileSize' returns the maximum unsigned, 32-bit integer to indicate
434 // that it could not get the file size. However, this is also a legal
435 // value for the file size's low 32-bits. To remove the ambiguity,
436 // this function calls 'GetLastError', which returns non-zero to indicate
437 // the last system call had an error, and 0 otherwise.
438
439 static const DWORD k_INVALID_FILE_SIZE = 0xFFFFFFFFul;
440 if (k_INVALID_FILE_SIZE == sizeLow32Bits) {
441 const DWORD lastError = GetLastError();
442
443 static const DWORD k_NO_ERROR = 0;
444 if (k_NO_ERROR != lastError) {
445 return -1; // RETURN
446 }
447 }
448
449 const ULONG64 uSizeHigh32Bits = static_cast<ULONG64>(sizeHigh32Bits);
450 const ULONG64 uSizeLow32Bits = static_cast<ULONG64>(sizeLow32Bits);
451 const ULONG64 uSize64Bits = (uSizeHigh32Bits << 32) | uSizeLow32Bits;
452
453 return static_cast<Offset>(uSize64Bits);
454}
455
456template <class WINDOWS_INTERFACE>
458 bdlt::Datetime *time,
459 FileDescriptor descriptor)
460{
461 static const LPFILETIME s_IGNORED_CREATION_TIME = 0;
462 static const LPFILETIME s_IGNORED_LAST_ACCESS_TIME = 0;
463
464 FILETIME lastWriteTime;
465 const BOOL getFileTimeSuccessFlag = GetFileTime(descriptor,
466 s_IGNORED_CREATION_TIME,
467 s_IGNORED_LAST_ACCESS_TIME,
468 &lastWriteTime);
469 if (!getFileTimeSuccessFlag) {
470 return -1; // RETURN
471 }
472
473 return convertFileTimeToDatetime(time, &lastWriteTime);
474}
475
476} // close package namespace
477
478
479#endif
480
481// ----------------------------------------------------------------------------
482// Copyright 2020 Bloomberg Finance L.P.
483//
484// Licensed under the Apache License, Version 2.0 (the "License");
485// you may not use this file except in compliance with the License.
486// You may obtain a copy of the License at
487//
488// http://www.apache.org/licenses/LICENSE-2.0
489//
490// Unless required by applicable law or agreed to in writing, software
491// distributed under the License is distributed on an "AS IS" BASIS,
492// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
493// See the License for the specific language governing permissions and
494// limitations under the License.
495// ----------------------------- END-OF-FILE ----------------------------------
496
497/** @} */
498/** @} */
499/** @} */
Definition bdlt_datetime.h:331
int addMicrosecondsIfValid(bsls::Types::Int64 microseconds)
Definition bdlt_datetime.h:2103
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLMT_ONCE_DO
Definition bslmt_once.h:425
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdls_fdstreambuf.h:412
Definition bdls_filesystemutil_windowsimputil.h:137
static int getLastModificationTime(bdlt::Datetime *time, FileDescriptor descriptor)
Definition bdls_filesystemutil_windowsimputil.h:457
static const bsls::Types::Int64 k_WINDOWS_TICKS_PER_MICROSECOND
Definition bdls_filesystemutil_windowsimputil.h:246
static const bsls::Types::Int64 k_NANOSECONDS_PER_WINDOWS_TICK
Definition bdls_filesystemutil_windowsimputil.h:244
WINDOWS_INTERFACE::HANDLE FileDescriptor
Definition bdls_filesystemutil_windowsimputil.h:143
WINDOWS_INTERFACE::INT64 Offset
Definition bdls_filesystemutil_windowsimputil.h:147
static Offset getFileSize(FileDescriptor descriptor)
Definition bdls_filesystemutil_windowsimputil.h:408
static int convertFileTimeToDatetime(bdlt::Datetime *time, const LPFILETIME lpFileTime)
Definition bdls_filesystemutil_windowsimputil.h:328
static const Datetime & epoch()
Definition bdlt_epochutil.h:375
static const bsls::Types::Int64 k_NANOSECONDS_PER_MICROSECOND
Definition bdlt_timeunitratio.h:205
Definition bslmf_isintegral.h:130
long long Int64
Definition bsls_types.h:132