// bdls_filesystemutil_uniximputil.h -*-C++-*- #ifndef INCLUDED_BDLS_FILESYSTEMUTIL_UNIXIMPUTIL #define INCLUDED_BDLS_FILESYSTEMUTIL_UNIXIMPUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide testable 'bdls::FilesystemUtil' operations for some Unixes. // //@CLASSES: // bdls::FilesystemUtil_UnixImpUtil: testable file-system utilities // //@SEE_ALSO: bdls_filesystemutil, bdls_filesystemutil_unixplatform // //@DESCRIPTION: This subordinate component to 'bdls_filesystemutil' provides a // utility 'struct' template, 'bdls::FilesystemUtil_UnixImpUtil' for // implementing some of 'bdls::FilesystemUtil's functions on Unix platforms. // 'bdls::FilesystemUtil_UnixImpUtil' accesses Unix functions and types through // its template parameter, 'UNIX_INTERFACE', in order to allow tests to supply // mock Unix interfaces. #include <bdlt_datetime.h> #include <bdlt_epochutil.h> #include <bdlt_timeunitratio.h> #include <bsls_assert.h> namespace BloombergLP { namespace bdls { // ================================= // struct FilesystemUtil_UnixImpUtil // ================================= template <class UNIX_INTERFACE> struct FilesystemUtil_UnixImpUtil { // This component-private utility 'struct' provides a namespace for a suite // of functions that 'FilesystemUtil' uses as implementation details. // These functions have a 'UNIX_INTERFACE' template parameter, which // provides access to the entities that large-file environment Unix // systems declare, and that the function implementations need. // // Note that, on some Unix platforms and some build configurations, the // 'stat' struct does not have an 'st_mtime' field, and 'st_mtime' is a // macro that emulates the access of the field. Similarly, on some Unix // platforms and some build configurations, the 'stat' structure does not // have an 'st_mtim' field or the 'st_mtim' struct does not have a // 'tv_nsec' (or, for some versions of Solaris, '__tv_nsec') field, in // which case the 'get_st_mtim_nsec' function returns zero. For more // information, please see the specification of the 'sys/stat.h' header // from IEEE Std // 1003.1-2017, which provides information about the evolution of the // 'stat' struct in the POSIX specification // (https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/). // // The program is ill-formed unless the specified 'UNIX_INTERFACE' is a // class type that meets the following requirements: // //: o 'UNIX_INTERFACE::off_t' is a type alias to the 'off_t' type provided //: by the 'sys/types.h' header. //: //: o 'UNIX_INTERFACE::stat' is a type alias to the 'stat' type provided //: by the 'sys/stat.h' header. //: //: o 'UNIX_INTERFACE::time_t' is a type alias to the 'time_t' type provided //: by the 'sys/types.h' header. //: //: o 'UNIX_INTERFACE::get_st_mtim_nsec' is a public, static member //: function that has 'long (const stat& stat)' type and whose contract //: is to return the value of the 'st_mtim.tv_nsec' field of the //: specified 'stat' struct. //: //: o 'UNIX_INTERFACE::get_st_mtime' is a public, static member function //: that has 'time_t (const stat& stat)' type and whose contract is to //: return the value of the 'st_mtime' field of the specified 'stat' //: struct. //: //: o 'UNIX_INTERFACE::get_st_size' is a public, static member function //: that has 'off_t (const stat& stat)' type and whose contract is to //: return the value of the 'st_size' field of the specified 'stat' //: struct. Note that this function is required in order to //: access the data members of a 'stat' struct in a manner consistent //: with the requirements of 'get_st_mtime'. //: //: o 'UNIX_INTERFACE::fstat' is a public, static member function that has //: 'int (int fildes, stat *buf)' type and whose contract is to return //: the result of '::fstat(fildes, buf)', where '::fstat' is the //: function provided by the 'sys/stat.h' header. // TYPES typedef int FileDescriptor; // 'FileDescriptor' is an alias for the operating system's native // file descriptor / file handle type. typedef typename UNIX_INTERFACE::off_t Offset; // 'Offset' is an alias for a signed integral type, and represents the // offset of a location in a file. private: // PRIVATE TYPES typedef typename UNIX_INTERFACE::off_t off_t; // 'off_t' is an alias to the 'off_t' type provided by the // 'sys/types.h' header. It is a signed integral type used to // represent quantities of bytes. Note that, depending on the build // configuration, this type may have 32 or 64 bits. typedef typename UNIX_INTERFACE::stat stat; // 'stat' is an alias to the 'stat' 'struct' provided by the // 'sys/stat.h' header. typedef typename UNIX_INTERFACE::time_t time_t; // 'time_t' is an alias to the 'time_t' type provided by the // 'sys/types.h' header. It represents a time point as number of // seconds since January 1st 1970 in Coordinated Universal Time. // PRIVATE CLASS METHODS static long get_st_mtim_nsec(const stat& stat); // Return the value of the 'st_mtim.nsec' field of the specified 'stat' // struct. static time_t get_st_mtime(const stat& stat); // Return the value of the 'st_mtime' data member of the specified // 'stat'. static off_t get_st_size(const stat& stat); // Return the value of the 'st_size' data member of the specified // 'stat' struct. Note that this function is provided in order to // create a consistent interface for accessing the data members of a // 'stat' struct with 'get_st_mtime'. static int fstat(int fildes, stat *buf); // Invoke and return the result of '::fstat(fildes, buf)' with the // specified 'fildes' and 'buf', where '::fstat' is the function // provided by the 'sys/stat.h' header. public: // CLASS METHODS static Offset getFileSize(FileDescriptor descriptor); // Return the size, in bytes, of the file with the specified // 'descriptor', or a negative value if an error occurs. static int getLastModificationTime(bdlt::Datetime *time, FileDescriptor descriptor); // Load into the specified 'time' the last modification time of the // file with the specified 'descriptor', as reported by the filesystem. // Return 0 on success, and a non-zero value otherwise. Note that the // time is reported in UTC. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // --------------------------------- // struct FilesystemUtil_UnixImpUtil // --------------------------------- // PRIVATE CLASS METHODS template <class UNIX_INTERFACE> long FilesystemUtil_UnixImpUtil<UNIX_INTERFACE>::get_st_mtim_nsec(const stat& stat) { return UNIX_INTERFACE::get_st_mtim_nsec(stat); } template <class UNIX_INTERFACE> typename UNIX_INTERFACE::time_t FilesystemUtil_UnixImpUtil<UNIX_INTERFACE>::get_st_mtime(const stat& stat) { return UNIX_INTERFACE::get_st_mtime(stat); } template <class UNIX_INTERFACE> typename UNIX_INTERFACE::off_t FilesystemUtil_UnixImpUtil<UNIX_INTERFACE>::get_st_size(const stat& stat) { return UNIX_INTERFACE::get_st_size(stat); } template <class UNIX_INTERFACE> int FilesystemUtil_UnixImpUtil<UNIX_INTERFACE>::fstat(int fildes, stat *buf) { return UNIX_INTERFACE::fstat(fildes, buf); } // CLASS METHODS template <class UNIX_INTERFACE> typename FilesystemUtil_UnixImpUtil<UNIX_INTERFACE>::Offset FilesystemUtil_UnixImpUtil<UNIX_INTERFACE>::getFileSize( FileDescriptor descriptor) { stat statResult; const int rc = fstat(descriptor, &statResult); if (0 != rc) { return -1; // RETURN } return get_st_size(statResult); } template <class UNIX_INTERFACE> int FilesystemUtil_UnixImpUtil<UNIX_INTERFACE>::getLastModificationTime( bdlt::Datetime *time, FileDescriptor descriptor) { stat statResult; int rc = fstat(descriptor, &statResult); if (0 != rc) { return -1; // RETURN } bdlt::Datetime result = bdlt::EpochUtil::epoch(); rc = result.addSecondsIfValid(get_st_mtime(statResult)); if (0 != rc) { return -1; // RETURN } long nanoseconds = get_st_mtim_nsec(statResult); BSLS_ASSERT_SAFE((0 <= nanoseconds) && (nanoseconds < bdlt::TimeUnitRatio::k_NANOSECONDS_PER_SECOND)); rc = result.addMicrosecondsIfValid( nanoseconds / bdlt::TimeUnitRatio::k_NANOSECONDS_PER_MICROSECOND_32); if (0 != rc) { return -1; // RETURN } *time = result; return 0; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2020 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------