You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2304 lines
74 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/filesystem/filesystem_traits.hpp
  3. *
  4. * Purpose: Contains the filesystem_traits template class, and ANSI and
  5. * Unicode specialisations thereof.
  6. *
  7. * Created: 15th November 2002
  8. * Updated: 13th August 2011
  9. *
  10. * Home: http://stlsoft.org/
  11. *
  12. * Copyright (c) 2002-2011, Matthew Wilson and Synesis Software
  13. * All rights reserved.
  14. *
  15. * Redistribution and use in source and binary forms, with or without
  16. * modification, are permitted provided that the following conditions are
  17. * met:
  18. *
  19. * - Redistributions of source code must retain the above copyright notice,
  20. * this list of conditions and the following disclaimer.
  21. * - Redistributions in binary form must reproduce the above copyright
  22. * notice, this list of conditions and the following disclaimer in the
  23. * documentation and/or other materials provided with the distribution.
  24. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the
  25. * names of any contributors may be used to endorse or promote products
  26. * derived from this software without specific prior written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  29. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  30. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  31. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  32. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  33. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  34. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  35. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  36. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  37. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * ////////////////////////////////////////////////////////////////////// */
  41. /** \file winstl/filesystem/filesystem_traits.hpp
  42. *
  43. * \brief [C++ only] Definition of the winstl::filesystem_traits traits
  44. * class
  45. * (\ref group__library__filesystem "File System" Library).
  46. */
  47. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  48. #define WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  49. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  50. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 4
  51. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 10
  52. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 3
  53. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 131
  54. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  55. /* /////////////////////////////////////////////////////////////////////////
  56. * Includes
  57. */
  58. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  59. # include <winstl/winstl.h>
  60. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  61. #ifdef WINSTL_OS_IS_WIN64
  62. # define _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  63. #endif /* _WIN64 || _M_??64 */
  64. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  65. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  66. # ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_CAST
  67. # include <stlsoft/conversion/truncation_cast.hpp>
  68. # endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_CAST */
  69. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  70. # ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_TEST
  71. # include <stlsoft/conversion/truncation_test.hpp>
  72. # endif /* !STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_TEST */
  73. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  74. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  75. #ifndef STLSOFT_INCL_STLSOFT_HPP_MEMORY_AUTO_BUFFER
  76. # include <stlsoft/memory/auto_buffer.hpp>
  77. #endif /* !STLSOFT_INCL_STLSOFT_HPP_MEMORY_AUTO_BUFFER */
  78. #ifndef WINSTL_INCL_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS
  79. # include <winstl/system/system_traits.hpp>
  80. #endif /* !WINSTL_INCL_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS */
  81. #ifndef STLSOFT_INCL_H_CTYPE
  82. # define STLSOFT_INCL_H_CTYPE
  83. # include <ctype.h>
  84. #endif /* !STLSOFT_INCL_H_CTYPE */
  85. #ifndef STLSOFT_INCL_H_STRING
  86. # define STLSOFT_INCL_H_STRING
  87. # include <string.h>
  88. #endif /* !STLSOFT_INCL_H_STRING */
  89. #ifndef STLSOFT_INCL_H_WCHAR
  90. # define STLSOFT_INCL_H_WCHAR
  91. # include <wchar.h>
  92. #endif /* !STLSOFT_INCL_H_WCHAR */
  93. #ifndef STLSOFT_INCL_H_WCTYPE
  94. # define STLSOFT_INCL_H_WCTYPE
  95. # include <wctype.h>
  96. #endif /* !STLSOFT_INCL_H_WCTYPE */
  97. /* /////////////////////////////////////////////////////////////////////////
  98. * FindVolume API declarations
  99. *
  100. * The FindVolume API is not visible in the Windows headers unless _WIN32_WINNT
  101. * is defined as 0x0500 or greater. Where this definition is not present, the
  102. * functions are declared here, unless _WINSTL_NO_FINDVOLUME_API is defined.
  103. *
  104. * Where _WINSTL_NO_FINDVOLUME_API is defined, the requisite members of the
  105. * traits classes are undeclared.
  106. */
  107. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  108. #if !defined(_WINSTL_NO_FINDVOLUME_API)
  109. # if !defined(_WIN32_WINNT) || \
  110. (_WIN32_WINNT < 0x0500) || \
  111. !defined(FindFirstVolume) || \
  112. !defined(FindNextVolume)
  113. # define WINSTL_FINDVOLUME_API_NOT_DECLARED
  114. HANDLE WINAPI FindFirstVolumeA(
  115. LPSTR lpszVolumeName, // output buffer
  116. DWORD cchBufferLength // size of output buffer
  117. );
  118. HANDLE WINAPI FindFirstVolumeW(
  119. LPWSTR lpszVolumeName, // output buffer
  120. DWORD cchBufferLength // size of output buffer
  121. );
  122. BOOL WINAPI FindNextVolumeA(
  123. HANDLE hFindVolume, // volume search handle
  124. LPSTR lpszVolumeName, // output buffer
  125. DWORD cchBufferLength // size of output buffer
  126. );
  127. BOOL WINAPI FindNextVolumeW(
  128. HANDLE hFindVolume, // volume search handle
  129. LPWSTR lpszVolumeName, // output buffer
  130. DWORD cchBufferLength // size of output buffer
  131. );
  132. BOOL WINAPI FindVolumeClose(
  133. HANDLE hFindVolume
  134. );
  135. # endif
  136. # endif /* !_WINSTL_NO_FINDVOLUME_API */
  137. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  138. /* /////////////////////////////////////////////////////////////////////////
  139. * Namespace
  140. */
  141. #ifndef _WINSTL_NO_NAMESPACE
  142. # if defined(_STLSOFT_NO_NAMESPACE) || \
  143. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  144. /* There is no stlsoft namespace, so must define ::winstl */
  145. namespace winstl
  146. {
  147. # else
  148. /* Define stlsoft::winstl_project */
  149. namespace stlsoft
  150. {
  151. namespace winstl_project
  152. {
  153. # endif /* _STLSOFT_NO_NAMESPACE */
  154. #endif /* !_WINSTL_NO_NAMESPACE */
  155. /* /////////////////////////////////////////////////////////////////////////
  156. * Classes
  157. */
  158. #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
  159. /** \brief Traits for accessing the correct file-system functions for a given character type
  160. *
  161. * \ingroup group__library__filesystem
  162. *
  163. * filesystem_traits is a traits class for determining the correct file-system
  164. * structures and functions for a given character type.
  165. *
  166. * \param C The character type (e.g. \c char, \c wchar_t)
  167. */
  168. template <ss_typename_param_k C>
  169. struct filesystem_traits
  170. : public system_traits<C>
  171. {
  172. /// \name Types
  173. /// @{
  174. private:
  175. typedef system_traits<C> parent_class_type;
  176. public:
  177. /// \brief The character type
  178. typedef C char_type;
  179. /// \brief The size type
  180. typedef ws_size_t size_type;
  181. /// \brief The difference type
  182. typedef ws_ptrdiff_t difference_type;
  183. /// \brief The find data type
  184. typedef WIN32_FIND_DATA find_data_type; // Placeholder only
  185. /// \brief The stat data type
  186. typedef WIN32_FIND_DATA stat_data_type;
  187. /// \brief The fstat data type
  188. typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
  189. /// \brief The current instantion of the type
  190. typedef filesystem_traits<C> class_type;
  191. /// \brief The (signed) integer type
  192. typedef ws_int_t int_type;
  193. /// \brief The Boolean type
  194. typedef ws_bool_t bool_type;
  195. /// \brief The type of a system file handle
  196. typedef HANDLE file_handle_type;
  197. /// \brief The type of a handle to a dynamically loaded module
  198. typedef HINSTANCE module_type;
  199. /// \brief The type of system error codes
  200. typedef DWORD error_type;
  201. /// @}
  202. /// \name Member Constants
  203. /// @{
  204. public:
  205. enum
  206. {
  207. maxPathLength = WINSTL_CONST_MAX_PATH //!< The maximum length of a path for the current file system
  208. };
  209. enum
  210. {
  211. pathComparisonIsCaseSensitive = false
  212. };
  213. /// @}
  214. /// \name General string handling
  215. /// @{
  216. public:
  217. /// Compares the contents of \c src and \c dest, according to the
  218. /// lexicographical ordering on the host operating system.
  219. static int_type str_fs_compare(char_type const* s1, char_type const* s2);
  220. /// Compares the contents of \c src and \c dest up to \c cch
  221. /// characters. according to the lexicographical ordering on the host
  222. /// operating system.
  223. static int_type str_fs_n_compare(char_type const* s1, char_type const* s2, size_type cch);
  224. /// @}
  225. /// \name File-system entry names
  226. /// @{
  227. public:
  228. /// \brief Appends a path name separator to \c dir if one does not exist
  229. ///
  230. /// \see \link #path_name_separator path_name_separator() \endlink
  231. static char_type* ensure_dir_end(char_type* dir);
  232. /// \brief Removes the path name separator from the end of \c dir, if it has it
  233. ///
  234. /// \see \link #path_name_separator path_name_separator() \endlink
  235. static char_type* remove_dir_end(char_type* dir);
  236. /// \brief Returns \c true if \c dir has trailing path name separator
  237. ///
  238. /// \see \link #path_name_separator path_name_separator() \endlink
  239. static bool_type has_dir_end(char_type const* dir);
  240. /// \brief Returns \c true if dir is \c "." or \c ".."
  241. static bool_type is_dots(char_type const* dir);
  242. /// \brief Returns \c true if path is rooted, i.e. it begins with root directory
  243. ///
  244. /// \note Only enough characters of the path pointed to by \c path as are
  245. /// necessary to detect the presence or absence of the operating system's
  246. /// root character sequence(s).
  247. static bool_type is_path_rooted(char_type const* path);
  248. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  249. static bool_type is_path_rooted(
  250. char_type const* path
  251. , size_t cchPath
  252. );
  253. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  254. /// \brief Returns \c true if path is an absolute path
  255. ///
  256. /// \note Only enough characters of the path pointed to by \c path as are
  257. /// necessary to detect the presence or absence of the operating system's
  258. /// absolute path character sequence(s).
  259. static bool_type is_path_absolute(char_type const* path);
  260. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  261. static bool_type is_path_absolute(
  262. char_type const* path
  263. , size_t cchPath
  264. );
  265. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  266. /// \brief Returns \c true if path is a UNC path
  267. ///
  268. /// \note Only enough characters of the path pointed to by \c path as are
  269. /// necessary to detect the presence or absence of the UNC character sequence(s).
  270. static bool_type is_path_UNC(char_type const* path);
  271. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  272. static bool_type is_path_UNC(
  273. char_type const* path
  274. , size_t cchPath
  275. );
  276. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  277. /// \brief Indicates whether the given path is the root designator.
  278. ///
  279. /// The root designator is one of the following:
  280. /// - the slash character <code>/</code>
  281. /// - the backslash character <code>\\</code>
  282. /// - a drive specification, e.g. <code>H:\\</code> or <code>H:/</code>
  283. /// - a UNC host, e.g. <code>H:\\\\host</code> or <code>H:\\\\host\\</code>
  284. ///
  285. /// The function returns false if the path contains any part of a
  286. /// file name (or extension), directory, or share.
  287. static bool_type is_root_designator(char_type const* path);
  288. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  289. static bool_type is_root_designator(
  290. char_type const* path
  291. , size_t cchPath
  292. );
  293. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  294. /// \brief Returns \c true if the character is a path-name separator
  295. ///
  296. /// \note Both \c / and \c \\ are interpreted as a path name separator
  297. static bool_type is_path_name_separator(char_type ch);
  298. /// \brief Returns the path separator
  299. ///
  300. /// This is the separator that is used to separate multiple paths on the operating system. On UNIX it is ':'
  301. static char_type path_separator();
  302. /// \brief Returns the path name separator
  303. ///
  304. /// This is the separator that is used to separate parts of a path on the operating system. On UNIX it is '/'
  305. static char_type path_name_separator();
  306. /// \brief Returns the wildcard pattern that represents all possible matches
  307. ///
  308. /// \note On Win32 it is '*.*'
  309. static char_type const* pattern_all();
  310. /// \brief The maximum length of a path on the file-system
  311. ///
  312. /// \note Because not all systems support fixed maximum path lengths, the value of this function is notionally dynamic
  313. static size_type path_max();
  314. /// \brief Gets the full path name into the given buffer, returning a pointer to the file-part
  315. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile);
  316. /// \brief Gets the full path name into the given buffer
  317. static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer);
  318. /// \brief Gets the full path name into the given buffer
  319. ///
  320. /// \deprecated The other overload is now the preferred form
  321. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer);
  322. /// \brief Gets the short path name into the given buffer
  323. ///
  324. /// \deprecated The other overload is now the preferred form
  325. static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer);
  326. /// \brief Gets the short path name into the given buffer
  327. static size_type get_short_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer);
  328. /// @}
  329. /// \name File-system enumeration
  330. /// @{
  331. public:
  332. // FindFirstFile/FindNextFile API
  333. /// \brief Initiate a file-system search
  334. static HANDLE find_first_file(char_type const* spec, find_data_type* findData);
  335. #if _WIN32_WINNT >= 0x0400
  336. /// \brief Initiate a file-system search - NT4+-only
  337. static HANDLE find_first_file_ex(char_type const* spec, FINDEX_SEARCH_OPS flags, find_data_type* findData);
  338. #endif /* _WIN32_WINNT >= 0x0400 */
  339. /// \brief Advance a given file-system search
  340. static bool_type find_next_file(HANDLE h, find_data_type* findData);
  341. /// \brief Closes the handle of the file-system search
  342. static void find_file_close(HANDLE h);
  343. // FindFirstVolume/FindNextVolume API
  344. #ifndef _WINSTL_NO_FINDVOLUME_API
  345. /// \brief Initiate a file-system volume search
  346. static HANDLE find_first_volume(char_type* volume_name, size_type cch_volume_name);
  347. /// \brief Advance a given file-system volume search
  348. static bool_type find_next_volume(HANDLE h, char_type* volume_name, size_type cch_volume_name);
  349. /// \brief Closes the handle of the file-volume search
  350. static void find_volume_close(HANDLE h);
  351. #endif // !_WINSTL_NO_FINDVOLUME_API
  352. /// @}
  353. /// \name File-system control
  354. /// @{
  355. public:
  356. /// \brief Sets the current directory to \c dir
  357. static bool_type set_current_directory(char_type const* dir);
  358. /// \brief Retrieves the name of the current directory into \c buffer up to a maximum of \c cchBuffer characters
  359. ///
  360. /// \deprecated The other overload is now the preferred form
  361. static size_type get_current_directory(size_type cchBuffer, char_type* buffer);
  362. /// \brief Retrieves the name of the current directory into \c buffer up to a maximum of \c cchBuffer characters
  363. static size_type get_current_directory(char_type* buffer, size_type cchBuffer);
  364. /// @}
  365. /// \name File-system state
  366. /// @{
  367. public:
  368. /// \brief Returns whether a file exists or not
  369. static bool_type file_exists(char_type const* path);
  370. /// \brief Returns whether the given path represents a file
  371. static bool_type is_file(char_type const* path);
  372. /// \brief Returns whether the given path represents a directory
  373. static bool_type is_directory(char_type const* path);
  374. /// \brief Gets the information for a particular file system entry
  375. static bool_type stat(char_type const* path, stat_data_type* stat_data);
  376. /// \brief Gets the information for a particular open file
  377. static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data);
  378. /// \brief Returns whether the given stat info represents a file
  379. static bool_type is_file(stat_data_type const* stat_data);
  380. static bool_type is_file(fstat_data_type const* stat_data);
  381. /// \brief Returns whether the given stat info represents a directory
  382. static bool_type is_directory(stat_data_type const* stat_data);
  383. static bool_type is_directory(fstat_data_type const* stat_data);
  384. /// \brief Returns whether the given stat info represents a link
  385. static bool_type is_link(stat_data_type const* stat_data);
  386. static bool_type is_link(fstat_data_type const* stat_data);
  387. /// \brief Returns whether the given stat info represents a read-only entry
  388. static bool_type is_readonly(stat_data_type const* stat_data);
  389. static bool_type is_readonly(fstat_data_type const* stat_data);
  390. /// \brief Indicates whether the given drive currently exists on the system
  391. static bool_type drive_exists(char_type driveLetter);
  392. /// \brief Returns a status code denoting the type of the drive
  393. ///
  394. /// \return One of the return codes of the GetDriveType() API function
  395. static DWORD get_drive_type(char_type driveLetter);
  396. /// @}
  397. /// \name File-system control
  398. /// @{
  399. public:
  400. /// \brief Creates a directory
  401. static bool_type create_directory(char_type const* dir);
  402. /// \brief Creates a directory, with the given security attributes
  403. static bool_type create_directory(char_type const* dir, LPSECURITY_ATTRIBUTES lpsa);
  404. /// \brief Deletes a directory
  405. static bool_type remove_directory(char_type const* dir);
  406. /// \brief Delete a file
  407. static bool_type unlink_file(char_type const* file);
  408. /// \brief Delete a file
  409. ///
  410. /// \deprecated Users should use unlink_file()
  411. static bool_type delete_file(char_type const* file);
  412. /// \brief Rename a file
  413. static bool_type rename_file(char_type const* currentName, char_type const* newName);
  414. /// \brief Copy a file
  415. static bool_type copy_file(char_type const* sourceName, char_type const* newName, bool_type bFailIfExists = false);
  416. /// The value returned by create_file() that indicates that the
  417. /// operation failed
  418. static file_handle_type invalid_file_handle_value();
  419. /// \brief Create / open a file
  420. static file_handle_type create_file(char_type const* fileName, size_type desiredAccess, size_type shareMode, LPSECURITY_ATTRIBUTES sa, size_type creationDisposition, size_type flagAndAttributes, HANDLE hTemplateFile);
  421. /// \brief Closes the given file handle
  422. static bool_type close_file(file_handle_type h);
  423. #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
  424. /// \brief Gets the size of the file
  425. static ws_uint64_t get_file_size(file_handle_type h);
  426. /// \brief Gets the size of the file
  427. static ws_uint64_t get_file_size(stat_data_type const& sd);
  428. /// \brief Gets the size of the file
  429. ///
  430. /// \pre (NULL != psd)
  431. static ws_uint64_t get_file_size(stat_data_type const* psd);
  432. #else /* STLSOFT_CF_64BIT_INT_SUPPORT */
  433. private:
  434. /// Not currently supported
  435. static void get_file_size(stat_data_type const*);
  436. /// Not currently supported
  437. static void get_file_size(stat_data_type const&);
  438. #endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
  439. /// @}
  440. };
  441. #else /* ? STLSOFT_DOCUMENTATION_SKIP_SECTION */
  442. template <ss_typename_param_k C>
  443. struct filesystem_traits;
  444. struct filesystem_traits_
  445. : public system_traits_
  446. {
  447. public:
  448. typedef ws_size_t size_type;
  449. typedef ws_ptrdiff_t difference_type;
  450. typedef filesystem_traits_ class_type;
  451. typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
  452. typedef ws_int_t int_type;
  453. typedef ws_bool_t bool_type;
  454. typedef HANDLE file_handle_type;
  455. typedef HINSTANCE module_type;
  456. typedef DWORD error_type;
  457. enum
  458. {
  459. maxPathLength = WINSTL_CONST_MAX_PATH //!< The maximum length of a path for the current file system
  460. };
  461. enum
  462. {
  463. pathComparisonIsCaseSensitive = false
  464. };
  465. public:
  466. static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data)
  467. {
  468. return FALSE != ::GetFileInformationByHandle(fd, fstat_data);
  469. }
  470. static bool_type is_file(fstat_data_type const* stat_data)
  471. {
  472. return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  473. }
  474. static bool_type is_directory(fstat_data_type const* stat_data)
  475. {
  476. return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  477. }
  478. static bool_type is_link(fstat_data_type const* /* stat_data */)
  479. {
  480. return false;
  481. }
  482. static bool_type is_readonly(fstat_data_type const* stat_data)
  483. {
  484. return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
  485. }
  486. #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
  487. static ws_uint64_t get_file_size(file_handle_type h)
  488. {
  489. DWORD dwHigh;
  490. DWORD dwLow = ::GetFileSize(h, &dwHigh);
  491. if( 0xFFFFFFFF == dwLow &&
  492. ERROR_SUCCESS != ::GetLastError())
  493. {
  494. dwHigh = 0xFFFFFFFF;
  495. }
  496. return (static_cast<ws_uint64_t>(dwHigh) << 32) | dwLow;
  497. }
  498. #endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
  499. };
  500. STLSOFT_TEMPLATE_SPECIALISATION
  501. struct filesystem_traits<ws_char_a_t>
  502. : public system_traits<ws_char_a_t>
  503. {
  504. public:
  505. typedef ws_char_a_t char_type;
  506. typedef ws_size_t size_type;
  507. typedef ws_ptrdiff_t difference_type;
  508. typedef WIN32_FIND_DATAA find_data_type;
  509. typedef WIN32_FIND_DATAA stat_data_type;
  510. typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
  511. typedef filesystem_traits<char_type> class_type;
  512. typedef ws_int_t int_type;
  513. typedef ws_bool_t bool_type;
  514. typedef HANDLE file_handle_type;
  515. typedef HINSTANCE module_type;
  516. typedef DWORD error_type;
  517. private:
  518. #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  519. _MSC_VER >= 1200
  520. typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_type_;
  521. #endif /* compiler */
  522. public:
  523. enum
  524. {
  525. maxPathLength = WINSTL_CONST_MAX_PATH //!< The maximum length of a path for the current file system
  526. };
  527. enum
  528. {
  529. pathComparisonIsCaseSensitive = false
  530. };
  531. public:
  532. static int_type str_fs_compare(char_type const* s1, char_type const* s2)
  533. {
  534. return str_compare_no_case(s1, s2);
  535. }
  536. static int_type str_fs_n_compare(char_type const* s1, char_type const* s2, size_type cch)
  537. {
  538. return str_n_compare_no_case(s1, s2, cch);
  539. }
  540. static char_type* ensure_dir_end(char_type* dir)
  541. {
  542. WINSTL_ASSERT(NULL != dir);
  543. char_type* end = str_end(dir);
  544. if( dir < end &&
  545. !is_path_name_separator(*(end - 1)))
  546. {
  547. *end = path_name_separator();
  548. *(end + 1) = '\0';
  549. }
  550. return dir;
  551. }
  552. static char_type* remove_dir_end(char_type* dir)
  553. {
  554. WINSTL_ASSERT(NULL != dir);
  555. // Don't trim drive roots ...
  556. if( isalpha(dir[0]) &&
  557. ':' == dir[1] &&
  558. is_path_name_separator(dir[2]) &&
  559. '\0' == dir[3])
  560. {
  561. return dir;
  562. }
  563. // ... or UNC roots
  564. if( '\\' == dir[0] &&
  565. '\\' == dir[1] &&
  566. '\0' == dir[3])
  567. {
  568. return dir;
  569. }
  570. char_type* end = str_end(dir);
  571. if( dir < end &&
  572. is_path_name_separator(*(end - 1)))
  573. {
  574. *(end - 1) = '\0';
  575. }
  576. return dir;
  577. }
  578. static bool_type has_dir_end(char_type const* dir)
  579. {
  580. WINSTL_ASSERT(NULL != dir);
  581. size_type len = str_len(dir);
  582. return (0 < len) && is_path_name_separator(dir[len - 1]);
  583. }
  584. static bool_type is_dots(char_type const* dir)
  585. {
  586. WINSTL_ASSERT(NULL != dir);
  587. return dir[0] == '.' &&
  588. ( dir[1] == '\0' ||
  589. ( dir[1] == '.' &&
  590. dir[2] == '\0'));
  591. }
  592. static bool_type is_path_rooted(char_type const* path)
  593. {
  594. WINSTL_ASSERT(NULL != path);
  595. return is_path_name_separator(*path) || is_path_absolute(path);
  596. }
  597. static bool_type is_path_rooted(
  598. char_type const* path
  599. , size_t cchPath
  600. )
  601. {
  602. return (0 != cchPath && is_path_name_separator(*path)) || is_path_absolute(path, cchPath);
  603. }
  604. static bool_type is_path_absolute(char_type const* path)
  605. {
  606. WINSTL_ASSERT(NULL != path);
  607. return is_path_absolute(path, str_len(path));
  608. }
  609. static bool_type is_path_absolute(
  610. char_type const* path
  611. , size_t cchPath
  612. )
  613. {
  614. if(is_path_UNC(path, cchPath))
  615. {
  616. return true;
  617. }
  618. if(cchPath >= 3)
  619. {
  620. if( isalpha(path[0]) &&
  621. ':' == path[1] &&
  622. is_path_name_separator(path[2]))
  623. {
  624. return true;
  625. }
  626. }
  627. return false;
  628. }
  629. static bool_type is_path_UNC(char_type const* path)
  630. {
  631. WINSTL_ASSERT(NULL != path);
  632. return ('\\' == path[0] && '\\' == path[1]);
  633. }
  634. static bool_type is_path_UNC(
  635. char_type const* path
  636. , size_t cchPath
  637. )
  638. {
  639. switch(cchPath)
  640. {
  641. case 0:
  642. case 1:
  643. return false;
  644. default:
  645. return '\\' == path[0] && '\\' == path[1];
  646. }
  647. }
  648. private:
  649. // Determines whether the given path is a properly-formed drive:
  650. //
  651. // "X:\"
  652. //
  653. static bool_type is_root_drive_(
  654. char_type const* path
  655. , size_type cchPath
  656. )
  657. {
  658. if(3 == cchPath)
  659. {
  660. if( isalpha(path[0]) &&
  661. ':' == path[1] &&
  662. is_path_name_separator(path[2]))
  663. {
  664. return true;
  665. }
  666. }
  667. return false;
  668. }
  669. // Determines whether the given path is a UNC root:
  670. //
  671. // "\\"
  672. //
  673. static bool_type is_root_UNC_(
  674. char_type const* path
  675. , size_type cchPath
  676. )
  677. {
  678. if(2 == cchPath)
  679. {
  680. if( '\\' == path[0] &&
  681. '\\' == path[1])
  682. {
  683. return true;
  684. }
  685. }
  686. return false;
  687. }
  688. // Determines whether the given path is a directory root:
  689. //
  690. // "\"
  691. //
  692. // or:
  693. //
  694. // "/"
  695. //
  696. static bool_type is_root_directory_(
  697. char_type const* path
  698. , size_type cchPath
  699. )
  700. {
  701. if(1 == cchPath)
  702. {
  703. if(is_path_name_separator(path[0]))
  704. {
  705. return true;
  706. }
  707. }
  708. return false;
  709. }
  710. public:
  711. static bool_type is_root_designator(char_type const* path)
  712. {
  713. WINSTL_ASSERT(NULL != path);
  714. size_type const cchPath = str_len(path);
  715. return is_root_directory_(path, cchPath) || is_root_drive_(path, cchPath) || is_root_UNC_(path, cchPath);
  716. }
  717. #if 0
  718. static bool_type is_root_designator(
  719. char_type const* path
  720. , size_t cchPath
  721. )
  722. {
  723. return is_root_directory_(path, cchPath) || is_root_drive_(path, cchPath) || is_root_UNC_(path, cchPath);
  724. }
  725. #endif /* 0 */
  726. static bool_type is_path_name_separator(char_type ch)
  727. {
  728. return '\\' == ch || '/' == ch;
  729. }
  730. static char_type path_separator()
  731. {
  732. return ';';
  733. }
  734. static char_type path_name_separator()
  735. {
  736. return '\\';
  737. }
  738. static char_type const* pattern_all()
  739. {
  740. return "*.*";
  741. }
  742. static size_type path_max()
  743. {
  744. return WINSTL_CONST_MAX_PATH;
  745. }
  746. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  747. _MSC_VER < 1200
  748. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  749. {
  750. WINSTL_MESSAGE_ASSERT("GetFullPathNameW() will crash when the file-name and buffer parameters are the same, so it's not a good idea to do this for ANSI compilation", fileName != buffer);
  751. if('"' == *fileName)
  752. {
  753. // This can only work if ...
  754. const size_type len = class_type::str_len(fileName);
  755. char_type const* const closing = class_type::str_chr(fileName + 1, '"');
  756. // ... 1. the only other double quote is at the end of the string, and ...
  757. if( NULL != closing &&
  758. closing - fileName == static_cast<ws_ptrdiff_t>(len - 1))
  759. {
  760. size_type res = class_type::get_full_path_name(fileName + 1, cchBuffer, buffer, ppFile);
  761. // ... 2. the front-quote skipped string can be converted, and ...
  762. if( 0 != res &&
  763. res < cchBuffer)
  764. {
  765. WINSTL_ASSERT('\0' == buffer[res]);
  766. char_type* const closing2 = class_type::str_chr(buffer, '"');
  767. // ... 3. the front-quote skipped converted string contains a single trailing quote
  768. if( NULL != closing2 &&
  769. closing2 - buffer == static_cast<ws_ptrdiff_t>(res - 1))
  770. {
  771. buffer[res-- - 1] = '\0';
  772. return res;
  773. }
  774. }
  775. }
  776. }
  777. return ::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
  778. }
  779. #else /* ? compiler */
  780. private:
  781. static size_type get_full_path_name_impl2(char_type const* fileName, size_type len, char_type* buffer, size_type cchBuffer, char_type** ppFile)
  782. {
  783. size_type r = class_type::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
  784. if( 0 != r &&
  785. NULL != buffer &&
  786. r > cchBuffer)
  787. {
  788. buffer_type_ buffer_(1 + r);
  789. if(0 == buffer_.size())
  790. {
  791. *ppFile = NULL;
  792. return 0;
  793. }
  794. else
  795. {
  796. char_type* pFile2;
  797. size_type r2 = get_full_path_name_impl2(fileName, len, &buffer_[0], buffer_.size(), &pFile2);
  798. if(0 == r2)
  799. {
  800. return 0;
  801. }
  802. else
  803. {
  804. if(r2 > cchBuffer)
  805. {
  806. r2 = cchBuffer;
  807. }
  808. ::memcpy(&buffer[0], &buffer_[0], sizeof(char_type) * r2);
  809. if( NULL != pFile2 &&
  810. r2 == (r - 1) &&
  811. static_cast<size_type>(pFile2 - &buffer_[0]) < r2)
  812. {
  813. *ppFile = &buffer[0] + (pFile2 - &buffer_[0]);
  814. }
  815. else
  816. {
  817. *ppFile = NULL;
  818. }
  819. return r2;
  820. }
  821. }
  822. }
  823. else
  824. {
  825. #if 0
  826. DWORD dw = ::GetLastError();
  827. if( 0 == r &&
  828. 0 == dw &&
  829. str_len(fileName) > WINSTL_CONST_MAX_PATH)
  830. {
  831. ::SetLastError(ERROR_FILENAME_EXCED_RANGE);
  832. }
  833. #endif /* 0 */
  834. return r;
  835. }
  836. }
  837. static size_type get_full_path_name_impl(char_type const* fileName, size_type len, char_type* buffer, size_type cchBuffer, char_type** ppFile)
  838. {
  839. WINSTL_ASSERT(len > 0);
  840. if('\0' != fileName[len])
  841. {
  842. buffer_type_ fileName_(1 + (len - 1));
  843. // May be being compiled absent exception support, so need to check the
  844. // file path buffers. (This _could_ be done with a compile-time #ifdef,
  845. // but it's best not, since some translators support exceptions but yet
  846. // don't throw on mem exhaustion, and in any case a user could change
  847. // ::new)
  848. if(0 == fileName_.size())
  849. {
  850. set_last_error(ERROR_OUTOFMEMORY);
  851. return 0;
  852. }
  853. else
  854. {
  855. fileName_[len] = '\0';
  856. return get_full_path_name_impl( static_cast<char_type*>(::memcpy(&fileName_[0], fileName, sizeof(char_type) * len))
  857. , len
  858. , buffer
  859. , cchBuffer
  860. , ppFile);
  861. }
  862. }
  863. else
  864. {
  865. return get_full_path_name_impl2(fileName, len, buffer, cchBuffer, ppFile);
  866. }
  867. }
  868. public:
  869. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  870. {
  871. WINSTL_MESSAGE_ASSERT("GetFullPathNameW() will crash when the file-name and buffer parameters are the same, so it's not a good idea to do this for ANSI compilation", fileName != buffer);
  872. size_type n = 0;
  873. const size_type len = class_type::str_len(fileName);
  874. if(NULL != class_type::str_pbrk(fileName, "<>|*?"))
  875. {
  876. ::SetLastError(ERROR_INVALID_NAME);
  877. return 0;
  878. }
  879. if('"' == *fileName)
  880. {
  881. // This can only work if:
  882. //
  883. // - the only other double-quote is at the end of the string
  884. // - the unquoted form successfully converts
  885. char_type const* const closing = class_type::str_chr(fileName + 1, '"');
  886. if( NULL == closing ||
  887. static_cast<size_type>(closing - fileName) != len - 1)
  888. {
  889. set_last_error(ERROR_INVALID_DATA);
  890. }
  891. else
  892. {
  893. size_type r;
  894. if(NULL == buffer)
  895. {
  896. r = get_full_path_name_impl(fileName, len, NULL, 0, ppFile);
  897. if(0 != r)
  898. {
  899. n = 2 + r;
  900. }
  901. }
  902. else if(cchBuffer == 0)
  903. {
  904. n = 0;
  905. *ppFile = NULL;
  906. }
  907. else if(cchBuffer == 1)
  908. {
  909. // Have to check it's valid
  910. r = get_full_path_name_impl(fileName, len, NULL, 0, ppFile);
  911. if(0 != r)
  912. {
  913. buffer[0] = '"';
  914. n = 1;
  915. *ppFile = NULL;
  916. }
  917. }
  918. else
  919. {
  920. r = get_full_path_name_impl(fileName + 1, len - 2, buffer + 1, cchBuffer - 1, ppFile);
  921. if(0 != r)
  922. {
  923. // Write the first quote character into the buffer
  924. buffer[0] = '"';
  925. if(r + 1 < cchBuffer)
  926. {
  927. // There's enough space for the result and the closing quote
  928. buffer[r + 1] = '"';
  929. if(r + 2 < cchBuffer)
  930. {
  931. // There's enough space for the result and the closing quote and the nul-terminator
  932. buffer[r + 2] = '\0';
  933. n = r + 2;
  934. }
  935. else
  936. {
  937. n = r + 2;
  938. }
  939. }
  940. else
  941. {
  942. n = r + 1;
  943. }
  944. }
  945. }
  946. }
  947. }
  948. else
  949. {
  950. n = get_full_path_name_impl(fileName, len, buffer, cchBuffer, ppFile);
  951. }
  952. // Paths that exceed _MAX_PATH (aka WINSTL_CONST_MAX_PATH) cause GetFullPathNameA() to fail, but it
  953. // does not (appear to) call SetLastError()
  954. if( 0 == n &&
  955. 0 == ::GetLastError() &&
  956. str_len(fileName) > WINSTL_CONST_MAX_PATH)
  957. {
  958. ::SetLastError(ERROR_FILENAME_EXCED_RANGE);
  959. }
  960. return n;
  961. }
  962. #endif /* compiler */
  963. static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  964. {
  965. WINSTL_ASSERT(NULL != fileName);
  966. char_type* pFile;
  967. if('\0' == *fileName)
  968. {
  969. static const char s_dot[2] = { '.', '\0' };
  970. fileName = s_dot;
  971. }
  972. return get_full_path_name(fileName, cchBuffer, buffer, &pFile);
  973. }
  974. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  975. {
  976. return get_full_path_name(fileName, buffer, cchBuffer);
  977. }
  978. static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  979. {
  980. return class_type::GetShortPathNameA(fileName, buffer, cchBuffer);
  981. }
  982. static size_type get_short_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  983. {
  984. return class_type::GetShortPathNameA(fileName, buffer, cchBuffer);
  985. }
  986. // File-system enumeration
  987. static HANDLE find_first_file(char_type const* spec, find_data_type* findData)
  988. {
  989. return ::FindFirstFileA(spec, findData);
  990. }
  991. #if defined(_WIN32_WINNT) && \
  992. _WIN32_WINNT >= 0x0400
  993. static HANDLE find_first_file_ex(char_type const* spec, FINDEX_SEARCH_OPS flags, find_data_type* findData)
  994. {
  995. return ::FindFirstFileExA(spec, FindExInfoStandard, findData, flags, NULL, 0);
  996. }
  997. #endif /* _WIN32_WINNT >= 0x0400 */
  998. static bool_type find_next_file(HANDLE h, find_data_type* findData)
  999. {
  1000. return ::FindNextFileA(h, findData) != FALSE;
  1001. }
  1002. static void find_file_close(HANDLE h)
  1003. {
  1004. WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
  1005. ::FindClose(h);
  1006. }
  1007. #ifndef _WINSTL_NO_FINDVOLUME_API
  1008. static HANDLE find_first_volume(char_type* volume_name, size_type cch_volume_name)
  1009. {
  1010. return class_type::FindFirstVolumeA(volume_name, cch_volume_name);
  1011. }
  1012. static bool_type find_next_volume(HANDLE h, char_type* volume_name, size_type cch_volume_name)
  1013. {
  1014. return class_type::FindNextVolumeA(h, volume_name, cch_volume_name) != FALSE;
  1015. }
  1016. static void find_volume_close(HANDLE h)
  1017. {
  1018. WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
  1019. ::FindVolumeClose(h);
  1020. }
  1021. #endif // !_WINSTL_NO_FINDVOLUME_API
  1022. // File-system state
  1023. static bool_type set_current_directory(char_type const* dir)
  1024. {
  1025. return ::SetCurrentDirectoryA(dir) != FALSE;
  1026. }
  1027. static size_type get_current_directory(char_type* buffer, size_type cchBuffer)
  1028. {
  1029. return class_type::GetCurrentDirectoryA(cchBuffer, buffer);
  1030. }
  1031. static size_type get_current_directory(size_type cchBuffer, char_type* buffer)
  1032. {
  1033. return class_type::get_current_directory(buffer, cchBuffer);
  1034. }
  1035. static bool_type file_exists(char_type const* fileName)
  1036. {
  1037. return 0xFFFFFFFF != ::GetFileAttributesA(fileName);
  1038. }
  1039. static bool_type is_file(char_type const* path)
  1040. {
  1041. DWORD attr = ::GetFileAttributesA(path);
  1042. return 0xFFFFFFFF != attr && 0 == (attr & FILE_ATTRIBUTE_DIRECTORY);
  1043. }
  1044. static bool_type is_directory(char_type const* path)
  1045. {
  1046. DWORD attr = ::GetFileAttributesA(path);
  1047. return 0xFFFFFFFF != attr && 0 != (attr & FILE_ATTRIBUTE_DIRECTORY);
  1048. }
  1049. private:
  1050. static bool_type stat_direct_(char_type const* path, stat_data_type* stat_data)
  1051. {
  1052. WINSTL_ASSERT(NULL != stat_data);
  1053. size_type const cchPath = (NULL == path) ? 0u : str_len(path);
  1054. if(0 == cchPath)
  1055. {
  1056. ::SetLastError(ERROR_INVALID_NAME);
  1057. return false;
  1058. }
  1059. if(is_root_drive_(path, cchPath))
  1060. {
  1061. stat_data->dwFileAttributes = ::GetFileAttributesA(path);
  1062. stat_data->ftCreationTime.dwLowDateTime = 0;
  1063. stat_data->ftCreationTime.dwHighDateTime = 0;
  1064. stat_data->ftLastAccessTime.dwLowDateTime = 0;
  1065. stat_data->ftLastAccessTime.dwHighDateTime = 0;
  1066. stat_data->ftLastWriteTime.dwLowDateTime = 0;
  1067. stat_data->ftLastWriteTime.dwHighDateTime = 0;
  1068. stat_data->nFileSizeHigh = 0;
  1069. stat_data->nFileSizeLow = 0;
  1070. { for(ws_size_t i = 0; i < 4; ++i)
  1071. {
  1072. stat_data->cFileName[i] = path[i];
  1073. stat_data->cAlternateFileName[i] = path[i];
  1074. }}
  1075. return 0xFFFFFFFF != stat_data->dwFileAttributes;
  1076. }
  1077. WINSTL_ASSERT(NULL != path);
  1078. HANDLE h = find_first_file(path, stat_data);
  1079. return (INVALID_HANDLE_VALUE == h) ? false : (find_file_close(h), true);
  1080. }
  1081. public:
  1082. static bool_type stat(char_type const* path, stat_data_type* stat_data)
  1083. {
  1084. WINSTL_ASSERT(NULL != path);
  1085. WINSTL_ASSERT(NULL != stat_data);
  1086. #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  1087. _MSC_VER >= 1200
  1088. size_type len = class_type::str_len(path);
  1089. bool_type bTryEndTest = false;
  1090. if(is_path_absolute(path))
  1091. {
  1092. if(len > 4)
  1093. {
  1094. bTryEndTest = true;
  1095. }
  1096. }
  1097. else if(is_path_rooted(path))
  1098. {
  1099. if(len > 3)
  1100. {
  1101. bTryEndTest = true;
  1102. }
  1103. }
  1104. else if(len > 2)
  1105. {
  1106. bTryEndTest = true;
  1107. }
  1108. if( bTryEndTest &&
  1109. class_type::has_dir_end(path + len - 2))
  1110. {
  1111. typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_t;
  1112. WINSTL_ASSERT(len > 2);
  1113. buffer_t buffer(1 + len);
  1114. if(0 == buffer.size())
  1115. {
  1116. return false;
  1117. }
  1118. else
  1119. {
  1120. WINSTL_ASSERT(len > 0);
  1121. ::memcpy(&buffer[0], path, sizeof(char_type) * (len - 1));
  1122. buffer[len - 1] = '\0';
  1123. return class_type::stat_direct_(buffer.data(), stat_data);
  1124. }
  1125. }
  1126. else
  1127. #endif /* compiler */
  1128. {
  1129. return stat_direct_(path, stat_data);
  1130. }
  1131. }
  1132. static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data)
  1133. {
  1134. return filesystem_traits_::fstat(fd, fstat_data);
  1135. }
  1136. static bool_type is_file(stat_data_type const* stat_data)
  1137. {
  1138. return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  1139. }
  1140. static bool_type is_directory(stat_data_type const* stat_data)
  1141. {
  1142. return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  1143. }
  1144. static bool_type is_link(stat_data_type const* /* stat_data */)
  1145. {
  1146. return false;
  1147. }
  1148. static bool_type is_readonly(stat_data_type const* stat_data)
  1149. {
  1150. return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
  1151. }
  1152. static bool_type is_file(fstat_data_type const* stat_data)
  1153. {
  1154. return filesystem_traits_::is_file(stat_data);
  1155. }
  1156. static bool_type is_directory(fstat_data_type const* stat_data)
  1157. {
  1158. return filesystem_traits_::is_directory(stat_data);
  1159. }
  1160. static bool_type is_link(fstat_data_type const* stat_data)
  1161. {
  1162. return filesystem_traits_::is_link(stat_data);
  1163. }
  1164. static bool_type is_readonly(fstat_data_type const* stat_data)
  1165. {
  1166. return filesystem_traits_::is_readonly(stat_data);
  1167. }
  1168. static bool_type drive_exists(char_type driveLetter)
  1169. {
  1170. WINSTL_ASSERT(::IsCharAlphaA(driveLetter));
  1171. const DWORD drivesBitmap = ::GetLogicalDrives();
  1172. const int driveOrdinal = (driveLetter - (::IsCharUpperA(driveLetter) ? 'A' : 'a'));
  1173. return 0 != ((0x01 << driveOrdinal) & drivesBitmap);
  1174. }
  1175. static DWORD get_drive_type(char_type driveLetter)
  1176. {
  1177. WINSTL_ASSERT(::IsCharAlphaA(driveLetter));
  1178. char_type drive[] = { '?', ':', '\\', '\0' };
  1179. return (drive[0] = driveLetter, ::GetDriveTypeA(drive));
  1180. }
  1181. static bool_type create_directory(char_type const* dir)
  1182. {
  1183. return FALSE != ::CreateDirectoryA(dir, NULL);
  1184. }
  1185. static bool_type create_directory(char_type const* dir, LPSECURITY_ATTRIBUTES lpsa)
  1186. {
  1187. return FALSE != ::CreateDirectoryA(dir, lpsa);
  1188. }
  1189. static bool_type remove_directory(char_type const* dir)
  1190. {
  1191. return FALSE != ::RemoveDirectoryA(dir);
  1192. }
  1193. static bool_type unlink_file(char_type const* file)
  1194. {
  1195. return FALSE != ::DeleteFileA(file);
  1196. }
  1197. static bool_type delete_file(char_type const* file)
  1198. {
  1199. return unlink_file(file);
  1200. }
  1201. static bool_type rename_file(char_type const* currentName, char_type const* newName)
  1202. {
  1203. return FALSE != ::MoveFileA(currentName, newName);
  1204. }
  1205. static bool_type copy_file(char_type const* sourceName, char_type const* newName, bool_type bFailIfExists = false)
  1206. {
  1207. return FALSE != ::CopyFileA(sourceName, newName, bFailIfExists);
  1208. }
  1209. static file_handle_type invalid_file_handle_value()
  1210. {
  1211. return INVALID_HANDLE_VALUE;
  1212. }
  1213. static file_handle_type create_file(char_type const* fileName, ws_uint32_t desiredAccess, ws_uint32_t shareMode, LPSECURITY_ATTRIBUTES sa, ws_uint32_t creationDisposition, ws_uint32_t flagAndAttributes, file_handle_type hTemplateFile)
  1214. {
  1215. return ::CreateFileA(fileName, desiredAccess, shareMode, sa, creationDisposition, flagAndAttributes, hTemplateFile);
  1216. }
  1217. static bool_type close_file(file_handle_type h)
  1218. {
  1219. return filesystem_traits_::close_handle(h);
  1220. }
  1221. #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
  1222. static ws_uint64_t get_file_size(file_handle_type h)
  1223. {
  1224. return filesystem_traits_::get_file_size(h);
  1225. }
  1226. static ws_uint64_t get_file_size(stat_data_type const& sd)
  1227. {
  1228. ws_uint64_t size = 0;
  1229. size += sd.nFileSizeHigh;
  1230. size += sd.nFileSizeHigh;
  1231. return size;
  1232. }
  1233. static ws_uint64_t get_file_size(stat_data_type const* psd)
  1234. {
  1235. WINSTL_ASSERT(NULL != psd);
  1236. return get_file_size(*psd);
  1237. }
  1238. #else /* ? STLSOFT_CF_64BIT_INT_SUPPORT */
  1239. private:
  1240. static void get_file_size(stat_data_type const*);
  1241. static void get_file_size(stat_data_type const&);
  1242. #endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
  1243. private:
  1244. static size_type GetFullPathNameA(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  1245. {
  1246. WINSTL_ASSERT(NULL != fileName);
  1247. size_type result;
  1248. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1249. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1250. result = ::GetFullPathNameA(fileName, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer, ppFile);
  1251. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1252. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
  1253. result = ::GetFullPathNameA(fileName, static_cast<DWORD>(cchBuffer), buffer, ppFile);
  1254. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1255. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1256. result = ::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
  1257. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1258. if(0 == result)
  1259. {
  1260. size_type requiredLen = 0;
  1261. requiredLen += str_len(fileName);
  1262. if(!is_path_rooted(fileName))
  1263. {
  1264. size_type cwdLen = ::GetCurrentDirectoryA(0, NULL);
  1265. requiredLen += cwdLen;
  1266. }
  1267. if(requiredLen > maxPathLength)
  1268. {
  1269. ::SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1270. }
  1271. }
  1272. return result;
  1273. }
  1274. static size_type GetShortPathNameA(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  1275. {
  1276. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1277. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1278. return ::GetShortPathNameA(fileName, buffer, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer));
  1279. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1280. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
  1281. return ::GetShortPathNameA(fileName, buffer, static_cast<DWORD>(cchBuffer));
  1282. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1283. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1284. return ::GetShortPathNameA(fileName, buffer, cchBuffer);
  1285. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1286. }
  1287. static HANDLE FindFirstVolumeA(char_type* volume_name, size_type cch_volume_name)
  1288. {
  1289. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1290. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1291. return ::FindFirstVolumeA(volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
  1292. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1293. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
  1294. return ::FindFirstVolumeA(volume_name, static_cast<DWORD>(cch_volume_name));
  1295. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1296. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1297. return ::FindFirstVolumeA(volume_name, cch_volume_name);
  1298. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1299. }
  1300. static bool_type FindNextVolumeA(HANDLE h, char_type* volume_name, size_type cch_volume_name)
  1301. {
  1302. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1303. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1304. return FALSE != ::FindNextVolumeA(h, volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
  1305. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1306. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
  1307. return FALSE != ::FindNextVolumeA(h, volume_name, static_cast<DWORD>(cch_volume_name));
  1308. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1309. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1310. return FALSE != ::FindNextVolumeA(h, volume_name, cch_volume_name);
  1311. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1312. }
  1313. static size_type GetCurrentDirectoryA(size_type cchBuffer, char_type* buffer)
  1314. {
  1315. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1316. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1317. return ::GetCurrentDirectoryA(stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer);
  1318. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1319. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
  1320. return ::GetCurrentDirectoryA(static_cast<DWORD>(cchBuffer), buffer);
  1321. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1322. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1323. return ::GetCurrentDirectoryA(cchBuffer, buffer);
  1324. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1325. }
  1326. };
  1327. STLSOFT_TEMPLATE_SPECIALISATION
  1328. struct filesystem_traits<ws_char_w_t>
  1329. : public system_traits<ws_char_w_t>
  1330. {
  1331. public:
  1332. typedef ws_char_w_t char_type;
  1333. typedef ws_size_t size_type;
  1334. typedef ws_ptrdiff_t difference_type;
  1335. typedef WIN32_FIND_DATAW find_data_type;
  1336. typedef WIN32_FIND_DATAW stat_data_type;
  1337. typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
  1338. typedef filesystem_traits<char_type> class_type;
  1339. typedef ws_int_t int_type;
  1340. typedef ws_bool_t bool_type;
  1341. typedef HANDLE file_handle_type;
  1342. typedef HINSTANCE module_type;
  1343. typedef DWORD error_type;
  1344. private:
  1345. #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  1346. _MSC_VER >= 1200
  1347. typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_type_;
  1348. #endif /* compiler */
  1349. public:
  1350. enum
  1351. {
  1352. maxPathLength = CONST_NT_MAX_PATH //!< The maximum length of a path for the current file system
  1353. };
  1354. public:
  1355. static int_type str_fs_compare(char_type const* s1, char_type const* s2)
  1356. {
  1357. return str_compare_no_case(s1, s2);
  1358. }
  1359. static int_type str_fs_n_compare(char_type const* s1, char_type const* s2, size_type cch)
  1360. {
  1361. return str_n_compare_no_case(s1, s2, cch);
  1362. }
  1363. static char_type* ensure_dir_end(char_type* dir)
  1364. {
  1365. WINSTL_ASSERT(NULL != dir);
  1366. char_type* end = str_end(dir);
  1367. if( dir < end &&
  1368. !is_path_name_separator(*(end - 1)))
  1369. {
  1370. *end = path_name_separator();
  1371. *(end + 1) = L'\0';
  1372. }
  1373. return dir;
  1374. }
  1375. static char_type* remove_dir_end(char_type* dir)
  1376. {
  1377. WINSTL_ASSERT(NULL != dir);
  1378. // Don't trim drive roots ...
  1379. if( isalpha(dir[0]) &&
  1380. L':' == dir[1] &&
  1381. is_path_name_separator(dir[2]) &&
  1382. L'\0' == dir[3])
  1383. {
  1384. return dir;
  1385. }
  1386. // ... or UNC roots
  1387. if( L'\\' == dir[0] &&
  1388. L'\\' == dir[1] &&
  1389. L'\0' == dir[3])
  1390. {
  1391. return dir;
  1392. }
  1393. char_type* end = str_end(dir);
  1394. if( dir < end &&
  1395. is_path_name_separator(*(end - 1)))
  1396. {
  1397. *(end - 1) = L'\0';
  1398. }
  1399. return dir;
  1400. }
  1401. static bool_type has_dir_end(char_type const* dir)
  1402. {
  1403. WINSTL_ASSERT(NULL != dir);
  1404. size_type len = str_len(dir);
  1405. return (0 < len) && is_path_name_separator(dir[len - 1]);
  1406. }
  1407. static bool_type is_dots(char_type const* dir)
  1408. {
  1409. WINSTL_ASSERT(NULL != dir);
  1410. return dir[0] == '.' &&
  1411. ( dir[1] == L'\0' ||
  1412. ( dir[1] == L'.' &&
  1413. dir[2] == L'\0'));
  1414. }
  1415. static bool_type is_path_rooted(char_type const* path)
  1416. {
  1417. WINSTL_ASSERT(NULL != path);
  1418. return is_path_name_separator(*path) || is_path_absolute(path);
  1419. }
  1420. static bool_type is_path_rooted(
  1421. char_type const* path
  1422. , size_t cchPath
  1423. )
  1424. {
  1425. return (0 != cchPath && is_path_name_separator(*path)) || is_path_absolute(path, cchPath);
  1426. }
  1427. static bool_type is_path_absolute(char_type const* path)
  1428. {
  1429. WINSTL_ASSERT(NULL != path);
  1430. return is_path_absolute(path, str_len(path));
  1431. }
  1432. static bool_type is_path_absolute(
  1433. char_type const* path
  1434. , size_t cchPath
  1435. )
  1436. {
  1437. if(is_path_UNC(path, cchPath))
  1438. {
  1439. return true;
  1440. }
  1441. if(cchPath >= 3)
  1442. {
  1443. if( isalpha(path[0]) &&
  1444. ':' == path[1] &&
  1445. is_path_name_separator(path[2]))
  1446. {
  1447. return true;
  1448. }
  1449. }
  1450. return false;
  1451. }
  1452. static bool_type is_path_UNC(char_type const* path)
  1453. {
  1454. WINSTL_ASSERT(NULL != path);
  1455. return (L'\\' == path[0] && L'\\' == path[1]);
  1456. }
  1457. static bool_type is_path_UNC(
  1458. char_type const* path
  1459. , size_t cchPath
  1460. )
  1461. {
  1462. switch(cchPath)
  1463. {
  1464. case 0:
  1465. case 1:
  1466. return false;
  1467. case 2:
  1468. default:
  1469. return '\\' == path[0] && '\\' == path[1];
  1470. }
  1471. }
  1472. private:
  1473. // Determines whether the given path is a properly-formed drive:
  1474. //
  1475. // "X:\"
  1476. //
  1477. static bool_type is_root_drive_(
  1478. char_type const* path
  1479. , size_type cchPath
  1480. )
  1481. {
  1482. if(3 == cchPath)
  1483. {
  1484. if( iswalpha(path[0]) &&
  1485. L':' == path[1] &&
  1486. is_path_name_separator(path[2]))
  1487. {
  1488. return true;
  1489. }
  1490. }
  1491. return false;
  1492. }
  1493. // Determines whether the given path is a UNC root:
  1494. //
  1495. // "\\"
  1496. //
  1497. static bool_type is_root_UNC_(
  1498. char_type const* path
  1499. , size_type cchPath
  1500. )
  1501. {
  1502. if(2 == cchPath)
  1503. {
  1504. if( '\\' == path[0] &&
  1505. '\\' == path[1])
  1506. {
  1507. return true;
  1508. }
  1509. }
  1510. return false;
  1511. }
  1512. // Determines whether the given path is a directory root:
  1513. //
  1514. // "\"
  1515. //
  1516. // or:
  1517. //
  1518. // "/"
  1519. //
  1520. static bool_type is_root_directory_(
  1521. char_type const* path
  1522. , size_type cchPath
  1523. )
  1524. {
  1525. if(1 == cchPath)
  1526. {
  1527. if(is_path_name_separator(path[0]))
  1528. {
  1529. return true;
  1530. }
  1531. }
  1532. return false;
  1533. }
  1534. public:
  1535. static bool_type is_root_designator(char_type const* path)
  1536. {
  1537. WINSTL_ASSERT(NULL != path);
  1538. size_type const cchPath = str_len(path);
  1539. return is_root_directory_(path, cchPath) || is_root_drive_(path, cchPath) || is_root_UNC_(path, cchPath);
  1540. }
  1541. #if 0
  1542. static bool_type is_root_designator(
  1543. char_type const* path
  1544. , size_t cchPath
  1545. )
  1546. {
  1547. return is_root_directory_(path, cchPath) || is_root_drive_(path, cchPath) || is_root_UNC_(path, cchPath);
  1548. }
  1549. #endif /* 0 */
  1550. static bool_type is_path_name_separator(char_type ch)
  1551. {
  1552. return L'\\' == ch || L'/' == ch;
  1553. }
  1554. static char_type path_separator()
  1555. {
  1556. return L';';
  1557. }
  1558. static char_type path_name_separator()
  1559. {
  1560. return L'\\';
  1561. }
  1562. static char_type const* pattern_all()
  1563. {
  1564. return L"*.*";
  1565. }
  1566. static size_type path_max()
  1567. {
  1568. return (::GetVersion() & 0x80000000) ? WINSTL_CONST_MAX_PATH : CONST_NT_MAX_PATH;
  1569. }
  1570. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  1571. {
  1572. WINSTL_MESSAGE_ASSERT("GetFullPathNameW() will crash when the file-name and buffer parameters are the same", fileName != buffer);
  1573. return class_type::GetFullPathNameW(fileName, cchBuffer, buffer, ppFile);
  1574. }
  1575. static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  1576. {
  1577. char_type* pFile;
  1578. return get_full_path_name(fileName, cchBuffer, buffer, &pFile);
  1579. }
  1580. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  1581. {
  1582. return get_full_path_name(fileName, buffer, cchBuffer);
  1583. }
  1584. static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  1585. {
  1586. return class_type::GetShortPathNameW(fileName, buffer, cchBuffer);
  1587. }
  1588. static size_type get_short_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  1589. {
  1590. return class_type::GetShortPathNameW(fileName, buffer, cchBuffer);
  1591. }
  1592. // FindFile() API
  1593. static HANDLE find_first_file(char_type const* spec, find_data_type* findData)
  1594. {
  1595. return ::FindFirstFileW(spec, findData);
  1596. }
  1597. #if defined(_WIN32_WINNT) && \
  1598. _WIN32_WINNT >= 0x0400
  1599. static HANDLE find_first_file_ex(char_type const* spec, FINDEX_SEARCH_OPS flags, find_data_type* findData)
  1600. {
  1601. return ::FindFirstFileExW(spec, FindExInfoStandard, findData, flags, NULL, 0);
  1602. }
  1603. #endif /* _WIN32_WINNT >= 0x0400 */
  1604. static bool_type find_next_file(HANDLE h, find_data_type* findData)
  1605. {
  1606. return ::FindNextFileW(h, findData) != FALSE;
  1607. }
  1608. static void find_file_close(HANDLE h)
  1609. {
  1610. WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
  1611. ::FindClose(h);
  1612. }
  1613. // FindVolume() API
  1614. #ifndef _WINSTL_NO_FINDVOLUME_API
  1615. static HANDLE find_first_volume(char_type* volume_name, size_type cch_volume_name)
  1616. {
  1617. return class_type::FindFirstVolumeW(volume_name, cch_volume_name);
  1618. }
  1619. static bool_type find_next_volume(HANDLE h, char_type* volume_name, size_type cch_volume_name)
  1620. {
  1621. return class_type::FindNextVolumeW(h, volume_name, cch_volume_name) != FALSE;
  1622. }
  1623. static void find_volume_close(HANDLE h)
  1624. {
  1625. WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
  1626. ::FindVolumeClose(h);
  1627. }
  1628. #endif // !_WINSTL_NO_FINDVOLUME_API
  1629. // File-system state
  1630. static bool_type set_current_directory(char_type const* dir)
  1631. {
  1632. return ::SetCurrentDirectoryW(dir) != FALSE;
  1633. }
  1634. static size_type get_current_directory(char_type* buffer, size_type cchBuffer)
  1635. {
  1636. return class_type::GetCurrentDirectoryW(cchBuffer, buffer);
  1637. }
  1638. static size_type get_current_directory(size_type cchBuffer, char_type* buffer)
  1639. {
  1640. return class_type::get_current_directory(buffer, cchBuffer);
  1641. }
  1642. static bool_type file_exists(char_type const* fileName)
  1643. {
  1644. return 0xFFFFFFFF != ::GetFileAttributesW(fileName);
  1645. }
  1646. static bool_type is_file(char_type const* path)
  1647. {
  1648. DWORD attr = ::GetFileAttributesW(path);
  1649. return 0xFFFFFFFF != attr && 0 == (attr & FILE_ATTRIBUTE_DIRECTORY);
  1650. }
  1651. static bool_type is_directory(char_type const* path)
  1652. {
  1653. DWORD attr = ::GetFileAttributesW(path);
  1654. return 0xFFFFFFFF != attr && 0 != (attr & FILE_ATTRIBUTE_DIRECTORY);
  1655. }
  1656. private:
  1657. static bool_type stat_direct_(char_type const* path, stat_data_type* stat_data)
  1658. {
  1659. WINSTL_ASSERT(NULL != stat_data);
  1660. size_type const cchPath = (NULL == path) ? 0u : str_len(path);
  1661. if(0 == cchPath)
  1662. {
  1663. ::SetLastError(ERROR_INVALID_NAME);
  1664. return false;
  1665. }
  1666. if(is_root_drive_(path, cchPath))
  1667. {
  1668. stat_data->dwFileAttributes = ::GetFileAttributesW(path);
  1669. stat_data->ftCreationTime.dwLowDateTime = 0;
  1670. stat_data->ftCreationTime.dwHighDateTime = 0;
  1671. stat_data->ftLastAccessTime.dwLowDateTime = 0;
  1672. stat_data->ftLastAccessTime.dwHighDateTime = 0;
  1673. stat_data->ftLastWriteTime.dwLowDateTime = 0;
  1674. stat_data->ftLastWriteTime.dwHighDateTime = 0;
  1675. stat_data->nFileSizeHigh = 0;
  1676. stat_data->nFileSizeLow = 0;
  1677. { for(ws_size_t i = 0; i < 4; ++i)
  1678. {
  1679. stat_data->cFileName[i] = path[i];
  1680. stat_data->cAlternateFileName[i] = path[i];
  1681. }}
  1682. return 0xFFFFFFFF != stat_data->dwFileAttributes;
  1683. }
  1684. WINSTL_ASSERT(NULL != path);
  1685. HANDLE h = find_first_file(path, stat_data);
  1686. return (INVALID_HANDLE_VALUE == h) ? false : (find_file_close(h), true);
  1687. }
  1688. public:
  1689. static bool_type stat(char_type const* path, stat_data_type* stat_data)
  1690. {
  1691. WINSTL_ASSERT(NULL != path);
  1692. WINSTL_ASSERT(NULL != stat_data);
  1693. #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  1694. _MSC_VER >= 1200
  1695. size_type len = class_type::str_len(path);
  1696. bool_type bTryEndTest = false;
  1697. if(is_path_absolute(path))
  1698. {
  1699. if(len > 4)
  1700. {
  1701. bTryEndTest = true;
  1702. }
  1703. }
  1704. else if(is_path_rooted(path))
  1705. {
  1706. if(len > 3)
  1707. {
  1708. bTryEndTest = true;
  1709. }
  1710. }
  1711. else if(len > 2)
  1712. {
  1713. bTryEndTest = true;
  1714. }
  1715. if( bTryEndTest &&
  1716. class_type::has_dir_end(path + len - 2))
  1717. {
  1718. typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_t;
  1719. WINSTL_ASSERT(len > 2);
  1720. buffer_t buffer(1 + len);
  1721. if(0 == buffer.size())
  1722. {
  1723. return false;
  1724. }
  1725. else
  1726. {
  1727. WINSTL_ASSERT(len > 0);
  1728. ::memcpy(&buffer[0], path, sizeof(char_type) * (len - 1));
  1729. buffer[len - 1] = L'\0';
  1730. return class_type::stat_direct_(buffer.data(), stat_data);
  1731. }
  1732. }
  1733. else
  1734. #endif /* compiler */
  1735. {
  1736. return stat_direct_(path, stat_data);
  1737. }
  1738. }
  1739. static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data)
  1740. {
  1741. return filesystem_traits_::fstat(fd, fstat_data);
  1742. }
  1743. static bool_type is_file(stat_data_type const* stat_data)
  1744. {
  1745. return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  1746. }
  1747. static bool_type is_directory(stat_data_type const* stat_data)
  1748. {
  1749. return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  1750. }
  1751. static bool_type is_link(stat_data_type const* /* stat_data */)
  1752. {
  1753. return false;
  1754. }
  1755. static bool_type is_readonly(stat_data_type const* stat_data)
  1756. {
  1757. return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
  1758. }
  1759. static bool_type is_file(fstat_data_type const* stat_data)
  1760. {
  1761. return filesystem_traits_::is_file(stat_data);
  1762. }
  1763. static bool_type is_directory(fstat_data_type const* stat_data)
  1764. {
  1765. return filesystem_traits_::is_directory(stat_data);
  1766. }
  1767. static bool_type is_link(fstat_data_type const* stat_data)
  1768. {
  1769. return filesystem_traits_::is_link(stat_data);
  1770. }
  1771. static bool_type is_readonly(fstat_data_type const* stat_data)
  1772. {
  1773. return filesystem_traits_::is_readonly(stat_data);
  1774. }
  1775. static bool_type drive_exists(char_type driveLetter)
  1776. {
  1777. WINSTL_ASSERT(IsCharAlphaW(driveLetter));
  1778. const DWORD drivesBitmap = ::GetLogicalDrives();
  1779. const int driveOrdinal = (driveLetter - (IsCharUpperW(driveLetter) ? L'A' : L'a'));
  1780. return 0 != ((0x01 << driveOrdinal) & drivesBitmap);
  1781. }
  1782. static DWORD get_drive_type(char_type driveLetter)
  1783. {
  1784. WINSTL_ASSERT(IsCharAlphaW(driveLetter));
  1785. char_type drive[] = { L'?', L':', L'\\', L'\0' };
  1786. return (drive[0] = driveLetter, ::GetDriveTypeW(drive));
  1787. }
  1788. // File-system control
  1789. static bool_type create_directory(char_type const* dir)
  1790. {
  1791. return FALSE != ::CreateDirectoryW(dir, NULL);
  1792. }
  1793. static bool_type create_directory(char_type const* dir, LPSECURITY_ATTRIBUTES lpsa)
  1794. {
  1795. return FALSE != ::CreateDirectoryW(dir, lpsa);
  1796. }
  1797. static bool_type remove_directory(char_type const* dir)
  1798. {
  1799. return FALSE != ::RemoveDirectoryW(dir);
  1800. }
  1801. static bool_type unlink_file(char_type const* file)
  1802. {
  1803. return FALSE != ::DeleteFileW(file);
  1804. }
  1805. static bool_type delete_file(char_type const* file)
  1806. {
  1807. return unlink_file(file);
  1808. }
  1809. static bool_type rename_file(char_type const* currentName, char_type const* newName)
  1810. {
  1811. return FALSE != ::MoveFileW(currentName, newName);
  1812. }
  1813. static bool_type copy_file(char_type const* sourceName, char_type const* newName, bool_type bFailIfExists = false)
  1814. {
  1815. return FALSE != ::CopyFileW(sourceName, newName, bFailIfExists);
  1816. }
  1817. static file_handle_type invalid_file_handle_value()
  1818. {
  1819. return INVALID_HANDLE_VALUE;
  1820. }
  1821. static file_handle_type create_file(char_type const* fileName, ws_uint32_t desiredAccess, ws_uint32_t shareMode, LPSECURITY_ATTRIBUTES sa, ws_uint32_t creationDisposition, ws_uint32_t flagAndAttributes, file_handle_type hTemplateFile)
  1822. {
  1823. return ::CreateFileW(fileName, desiredAccess, shareMode, sa, creationDisposition, flagAndAttributes, hTemplateFile);
  1824. }
  1825. static bool_type close_file(file_handle_type h)
  1826. {
  1827. return filesystem_traits_::close_handle(h);
  1828. }
  1829. #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
  1830. static ws_uint64_t get_file_size(file_handle_type h)
  1831. {
  1832. return filesystem_traits_::get_file_size(h);
  1833. }
  1834. static ws_uint64_t get_file_size(stat_data_type const& sd)
  1835. {
  1836. ws_uint64_t size = 0;
  1837. size += sd.nFileSizeHigh;
  1838. size += sd.nFileSizeHigh;
  1839. return size;
  1840. }
  1841. static ws_uint64_t get_file_size(stat_data_type const* psd)
  1842. {
  1843. WINSTL_ASSERT(NULL != psd);
  1844. return get_file_size(*psd);
  1845. }
  1846. #else /* ? STLSOFT_CF_64BIT_INT_SUPPORT */
  1847. private:
  1848. static void get_file_size(stat_data_type const*);
  1849. static void get_file_size(stat_data_type const&);
  1850. #endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
  1851. private:
  1852. static size_type GetFullPathNameW(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  1853. {
  1854. WINSTL_ASSERT(NULL != fileName);
  1855. size_type result;
  1856. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1857. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1858. result = ::GetFullPathNameW(fileName, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer, ppFile);
  1859. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1860. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
  1861. result = ::GetFullPathNameW(fileName, static_cast<DWORD>(cchBuffer), buffer, ppFile);
  1862. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1863. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1864. result = ::GetFullPathNameW(fileName, cchBuffer, buffer, ppFile);
  1865. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1866. if(0 == result)
  1867. {
  1868. size_type requiredLen = 0;
  1869. requiredLen += str_len(fileName);
  1870. if(!is_path_rooted(fileName))
  1871. {
  1872. size_type cwdLen = ::GetCurrentDirectoryA(0, NULL);
  1873. requiredLen += cwdLen;
  1874. }
  1875. if(requiredLen > maxPathLength)
  1876. {
  1877. ::SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1878. }
  1879. }
  1880. return result;
  1881. }
  1882. static size_type GetShortPathNameW(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  1883. {
  1884. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1885. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1886. return ::GetShortPathNameW(fileName, buffer, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer));
  1887. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1888. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
  1889. return ::GetShortPathNameW(fileName, buffer, static_cast<DWORD>(cchBuffer));
  1890. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1891. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1892. return ::GetShortPathNameW(fileName, buffer, cchBuffer);
  1893. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1894. }
  1895. static HANDLE FindFirstVolumeW(char_type* volume_name, size_type cch_volume_name)
  1896. {
  1897. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1898. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1899. return ::FindFirstVolumeW(volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
  1900. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1901. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
  1902. return ::FindFirstVolumeW(volume_name, static_cast<DWORD>(cch_volume_name));
  1903. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1904. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1905. return ::FindFirstVolumeW(volume_name, cch_volume_name);
  1906. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1907. }
  1908. static bool_type FindNextVolumeW(HANDLE h, char_type* volume_name, size_type cch_volume_name)
  1909. {
  1910. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1911. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1912. return FALSE != ::FindNextVolumeW(h, volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
  1913. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1914. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
  1915. return FALSE != ::FindNextVolumeW(h, volume_name, static_cast<DWORD>(cch_volume_name));
  1916. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1917. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1918. return FALSE != ::FindNextVolumeW(h, volume_name, cch_volume_name);
  1919. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1920. }
  1921. static size_type GetCurrentDirectoryW(size_type cchBuffer, char_type* buffer)
  1922. {
  1923. #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
  1924. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1925. return ::GetCurrentDirectoryW(stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer);
  1926. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1927. WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
  1928. return ::GetCurrentDirectoryW(static_cast<DWORD>(cchBuffer), buffer);
  1929. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1930. #else /* ? _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1931. return ::GetCurrentDirectoryW(cchBuffer, buffer);
  1932. #endif /* _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING */
  1933. }
  1934. };
  1935. #endif /* STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1936. /* /////////////////////////////////////////////////////////////////////////
  1937. * Unit-testing
  1938. */
  1939. #ifdef STLSOFT_UNITTEST
  1940. # include "./unittest/filesystem_traits_unittest_.h"
  1941. #endif /* STLSOFT_UNITTEST */
  1942. /* ////////////////////////////////////////////////////////////////////// */
  1943. #ifndef _WINSTL_NO_NAMESPACE
  1944. # if defined(_STLSOFT_NO_NAMESPACE) || \
  1945. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1946. } // namespace winstl
  1947. # else
  1948. } // namespace winstl_project
  1949. } // namespace stlsoft
  1950. # endif /* _STLSOFT_NO_NAMESPACE */
  1951. #endif /* !_WINSTL_NO_NAMESPACE */
  1952. /* ////////////////////////////////////////////////////////////////////// */
  1953. #endif /* WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  1954. /* ///////////////////////////// end of file //////////////////////////// */