// bdls_filesystemutil.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BDLS_FILESYSTEMUTIL #define INCLUDED_BDLS_FILESYSTEMUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide methods for filesystem access with multi-language names. // //@CLASSES: // bdls::FilesystemUtil: namespace for filesystem access methods // //@SEE_ALSO: bdls_pathutil // //@DESCRIPTION: This component provides a platform-independent interface to // filesystem utility methods, supporting multi-language file and path names. // Each method in the 'bdls::FilesystemUtil' namespace is a thin wrapper on top // of the operating system's own filesystem access functions, providing a // consistent and unambiguous interface for handling files on all supported // platforms. // // Methods in this component can be used to manipulate files with any name in // any language on all supported platforms. To provide such support, the // following restrictions are applied to file names and patterns passed to // methods of this component: On Windows, all file names and patterns must be // passed as UTF-8-encoded strings; file search results will similarly be // encoded as UTF-8. On Posix, file names and patterns may be passed in any // encoding, but all processes accessing a given file must encode its name in // the same encoding. On modern Posix installations, this effectively means // that file names and patterns should be encoded in UTF-8, just as on Windows. // See the section "Platform-Specific File Name Encoding Caveats" below. // ///Policies for 'open' ///------------------- // The behavior of the 'open' method is governed by three sets of enumerations: // ///Open/Create Policy: 'bdls::FilesystemUtil::FileOpenPolicy' /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 'bdls::FilesystemUtil::FileOpenPolicy' governs whether 'open' creates a new // file or opens an existing one. The following values are possible: // //: 'e_OPEN': //: Open an existing file. //: //: 'e_CREATE': //: Create a new file. //: //: 'e_CREATE_PRIVATE': //: Create a new file, with limited permissions where that is supported (e.g. //: not necessarily Microsoft Windows). //: //: 'e_OPEN_OR_CREATE': //: Open a file if it exists, and create a new file otherwise. // ///Input/Output Access Policy: 'bdls::FilesystemUtil::FileIOPolicy' /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 'bdls::FilesystemUtil::FileIOPolicy' governs what Input/Output operations // are allowed on a file after it is opened. The following values are // possible: // //: 'e_READ_ONLY': //: Allow reading only. //: //: 'e_WRITE_ONLY': //: Allow writing only. //: //: 'e_READ_WRITE': //: Allow both reading and writing. //: //: 'e_APPEND_ONLY': //: Allow appending to end-of-file only. //: //: 'e_READ_APPEND': //: Allow both reading and appending to end-of-file. // ///Truncation Policy: 'bdls::FilesystemUtil::FileTruncatePolicy' ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 'bdls::FilesystemUtil::FileTruncatePolicy' governs whether 'open' deletes // the existing contents of a file when it is opened. The following values are // possible: // //: 'e_TRUNCATE': //: Delete the file's contents. //: //: 'e_KEEP': //: Keep the file's contents. // ///Starting Points for 'seek' ///-------------------------- // The behavior of the 'seek' method is governed by an enumeration that // determines the point from which the seek operation starts: // //: 'e_SEEK_FROM_BEGINNING': //: Seek from the beginning of the file. //: //: 'e_SEEK_FROM_CURRENT': //: Seek from the current position in the file. //: //: 'e_SEEK_FROM_END': //: Seek from the end of the file. // ///Platform-Specific File Locking Caveats ///-------------------------------------- // Locking has the following caveats for the following operating systems: //: //: o On Posix, closing a file releases all locks on all file descriptors //: referring to that file within the current process. [doc 1] [doc 2] //: //: o On Posix, the child of a fork does not inherit the locks of the parent //: process. [doc 1] [doc 2] //: //: o On at least some flavors of Unix, you can't lock a file for writing using //: a file descriptor opened in read-only mode. // ///Platform-Specific Atomicity Caveats ///----------------------------------- // The 'bdls::FilesystemUtil::read' and 'bdls::FilesystemUtil::write' methods // add no atomicity guarantees for reading and writing to those provided (if // any) by the underlying platform's methods for reading and writing (see // 'http://lwn.net/articles/180387/'). // ///Platform-Specific File Name Encoding Caveats ///-------------------------------------------- // File-name encodings have the following caveats for the following operating // systems: // //: o On Windows, methods of 'bdls::FilesystemUtil' that take a file or //: directory name or pattern as a 'char*' or 'bsl::string' type assume that //: the name is encoded in UTF-8. The routines attempt to convert the name //: to a UTF-16 'wchar_t' string via 'bdlde::CharConvertUtf16::utf8ToUtf16', //: and if the conversion succeeds, call the Windows wide-character 'W' APIs //: with the UTF-16 name. If the conversion fails, the method fails. //: Similarly, file searches returning file names call the Windows //: wide-character 'W' APIs and convert the resulting UTF-16 names to UTF-8. //: //: o Narrow-character file names in other encodings, containing characters //: with values in the range 128 - 255, will likely result in files being //: created with names that appear garbled if the conversion from UTF-8 to //: UTF-16 happens to succeed. //: //: o Neither 'utf8ToUtf16' nor the Windows 'W' APIs do any normalization of //: the UTF-16 strings resulting from UTF-8 conversion, and it is therefore //: possible to have sets of file names that have the same visual //: representation but are treated as different names by the filesystem. //: //: o On Posix, a file name or pattern supplied to methods of //: 'bdls::FilesystemUtil' as a 'char*' or 'bsl::string' type is passed //: unchanged to the underlying system file APIs. Because the file names and //: patterns are passed unchanged, 'bdls::FilesystemUtil' methods will work //: correctly on Posix with any encoding, but will *interoperate* only with //: processes that use the same encoding as the current process. //: //: o For compatibility with most modern Posix installs, and consistency with //: this component's Windows API, best practice is to encode all file names //: and patterns in UTF-8. // ///File Truncation Caveats ///----------------------- // In order to provide consistent behavior across both Posix and Windows // platforms, when the 'open' method is called, file truncation is allowed only // if the client requests an 'openPolicy' containing the word 'CREATE' and/or // an 'ioPolicy' containing the word 'WRITE'. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: General Usage /// - - - - - - - - - - - - // In this example, we start with a (relative) native path to a directory // containing log files: //.. // #ifdef BSLS_PLATFORM_OS_WINDOWS // bsl::string logPath = "temp.1\\logs"; // #else // bsl::string logPath = "temp.1/logs"; // #endif //.. // Suppose that we want to separate files into "old" and "new" subdirectories // on the basis of modification time. We will provide paths representing these // locations, and create the directories if they do not exist: //.. // bsl::string oldPath(logPath), newPath(logPath); // bdls::PathUtil::appendRaw(&oldPath, "old"); // bdls::PathUtil::appendRaw(&newPath, "new"); // int rc = bdls::FilesystemUtil::createDirectories(oldPath, true); // assert(0 == rc); // rc = bdls::FilesystemUtil::createDirectories(newPath, true); // assert(0 == rc); //.. // We know that all of our log files match the pattern "*.log", so let's search // for all such files in the log directory: //.. // bdls::PathUtil::appendRaw(&logPath, "*.log"); // bsl::vector<bsl::string> logFiles; // bdls::FilesystemUtil::findMatchingPaths(&logFiles, logPath.c_str()); //.. // Now for each of these files, we will get the modification time. Files that // are older than 2 days will be moved to "old", and the rest will be moved to // "new": //.. // bdlt::Datetime modTime; // bsl::string fileName; // for (bsl::vector<bsl::string>::iterator it = logFiles.begin(); // it != logFiles.end(); ++it) { // assert(0 == // bdls::FilesystemUtil::getLastModificationTime(&modTime, *it)); // assert(0 == bdls::PathUtil::getLeaf(&fileName, *it)); // bsl::string *whichDirectory = // 2 < (bdlt::CurrentTime::utc() - modTime).totalDays() // ? &oldPath // : &newPath; // bdls::PathUtil::appendRaw(whichDirectory, fileName.c_str()); // assert(0 == bdls::FilesystemUtil::move(it->c_str(), // whichDirectory->c_str())); // bdls::PathUtil::popLeaf(whichDirectory); // } //.. // ///Example 2: Using 'bdls::FilesystemUtil::visitPaths' ///- - - - - - - - - - - - - - - - - - - - - - - - - - // 'bdls::FilesystemUtil::visitPaths' enables clients to define a function // object to operate on file paths that match a specified pattern. In this // example, we create a function that can be used to filter out files that have // a last modified time within a particular time frame. // // First we define our filtering function: //.. // void getFilesWithinTimeframe(bsl::vector<bsl::string> *vector, // const char *item, // const bdlt::Datetime& start, // const bdlt::Datetime& end) // { // bdlt::Datetime datetime; // int ret = bdls::FilesystemUtil::getLastModificationTime(&datetime, // item); // // if (ret) { // return; // RETURN // } // // if (datetime < start || datetime > end) { // return; // RETURN // } // // vector->push_back(item); // } //.. // Then, with the help of 'bdls::FilesystemUtil::visitPaths' and // 'bdlf::BindUtil::bind', we create a function for finding all file paths that // match a specified pattern and have a last modified time within a specified // start and end time (both specified as a 'bdlt::Datetime'): //.. // void findMatchingFilesInTimeframe(bsl::vector<bsl::string> *result, // const char *pattern, // const bdlt::Datetime& start, // const bdlt::Datetime& end) // { // result->clear(); // bdls::FilesystemUtil::visitPaths( // pattern, // bdlf::BindUtil::bind(&getFilesWithinTimeframe, // result, // bdlf::PlaceHolders::_1, // start, // end)); // } //.. #include <bdlscm_version.h> #include <bdls_filesystemutil_unixplatform.h> #include <bdlt_datetime.h> #include <bdlt_epochutil.h> #include <bslmf_assert.h> #include <bsls_assert.h> #include <bsl_functional.h> #include <bsl_optional.h> #include <bsls_keyword.h> #include <bsls_libraryfeatures.h> #include <bsls_platform.h> #include <bsls_review.h> #include <bsl_string.h> #include <bsl_string_view.h> #include <bsl_vector.h> #include <bsl_cstddef.h> #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR #include <memory_resource> // 'std::pmr::polymorphic_allocator' #endif #include <string> // 'std::string', 'std::pmr::string' #include <vector> #include <sys/types.h> namespace BloombergLP { namespace bdls { // ===================== // struct FilesystemUtil // ===================== struct FilesystemUtil { // This 'struct' provides a namespace for utility functions dealing with // platform-independent filesystem access. // TYPES #ifdef BSLS_PLATFORM_OS_WINDOWS typedef void *HANDLE; // 'HANDLE' is a stand-in for the Windows API 'HANDLE' type, to allow // us to avoid including 'windows.h' in this header. 'HANDLE' should // not be used by client code. typedef HANDLE FileDescriptor; // 'FileDescriptor' is an alias for the operating system's native file // descriptor / file handle type. typedef __int64 Offset; // 'Offset' is an alias for a signed value, representing the offset of // a location within a file. static const Offset k_OFFSET_MAX = _I64_MAX; // maximum representable file offset value static const Offset k_OFFSET_MIN = _I64_MIN; // minimum representable file offset value #elif defined(BSLS_PLATFORM_OS_UNIX) typedef int FileDescriptor; // 'FileDescriptor' is an alias for the operating system's native file // descriptor / file handle type. #if defined(BDLS_FILESYSTEMUTIL_UNIXPLATFORM_64_BIT_OFF64) typedef off64_t Offset; // 'Offset' is an alias for a signed value, representing the offset of // a location within a file. #else typedef off_t Offset; // 'Offset' is an alias for a signed value, representing the offset of // a location within a file. #endif static const Offset k_OFFSET_MAX = (0x7FFFFFFFFFFFFFFFLL); // maximum representable file offset value static const Offset k_OFFSET_MIN = (-0x7FFFFFFFFFFFFFFFLL-1); // minimum representable file offset value #else # error "'bdls_filesystemutil' does not support this platform." #endif enum Whence { // Enumeration used to distinguish among different starting points for // a seek operation. e_SEEK_FROM_BEGINNING = 0, // Seek from beginning of file. e_SEEK_FROM_CURRENT = 1, // Seek from current position. e_SEEK_FROM_END = 2 // Seek from end of file. }; enum { k_DEFAULT_FILE_GROWTH_INCREMENT = 0x10000 // default block size to // grow files by }; enum { k_ERROR_LOCKING_CONFLICT = 1, // value representing a failure to // obtain a lock on a file k_ERROR_LOCKING_INTERRUPTED = 2, // value representing a failure to // obtain a lock on a file due to // interruption by a signal k_ERROR_ALREADY_EXISTS = 3, // value representing a failure to // create a directory due to a file // system entry already existing k_ERROR_PATH_NOT_FOUND = 4, // value representing a failure to // create a directory due to one ore // more components of the path // either not existing or not being // a directory k_BAD_FILE_DESCRIPTOR = -1 // value indicating a bad file // descriptor was supplied }; enum FileOpenPolicy { // Enumeration used to determine whether 'open' should open an existing // file, or create a new file. e_OPEN, // Open a file if it exists, and fail otherwise. e_CREATE, // Create a new file, and fail if the file already // exists. e_CREATE_PRIVATE, // Create a new file with access restricted to the // creating userid, where supported, and fail if the // file already exists. e_OPEN_OR_CREATE // Open a file if it exists, and create a new file // otherwise. }; enum FileIOPolicy { // Enumeration used to distinguish between different sets of actions // permitted on an open file descriptor. e_READ_ONLY, // Allow reading only. e_WRITE_ONLY, // Allow writing only. e_APPEND_ONLY, // Allow appending to end-of-file only. e_READ_WRITE, // Allow both reading and writing. e_READ_APPEND // Allow both reading and appending to end-of-file. }; enum FileTruncatePolicy { // Enumeration used to distinguish between different ways to handle the // contents, if any, of an existing file immediately upon opening the // file. e_TRUNCATE, // Delete the file's contents on open. e_KEEP // Keep the file's contents. }; // CLASS DATA static const FileDescriptor k_INVALID_FD; // 'FileDescriptor' value // representing no file, used // as the error return for // 'open' // CLASS METHODS static FileDescriptor open(const char *path, FileOpenPolicy openPolicy, FileIOPolicy ioPolicy, FileTruncatePolicy truncatePolicy = e_KEEP); template <class STRING_TYPE> static FileDescriptor open(const STRING_TYPE& path, FileOpenPolicy openPolicy, FileIOPolicy ioPolicy, FileTruncatePolicy truncatePolicy = e_KEEP); // Open the file at the specified 'path', using the specified // 'openPolicy' to determine whether to open an existing file or create // a new file, and using the specified 'ioPolicy' to determine whether // the file will be opened for reading, writing, or both. Optionally // specify a 'truncatePolicy' to determine whether any contents of the // file will be deleted before 'open' returns. If 'truncatePolicy' is // not supplied, the value 'e_KEEP' will be used. Return a valid // 'FileDescriptor' for the file on success, or 'k_INVALID_FD' // otherwise. If 'openPolicy' is 'e_OPEN', the file will be opened if // it exists, and 'open' will fail otherwise. If 'openPolicy' is // 'e_CREATE' or 'e_CREATE_PRIVATE', and no file exists at 'path', a // new file will be created, and 'open' will fail otherwise. If // 'openPolicy' is 'e_CREATE_PRIVATE', the file will be created with // access restricted to the same userid as the caller in environments // where that is supported (which does not necessarily include Windows) // otherwise the system default access policy is used (e.g. '0777 & // ~umask'). If 'openPolicy' is 'e_OPEN_OR_CREATE', the file will be // opened if it exists, and a new file will be created otherwise. If // 'ioPolicy' is 'e_READ_ONLY', the returned 'FileDescriptor' will // allow only read operations on the file. If 'ioPolicy' is // 'e_WRITE_ONLY' or 'e_APPEND_ONLY', the returned 'FileDescriptor' // will allow only write operations on the file. If 'ioPolicy' is // 'e_READ_WRITE' or 'e_READ_APPEND', the returned 'FileDescriptor' // will allow both read and write operations on the file. // Additionally, if 'ioPolicy' is 'e_APPEND_ONLY' or 'e_READ_APPEND' // all writes will be made to the end of the file ("append mode"). If // 'truncatePolicy' is 'e_TRUNCATE', the file will have zero length // when 'open' returns. If 'truncatePolicy' is 'e_KEEP', the file will // be opened with its existing contents, if any. Note that when a file // is opened in 'append' mode, all writes will go to the end of the // file, even if there has been seeking on the file descriptor or // another process has changed the length of the file. Append-mode // writes are not atomic except in limited cases; another thread, or // even another process, operating on the file may cause output not to // be written, unbroken, to the end of the file. (Unix environments // writing to local file systems may promise more.) Note that 'open' // will fail to open a file with a 'truncatePolicy' of 'e_TRUNCATE' // unless at least one of the following policies is specified for // 'openPolicy' or 'ioPolicy': //: o 'e_CREATE' //: o 'e_CREATE_PRIVATE' //: o 'e_OPEN_OR_CREATE' //: o 'e_WRITE_ONLY //: o 'e_READ_WRITE' // The parameterized 'STRING_TYPE' must be one of 'bsl::string', // 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static int close(FileDescriptor descriptor); // Close the specified 'descriptor'. Return 0 on success and a // non-zero value otherwise. A return value of // 'k_BAD_FILE_DESCRIPTOR' indicates that the supplied 'descriptor' is // invalid. static int getWorkingDirectory(bsl::string *path); static int getWorkingDirectory(std::string *path); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static int getWorkingDirectory(std::pmr::string *path); #endif // Load into the specified 'path' the absolute pathname of the current // working directory. Return 0 on success and a non-zero value // otherwise. static int setWorkingDirectory(const char *path); template <class STRING_TYPE> static int setWorkingDirectory(const STRING_TYPE& path); // Set the working directory of the current process to the specified // 'path'. Return 0 on success and a non-zero value otherwise. The // parameterized 'STRING_TYPE' must be one of 'bsl::string', // 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static bool exists(const char *path); template <class STRING_TYPE> static bool exists(const STRING_TYPE& path); // Return 'true' if there currently exists a file or directory at the // specified 'path', and 'false' otherwise. If 'path' is a symlink, // the result of this function is platform dependent. On POSIX/Unix // platforms this method dereferences symlinks, while on Windows it // does not. The parameterized 'STRING_TYPE' must be one of // 'bsl::string', 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static bool isRegularFile(const char *path, bool followLinksFlag = false); template <class STRING_TYPE> static bool isRegularFile(const STRING_TYPE& path, bool followLinksFlag = false); // Return 'true' if there currently exists a regular file at the // specified 'path', and 'false' otherwise. If there is a symbolic // link at 'path', follow it only if the optionally specified // 'followLinksFlag' is 'true' (otherwise, return 'false' as the // symbolic link itself is not a regular file irrespective of the file // to which it points). Platform-specific note: On POSIX, this is a // positive test on the "regular file" mode; on Windows, this is a // negative test on the "directory" attribute, i.e., on Windows, // everything that exists and is not a directory is a regular file. // The parameterized 'STRING_TYPE' must be one of 'bsl::string', // 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static bool isDirectory(const char *path, bool followLinksFlag = false); template <class STRING_TYPE> static bool isDirectory(const STRING_TYPE& path, bool followLinksFlag = false); // Return 'true' if there currently exists a directory at the specified // 'path', and 'false' otherwise. If there is a symbolic link at // 'path', follow it only if the optionally specified 'followLinksFlag' // is 'true' (otherwise return 'false'). Platform-specific note: On // Windows, a "shortcut" is not a symbolic link. The parameterized // 'STRING_TYPE' must be one of 'bsl::string', 'std::string', // 'std::pmr::string' (if supported), or 'bslstl::StringRef'. static bool isSymbolicLink(const char *path); template <class STRING_TYPE> static bool isSymbolicLink(const STRING_TYPE& path); // Return 'true' if there currently exists a symbolic link at the // specified 'path', and 'false' otherwise. Windows directory // junctions are treated as directory symbolic links. The // parameterized 'STRING_TYPE' must be one of 'bsl::string', // 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static int getLastModificationTime(bdlt::Datetime *time, const char *path); template <class STRING_TYPE> static int getLastModificationTime(bdlt::Datetime *time, const STRING_TYPE& path); // Load into the specified 'time' the last modification time of the // file at the specified 'path', as reported by the filesystem. Return // 0 on success, and a non-zero value otherwise. The time is reported // in UTC. The parameterized 'STRING_TYPE' must be one of // 'bsl::string', 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. 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. The time is // reported in UTC. // TBD: write setModificationTime() when SetFileInformationByHandle() // becomes available on our standard Windows platforms. static int createDirectories(const char *path, bool isLeafDirectoryFlag = false); template <class STRING_TYPE> static int createDirectories( const STRING_TYPE& path, bool isLeafDirectoryFlag = false); // Create any directories in the specified 'path' that do not exist. // If the optionally specified 'isLeafDirectoryFlag' is 'true', treat // the final name component in 'path' as a directory name, and create // it. Otherwise, create only the directories leading up to the final // name component. Return 0 on success, 'k_ERROR_PATH_NOT_FOUND' if a // component used as a directory in 'path' exists but is not a // directory, and a negative value for any other kind of error. The // parameterized 'STRING_TYPE' must be one of 'bsl::string', // 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static int createPrivateDirectory(const char *path); template <class STRING_TYPE> static int createPrivateDirectory(const STRING_TYPE& path); // Create a private directory with the specified 'path'. Return 0 on // success, 'k_ERROR_PATH_NOT_FOUND' if a component used as a directory // in 'path' either does not exist or is not a directory, // 'k_ERROR_ALREADY_EXISTS' if the file system entry (not necessarily a // directory) with the name 'path' already exists, and a negative value // for any other kind of error. The directory is created with // permissions restricting access, as closely as possible, to the // caller's userid only. Note that directories created on Microsoft // Windows may receive default, not restricted permissions. The // parameterized 'STRING_TYPE' must be one of 'bsl::string', // 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static int getSystemTemporaryDirectory(bsl::string *path); static int getSystemTemporaryDirectory(std::string *path); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static int getSystemTemporaryDirectory(std::pmr::string *path); #endif // Load a valid path to the system temporary directory to the specified // 'path'. Return 0 on success, and a non-zero value otherwise. A // temporary directory is one in which the operating system has // permission to delete its contents, but not necessarily the directory // itself, the next time the computer reboots. static FileDescriptor createTemporaryFile(bsl::string *outPath, const bsl::string_view& prefix); static FileDescriptor createTemporaryFile(std::string *outPath, const bsl::string_view& prefix); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static FileDescriptor createTemporaryFile(std::pmr::string *outPath, const bsl::string_view& prefix); #endif // Create and open a new file with a name constructed by appending an // automatically-generated suffix to the specified 'prefix', and return // its file descriptor open for reading and writing. A return value of // 'k_INVALID_FD' indicates that no such file could be created; // otherwise, the name of the file created is assigned to the specified // 'outPath'. The file is created with permissions restricted, as // closely as possible, to the caller's userid only. If the prefix is // a relative path, the file is created relative to the process current // directory. Responsibility for deleting the file is left to the // caller. Note that on Posix systems, if 'outPath' is unlinked // immediately, the file will remain usable until its descriptor is // closed. Note that files created on Microsoft Windows may receive // default, not restricted permissions. static int createTemporaryDirectory(bsl::string *outPath, const bsl::string_view& prefix); static int createTemporaryDirectory(std::string *outPath, const bsl::string_view& prefix); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static int createTemporaryDirectory(std::pmr::string *outPath, const bsl::string_view& prefix); #endif // Create a new directory with a name constructed by appending an // automatically-generated suffix to the specified 'prefix'. A // non-zero return value indicates that no such directory could be // created; otherwise the name of the directory created is assigned to // the specified 'outPath'. The directory is created with permissions // restricted, as closely as possible, to the caller only. If the // prefix is a relative path, the directory is created relative to the // process current directory. Responsibility for deleting the // directory (and any files subsequently created in it) is left to the // caller. static void makeUnsafeTemporaryFilename(bsl::string *outPath, const bsl::string_view& prefix); static void makeUnsafeTemporaryFilename(std::string *outPath, const bsl::string_view& prefix); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static void makeUnsafeTemporaryFilename(std::pmr::string *outPath, const bsl::string_view& prefix); #endif // Construct a file name by appending an automatically-generated suffix // to the specified 'prefix'. The file name constructed is assigned to // the specified 'outPath'. Note that this function is called "unsafe" // because a file with the resulting name may be created by another // program before the caller has opportunity to use the name, which // could be a security vulnerability, and a file with the given name // may already exist where you mean to put it. Note that the suffix is // hashed from environmental details, including any pre-existing value // of 'outPath' so that if a resulting name is unsuitable (e.g. the // file exists) this function may simply be called again, pointing to // its previous result, to get a new, probably different name. static int visitPaths( const char *pattern, const bsl::function<void(const char *path)>& visitor); template <class STRING_TYPE> static int visitPaths( const STRING_TYPE& pattern, const bsl::function<void(const char *path)>& visitor); // Call the specified 'visitor' function object for each path in the // filesystem matching the specified 'pattern'. Return the number of // paths visited on success, and a negative value otherwise. Note that // if 'visitor' deletes files or directories during the search, // 'visitor' may subsequently be called with paths which have already // been deleted, so must be prepared for this event. Also note that // there is no guarantee as to the order in which paths will be // visited. See 'findMatchingPaths' for a discussion of how 'pattern' // is interpreted. Also note that '.' and '..' are never matched by // wild cards. The parameterized 'STRING_TYPE' must be one of // 'bsl::string', 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. // // IBM-SPECIFIC WARNING: This function is not thread-safe. The AIX // implementation of the system 'glob' function can temporarily change // the working directory of the entire program, causing attempts in // other threads to open files with relative path names to fail. static int visitTree( const bsl::string_view& root, const bsl::string_view& pattern, const bsl::function<void(const char *path)>& visitor, bool sortFlag = false); // Recursively traverse the directory tree starting at the specified // 'root' for files whose leaf names match the specified 'pattern', and // run the specified function 'visitor', passing it the full path // starting with 'root' to each pattern matching file. See // 'findMatchingPaths' for a discussion of how 'pattern' is // interpreted. If the specified 'sortFlag' is 'true', traverse the // files in the tree in sorted order, sorted by the full path name, // otherwise the order in which the files will be visited is // unspecified. UTF-8 paths will be sorted by 'strcmp', which sorts by // 'char's, not unicode code points. Found '.' and '..' directories // are ignored, except that 'root' may be '.' or '..'. Return 0 on // success, and a non-zero value otherwise. This function will fail if // 'root' does not specify a directory, of if 'pattern' contains '/' on // Unix or '\' on Windows. Note that both directories and plain files // whose names match 'pattern' will be visited, while other files such // as symlinks will not be visited or followed. No file or directory // that is not matched will be visited. All directories are traversed, // regardless of whether they are matched. If a directory is matched // and 'sortFlag' is 'true', it is visited immediately before it is // traversed. Also note that 'root' is never visited, even if it // matches 'pattern'. Also note that no pattern matching is done on // 'root' -- if it contains wildcards, they are not interpreted as such // and must exactly match the characters in the name of the directory. // // IBM-SPECIFIC WARNING: This function is not thread-safe. The AIX // implementation of the system 'glob' function can temporarily change // the working directory of the entire program, casuing attempts in // other threads to open files with relative path names to fail. static int findMatchingPaths(bsl::vector<bsl::string> *result, const char *pattern); template <class STRING_TYPE> static int findMatchingPaths(bsl::vector<bsl::string> *result, const STRING_TYPE& pattern); static int findMatchingPaths(std::vector<std::string> *result, const char *pattern); template <class STRING_TYPE> static int findMatchingPaths(std::vector<std::string> *result, const STRING_TYPE& pattern); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static int findMatchingPaths(std::pmr::vector<std::pmr::string> *result, const char *pattern); template <class STRING_TYPE> static int findMatchingPaths(std::pmr::vector<std::pmr::string> *result, const STRING_TYPE& pattern); #endif // Load into the specified 'result' vector all paths in the filesystem // matching the specified 'pattern'. The '*' character will match any // number of characters in a filename; however, this matching will not // span a directory separator (e.g., "logs/m*.txt" will not match // "logs/march/001.txt"). '?' will match any one character. '*' and // '?' may be used any number of times in the pattern. The special // directories "." and ".." will not be matched against any pattern. // Note that any initial contents of 'result' will be erased, and that // the paths in 'result' will not be in any particular guaranteed // order. Return the number of paths matched on success, and a // negative value otherwise; if a negative value is returned, the // contents of '*result' are undefined. The parameterized // 'STRING_TYPE' must be one of 'bsl::string', 'std::string', // 'std::pmr::string' (if supported), or 'bslstl::StringRef'. // // WINDOWS-SPECIFIC NOTE: To support DOS idioms, the OS-provided search // function has behavior that we have chosen not to work around: an // extension consisting of wild-card characters ('?', '*') can match an // extension or *no* extension. E.g., "file.?" matches "file.z", but // not "file.txt"; however, it also matches "file" (without any // extension). Likewise, "*.*" matches any filename, including // filenames having no extension. Also, on Windows (but not on Unix) // attempting to match a pattern that is invalid UTF-8 will result in // an error. // // IBM-SPECIFIC WARNING: This function is not thread-safe. The AIX // implementation of the system 'glob' function can temporarily change // the working directory of the entire program, casuing attempts in // other threads to open files with relative path names to fail. static Offset getAvailableSpace(const char *path); template <class STRING_TYPE> static Offset getAvailableSpace(const STRING_TYPE& path); // Return the number of bytes available for allocation in the file // system where the file or directory with the specified 'path' // resides, or a negative value if an error occurs. The parameterized // 'STRING_TYPE' must be one of 'bsl::string', 'std::string', // 'std::pmr::string' (if supported), or 'bslstl::StringRef'. static Offset getAvailableSpace(FileDescriptor descriptor); // Return the number of bytes available for allocation in the file // system where the file with the specified 'descriptor' resides, or a // negative value if an error occurs. static Offset getFileSize(const char *path); template <class STRING_TYPE> static Offset getFileSize(const STRING_TYPE& path); // Return the size, in bytes, of the file or directory at the specified // 'path', or a negative value if an error occurs. Note that the size // of a symbolic link is the size of the file or directory to which it // points. The parameterized 'STRING_TYPE' must be one of // 'bsl::string', 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. 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 Offset getFileSizeLimit(); // Return the file size limit for this process, 'k_OFFSET_MAX' if no // limit is set, or a negative value if an error occurs. Note that if // you are doing any calculations involving the returned value, it is // recommended to check for 'k_OFFSET_MAX' specifically to avoid // integer overflow in your calculations. static int getSymbolicLinkTarget(bsl::string *result, const char *path); static int getSymbolicLinkTarget(std::string *result, const char *path); template <class STRING_TYPE> static int getSymbolicLinkTarget(bsl::string *result, const STRING_TYPE& path); template <class STRING_TYPE> static int getSymbolicLinkTarget(std::string *result, const STRING_TYPE& path); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static int getSymbolicLinkTarget(std::pmr::string *result, const char *path); template <class STRING_TYPE> static int getSymbolicLinkTarget(std::pmr::string *result, const STRING_TYPE& path); #endif // Load, into the specified 'result', the target of the symbolic link // at the specified 'path'. Return 0 on success, and a non-zero value // otherwise. For example, this function will return an error if // 'path' does not refer to a symbolic link. Windows directory // junctions are treated as directory symbolic links. If 'path' is a // relative path, it is evaluated against the current working // directory. The parameterized 'STRING_TYPE' must be one of // 'bsl::string', 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. static int lock(FileDescriptor descriptor, bool lockWriteFlag); // Acquire a lock for the file with the specified 'descriptor'. If // 'lockWriteFlag' is true, acquire an exclusive write lock; otherwise // acquire a (possibly) shared read lock. The calling thread will // block until the lock is acquired. Return 0 on success, and a // non-zero value otherwise. Note that this operation locks the // indicated file for use by the current *process*, but the behavior is // unspecified (and platform-dependent) when either attempting to lock // 'descriptor' multiple times, or attempting to lock another // descriptor referring to the same file, within a single process. static int truncateFileSize(FileDescriptor descriptor, Offset size); // Set the size of the file referred to by the specified 'descriptor' // to the specified 'size'. 'descriptor' must be open for writing. // After the function call, the position is set to the end of the file. // Return 0 on success and a non-zero value otherwise. The behavior is // undefined if the file is currently mapped, or if 'size' is greater // than the existing size of the file. static int tryLock(FileDescriptor descriptor, bool lockWriteFlag); // Acquire a lock for the file with the specified 'descriptor' if it is // currently available. If the specified 'lockWriteFlag' is true, // acquire an exclusive write lock unless another process has any type // of lock on the file. If 'lockWriteFlag' is false, acquire a shared // read lock unless a process has a write lock. This method will not // block. Return 0 on success, 'k_ERROR_LOCKING_CONFLICT' if the // platform reports the lock could not be acquired because another // process holds a conflicting lock, and a negative value for any other // kind of error. Note that this operation locks the indicated file // for the current *process*, but the behavior is unspecified (and // platform-dependent) when either attempting to lock 'descriptor' // multiple times, or attempting to lock another descriptor referring // to the same file, within a single process. static int unlock(FileDescriptor descriptor); // Release any lock this process holds on the file with the specified // 'descriptor'. Return 0 on success, and a non-zero value otherwise. static int map(FileDescriptor descriptor, void **address, Offset offset, bsl::size_t size, int mode); // Map the region of the specified 'size' bytes, starting at the // specified 'offset' bytes into the file with the specified // 'descriptor' to memory, and load into the specified 'address' of the // mapped area. Return 0 on success, and a non-zero value otherwise. // The access permissions for mapping memory are defined by the // specified 'mode', which may be a combination of // 'MemoryUtil::k_ACCESS_READ', 'MemoryUtil::k_ACCESS_WRITE' and // 'MemoryUtil::k_ACCESS_EXECUTE'. Note that on failure, the value of // 'address' is undefined. Also note that mapping will succeed even if // there are fewer than 'offset + size' bytes in the specified file, // and an attempt to access the mapped memory beyond the end of the // file will result in undefined behavior (i.e., this function does not // grow the file to guarantee it can accommodate the mapped region). static int unmap(void *address, bsl::size_t size); // Unmap the memory mapping with the specified base 'address' and // specified 'size'. Return 0 on success, and a non-zero value // otherwise. The behavior is undefined unless this area with // 'address' and 'size' was previously mapped with a 'map' call. static int sync(char *address, bsl::size_t numBytes, bool syncFlag); // Synchronize the contents of the specified 'numBytes' of mapped // memory beginning at the specified 'address' with the underlying file // on disk. If the specified 'syncFlag' is true, block until all // writes to nonvolatile media have actually completed, otherwise, // return once they have been scheduled. Return 0 on success, and a // non-zero value otherwise. The behavior is undefined unless // 'address' is aligned on a page boundary, 'numBytes' is a multiple of // 'pageSize()', and '0 <= numBytes'. static Offset seek(FileDescriptor descriptor, Offset offset, int whence); // Set the file pointer associated with the specified 'descriptor' // (used by calls to the 'read' and 'write' system calls) according to // the specified 'whence' behavior: //.. // * If 'whence' is e_SEEK_FROM_BEGINNING, set the pointer to // 'offset' bytes from the beginning of the file. // * If 'whence' is e_SEEK_FROM_CURRENT, advance the pointer by // 'offset' bytes // * If 'whence' is e_SEEK_FROM_END, set the pointer to 'offset' // bytes beyond the end of the file. //.. // Return the new location of the file pointer, in bytes from the // beginning of the file, on success; and -1 otherwise. The effect on // the file pointer is undefined unless the file is on a device capable // of seeking. Note that 'seek' does not change the size of the file // if the pointer advances beyond the end of the file; instead, the // next write at the pointer will increase the file size. static int read(FileDescriptor descriptor, void *buffer, int numBytes); // Read the specified 'numBytes' bytes beginning at the file pointer of // the file with the specified 'descriptor' into the specified // 'buffer'. Return 'numBytes' on success; the number of bytes read // if there were not enough available; or a negative number on some // other error. static int remove(const char *path, bool recursiveFlag = false); template <class STRING_TYPE> static int remove(const STRING_TYPE& path, bool recursiveFlag = false); // Remove the file or directory at the specified 'path'. If the 'path' // refers to a directory and the optionally specified 'recursiveFlag' // is 'true', recursively remove all files and directories within the // specified directory before removing the directory itself. Return 0 // on success and a non-zero value otherwise. If 'path' refers to a // symbolic link, the symbolic link will be removed, not the target of // the link. Note that if 'path' is a directory, and the directory is // not empty, and recursive is 'false', this method will fail. Also // note that if the function fails when 'recursive' is 'true', it may // or may not have removed *some* files or directories before failing. // The parameterized 'STRING_TYPE' must be one of 'bsl::string', // 'std::string', 'std::pmr::string' (if supported), or // 'bslstl::StringRef'. // // IBM-SPECIFIC WARNING: This function is not thread-safe. The AIX // implementation of the system 'glob' function can temporarily change // the working directory of the entire program, causing attempts in // other threads to open files with relative path names to fail. static int rollFileChain(const bsl::string_view& path, int maxSuffix); // Remove the file at the specified 'path' appended with the specified // 'maxSuffix' using a '.' as a separator. Then move the files with // the suffixes '.1' to '.maxSuffix-1' so they have new suffixes from // '.2' to '.maxSuffix'. Finally, move 'path' to 'path' with a '.1' // suffix. Return 0 on success, and non-zero otherwise. static int move(const char *oldPath, const char *newPath); template <class OLD_STRING_TYPE, class NEW_STRING_TYPE> static int move(const OLD_STRING_TYPE& oldPath, const NEW_STRING_TYPE& newPath); // Move the file or directory at the specified 'oldPath' to the // specified 'newPath'. If there is a file or directory at 'newPath', // it will be removed and replaced. In that case, 'newPath' must refer // to the same type of filesystem item as 'oldPath' - that is, they // must both be directories or both be files. Return 0 on success, and // a non-zero value otherwise. If 'oldPath' is a symbolic link, the // link will be renamed. If a symbolic link already exists at // 'newPath', the resulting behavior is platform dependent. Note that // this operation is carried out via library/system facilities // ('rename' in UNIX and 'MoveFile' in Windows) that usually cannot // move files between file systems or volumes, and that the behavior of // the underlying library/system facilities differs when 'oldPath' and // 'newPath' refer to the same file (in that case, UNIX succeeds, // Windows fails). Note that a symbolic link already exists at // 'newPath' POSIX/Unix systems will overwrite that existing symbolic // link, while Windows will return an error status ('GetLastError' will // report 'ERROR_ALREADY_EXISTS'). The parameterized 'OLD_STRING_TYPE' // and 'NEW_STRING_TYPE' must be one of 'bsl::string', 'std::string', // 'std::pmr::string' (if supported), or 'bslstl::StringRef'. static int write(FileDescriptor descriptor, const void *buffer, int numBytes); // Write the specified 'numBytes' from the specified 'buffer' address // to the file with the specified 'descriptor'. Return 'numBytes' on // success; the number of bytes written if space was exhausted; or a // negative value on some other error. static int growFile( FileDescriptor descriptor, Offset size, bool reserveFlag = false, bsl::size_t increment = k_DEFAULT_FILE_GROWTH_INCREMENT); // Grow the file with the specified 'descriptor' to the size of at // least the specified 'size' bytes. Return 0 on success, and a // non-zero value otherwise. If the optionally specified 'reserveFlag' // is true, make sure the space on disk is preallocated and not // allocated on demand, preventing a possible out-of-disk-space error // when accessing the data on file systems with sparse file support. // Preallocation is done by writing unspecified data to file in blocks // of the optionally specified 'increment' or a default value if // 'increment' is zero or unspecified. Note that if the size of the // file is greater than or equal to 'size', this function has no // effect. Also note that the contents of the newly grown portion of // the file is undefined. }; // ================================ // class FilesystemUtil_CStringUtil // ================================ struct FilesystemUtil_CStringUtil { // This component-private utility 'struct' provides a namespace for the // 'flatten' overload set intended to be used in concert with an overload // set consisting of a function template with a deduced argument and an // non-template overload accepting a 'const char *'. The actual // implementation of the functionality would be in the 'const char *' // overload whereas the purpose of the function template is to invoke the // 'const char *' overload with a null-terminated string. // // The function template achieves null-termination by recursively calling // the function and supplying it with the result of 'flatten' invoked on // the deduced argument. This 'flatten' invocation will call 'c_str()' on // various supported 'string' types, will produce a temporary 'bsl::string' // for possibly non-null-terminated 'bslstl::StringRef', and will result in // a 'BSLMF_ASSERT' for any unsupported type. Calling the function with // the temporary 'bsl::string' produced from 'bslstl::StringRef' will // result in a second invocation of 'flatten', this time producing // 'const char *', and finally calling the function with a null-terminated // string. // // Note that the 'bslstl::StringRef' overload for 'flatten' is provided for // backwards compatibility. Without it, the 'bsl::string' and // 'std::string' overloads would be ambiguous. In new code, it is // preferable to not provide 'bslstl::StringRef' overload in a similar // facility and require the clients to explicitly state the string type in // their code, making a potential allocation obvious. The // 'bsl::string_view' overload is not provided for the same reason. // CLASS METHODS static const char *flatten(char *cString); static const char *flatten(const char *cString); // Return the specified 'cString'. static const char *flatten(const bsl::string& string); static const char *flatten(const std::string& string); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static const char *flatten(const std::pmr::string& string); #endif // Return the result of invoking 'c_str()' on the specified 'string'. static bsl::string flatten(const bslstl::StringRef& stringRef); // Return a temporary 'bsl::string' constructed from the specified // 'stringRef'. template <class TYPE> static const char *flatten(const TYPE&); // Produce a compile-time error informing the caller that the // parameterized 'TYPE' is not supported as the parameter for the call. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------------- // class FilesystemUtil // -------------------- // CLASS METHODS template <class STRING_TYPE> inline FilesystemUtil::FileDescriptor FilesystemUtil::open( const STRING_TYPE& path, FileOpenPolicy openPolicy, FileIOPolicy ioPolicy, FileTruncatePolicy truncatePolicy) { return FilesystemUtil::open(FilesystemUtil_CStringUtil::flatten(path), openPolicy, ioPolicy, truncatePolicy); } template <class STRING_TYPE> inline int FilesystemUtil::setWorkingDirectory(const STRING_TYPE& path) { return FilesystemUtil::setWorkingDirectory( FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline bool FilesystemUtil::exists(const STRING_TYPE& path) { return FilesystemUtil::exists(FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline bool FilesystemUtil::isRegularFile(const STRING_TYPE& path, bool followLinksFlag) { return FilesystemUtil::isRegularFile( FilesystemUtil_CStringUtil::flatten(path), followLinksFlag); } template <class STRING_TYPE> inline bool FilesystemUtil::isDirectory(const STRING_TYPE& path, bool followLinksFlag) { return FilesystemUtil::isDirectory( FilesystemUtil_CStringUtil::flatten(path), followLinksFlag); } template <class STRING_TYPE> inline bool FilesystemUtil::isSymbolicLink(const STRING_TYPE& path) { return FilesystemUtil::isSymbolicLink( FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline int FilesystemUtil::getLastModificationTime(bdlt::Datetime *time, const STRING_TYPE& path) { return FilesystemUtil::getLastModificationTime( time, FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline int FilesystemUtil::createDirectories( const STRING_TYPE& path, bool isLeafDirectoryFlag) { return FilesystemUtil::createDirectories( FilesystemUtil_CStringUtil::flatten(path), isLeafDirectoryFlag); } template <class STRING_TYPE> inline int FilesystemUtil::createPrivateDirectory(const STRING_TYPE& path) { return FilesystemUtil::createPrivateDirectory( FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline int FilesystemUtil::visitPaths( const STRING_TYPE& pattern, const bsl::function<void(const char *path)>& visitor) { return FilesystemUtil::visitPaths( FilesystemUtil_CStringUtil::flatten(pattern), visitor); } template <class STRING_TYPE> inline int FilesystemUtil::findMatchingPaths(bsl::vector<bsl::string> *result, const STRING_TYPE& pattern) { return FilesystemUtil::findMatchingPaths( result, FilesystemUtil_CStringUtil::flatten(pattern)); } template <class STRING_TYPE> inline int FilesystemUtil::findMatchingPaths(std::vector<std::string> *result, const STRING_TYPE& pattern) { return FilesystemUtil::findMatchingPaths( result, FilesystemUtil_CStringUtil::flatten(pattern)); } #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR template <class STRING_TYPE> inline int FilesystemUtil::findMatchingPaths( std::pmr::vector<std::pmr::string> *result, const STRING_TYPE& pattern) { return FilesystemUtil::findMatchingPaths( result, FilesystemUtil_CStringUtil::flatten(pattern)); } #endif template <class STRING_TYPE> inline FilesystemUtil::Offset FilesystemUtil::getAvailableSpace( const STRING_TYPE& path) { return FilesystemUtil::getAvailableSpace( FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline FilesystemUtil::Offset FilesystemUtil::getFileSize(const STRING_TYPE& path) { return FilesystemUtil::getFileSize( FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline int FilesystemUtil::getSymbolicLinkTarget(bsl::string *result, const STRING_TYPE& path) { return FilesystemUtil::getSymbolicLinkTarget( result, FilesystemUtil_CStringUtil::flatten(path)); } template <class STRING_TYPE> inline int FilesystemUtil::getSymbolicLinkTarget(std::string *result, const STRING_TYPE& path) { return FilesystemUtil::getSymbolicLinkTarget( result, FilesystemUtil_CStringUtil::flatten(path)); } #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR template <class STRING_TYPE> inline int FilesystemUtil::getSymbolicLinkTarget(std::pmr::string *result, const STRING_TYPE& path) { return FilesystemUtil::getSymbolicLinkTarget( result, FilesystemUtil_CStringUtil::flatten(path)); } #endif template <class STRING_TYPE> inline int FilesystemUtil::remove(const STRING_TYPE& path, bool recursiveFlag) { return FilesystemUtil::remove(FilesystemUtil_CStringUtil::flatten(path), recursiveFlag); } template <class OLD_STRING_TYPE, class NEW_STRING_TYPE> inline int FilesystemUtil::move(const OLD_STRING_TYPE& oldPath, const NEW_STRING_TYPE& newPath) { return FilesystemUtil::move(FilesystemUtil_CStringUtil::flatten(oldPath), FilesystemUtil_CStringUtil::flatten(newPath)); } // -------------------------------- // class FilesystemUtil_CStringUtil // -------------------------------- // CLASS METHODS inline const char *FilesystemUtil_CStringUtil::flatten(char *cString) { return cString; } inline const char *FilesystemUtil_CStringUtil::flatten(const char *cString) { return cString; } inline const char *FilesystemUtil_CStringUtil::flatten(const bsl::string& string) { return string.c_str(); } inline const char *FilesystemUtil_CStringUtil::flatten(const std::string& string) { return string.c_str(); } #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR inline const char *FilesystemUtil_CStringUtil::flatten(const std::pmr::string& string) { return string.c_str(); } #endif inline bsl::string FilesystemUtil_CStringUtil::flatten( const bslstl::StringRef& stringRef) { return stringRef; } template <class TYPE> inline const char *FilesystemUtil_CStringUtil::flatten(const TYPE&) { BSLMF_ASSERT(("Unsupported parameter type." && !sizeof(TYPE))); return 0; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 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 ----------------------------------