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.

671 lines
25 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/filesystem/directory_functions.hpp (originally MLFlMan.h, ::SynesisStd)
  3. *
  4. * Purpose: Functions for manipulating directories.
  5. *
  6. * Created: 7th February 2002
  7. * Updated: 26th February 2011
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2002-2011, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file winstl/filesystem/directory_functions.hpp
  40. *
  41. * \brief [C++ only] Functions for manipulating directories
  42. * (\ref group__library__filesystem "File System" Library).
  43. */
  44. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_DIRECTORY_FUNCTIONS
  45. #define WINSTL_INCL_WINSTL_FILESYSTEM_HPP_DIRECTORY_FUNCTIONS
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_DIRECTORY_FUNCTIONS_MAJOR 5
  48. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_DIRECTORY_FUNCTIONS_MINOR 0
  49. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_DIRECTORY_FUNCTIONS_REVISION 4
  50. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_DIRECTORY_FUNCTIONS_EDIT 49
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Compatibility
  54. */
  55. /*
  56. [Incompatibilies-start]
  57. STLSOFT_COMPILER_IS_MSVC: _MSC_VER<1200
  58. [Incompatibilies-end]
  59. */
  60. /* /////////////////////////////////////////////////////////////////////////
  61. * Includes
  62. */
  63. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  64. # include <winstl/winstl.h>
  65. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  66. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  67. # include <winstl/filesystem/filesystem_traits.hpp>
  68. #endif /* !WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  69. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER
  70. # include <winstl/filesystem/file_path_buffer.hpp>
  71. #endif /* !WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER */
  72. #ifdef _ATL_MIN_CRT
  73. # ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR
  74. # include <stlsoft/memory/allocator_selector.hpp>
  75. # endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR */
  76. #endif /* _ATL_MIN_CRT */
  77. /* /////////////////////////////////////////////////////////////////////////
  78. * Namespace
  79. */
  80. #ifndef _WINSTL_NO_NAMESPACE
  81. # if defined(_STLSOFT_NO_NAMESPACE) || \
  82. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  83. /* There is no stlsoft namespace, so must define ::winstl */
  84. namespace winstl
  85. {
  86. # else
  87. /* Define stlsoft::winstl_project */
  88. namespace stlsoft
  89. {
  90. namespace winstl_project
  91. {
  92. # endif /* _STLSOFT_NO_NAMESPACE */
  93. #endif /* !_WINSTL_NO_NAMESPACE */
  94. /* /////////////////////////////////////////////////////////////////////////
  95. * Helper functions
  96. */
  97. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  98. template <ss_typename_param_k C>
  99. inline C* find_last_path_name_separator_(C const* s)
  100. {
  101. typedef filesystem_traits<C> traits_t;
  102. ss_typename_type_k traits_t::char_type const* slash = traits_t::str_rchr(s, '/');
  103. ss_typename_type_k traits_t::char_type const* bslash = traits_t::str_rchr(s, '\\');
  104. if(NULL == slash)
  105. {
  106. slash = bslash;
  107. }
  108. else if(NULL != bslash)
  109. {
  110. if(slash < bslash)
  111. {
  112. slash = bslash;
  113. }
  114. }
  115. return const_cast<C*>(slash);
  116. }
  117. template <ss_typename_param_k C>
  118. inline
  119. ws_bool_t
  120. create_directory_recurse_impl(
  121. C const* dir
  122. , LPSECURITY_ATTRIBUTES lpsa
  123. )
  124. {
  125. typedef C char_type;
  126. typedef filesystem_traits<C> traits_t;
  127. #ifdef _ATL_MIN_CRT
  128. typedef ss_typename_type_k stlsoft_ns_qual(allocator_selector)<C>::allocator_type allocator_t;
  129. typedef basic_file_path_buffer< char_type
  130. , allocator_t
  131. > file_path_buffer_t;
  132. #else /* ? _ATL_MIN_CRT */
  133. typedef basic_file_path_buffer<char_type> file_path_buffer_t;
  134. #endif /* _ATL_MIN_CRT */
  135. ws_bool_t bRet;
  136. if( NULL == dir ||
  137. '\0' == *dir)
  138. {
  139. traits_t::set_last_error(ERROR_DIRECTORY);
  140. bRet = false;
  141. }
  142. else
  143. {
  144. if(traits_t::file_exists(dir))
  145. {
  146. if(traits_t::is_directory(dir))
  147. {
  148. traits_t::set_last_error(ERROR_ALREADY_EXISTS);
  149. bRet = true;
  150. }
  151. else
  152. {
  153. traits_t::set_last_error(ERROR_FILE_EXISTS);
  154. bRet = false;
  155. }
  156. }
  157. else
  158. {
  159. file_path_buffer_t sz;
  160. file_path_buffer_t szParent;
  161. // May be being compiled absent exception support, so need to check the
  162. // file path buffers. (This _could_ be done with a compile-time #ifdef,
  163. // but it's best not, since some translators support exceptions but yet
  164. // don't throw on mem exhaustion, and in any case a user could change
  165. // ::new)
  166. if( 0 == sz.size() ||
  167. 0 == szParent.size())
  168. {
  169. bRet = false;
  170. }
  171. else
  172. {
  173. ws_size_t dirLen = traits_t::str_len(dir);
  174. traits_t::char_copy(&sz[0], dir, dirLen);
  175. sz[dirLen] = '\0';
  176. traits_t::remove_dir_end(&sz[0]);
  177. if( traits_t::create_directory(sz.c_str(), lpsa) ||
  178. ERROR_ALREADY_EXISTS == traits_t::get_last_error())
  179. {
  180. traits_t::set_last_error(ERROR_SUCCESS);
  181. bRet = true;
  182. }
  183. else
  184. {
  185. // Trim previous directory
  186. ws_size_t szLen = traits_t::str_len(dir);
  187. traits_t::char_copy(&szParent[0], sz.c_str(), szLen);
  188. szParent[szLen] = '\0';
  189. char_type* pszSlash = find_last_path_name_separator_<C>(szParent.c_str());
  190. if(pszSlash == NULL)
  191. {
  192. traits_t::set_last_error(ERROR_DIRECTORY);
  193. bRet = false;
  194. }
  195. else
  196. {
  197. *pszSlash = '\0'; // Will always have enough room for two bytes
  198. // If second character is ':', and total lengths is less than four,
  199. // or the recurse create fails, then return false;
  200. if( ( szParent[1] == ':' &&
  201. (traits_t::set_last_error(ERROR_CANNOT_MAKE), traits_t::str_len(szParent.c_str()) < 4)) ||
  202. !create_directory_recurse_impl(szParent.c_str(), lpsa))
  203. {
  204. bRet = false;
  205. }
  206. else
  207. {
  208. bRet = traits_t::create_directory(sz.c_str(), lpsa) || ERROR_ALREADY_EXISTS == traits_t::get_last_error();
  209. }
  210. }
  211. }
  212. }
  213. }
  214. }
  215. return bRet;
  216. }
  217. template<
  218. ss_typename_param_k C
  219. , ss_typename_param_k FD // This is need because VC++6 cannot deduce filesystem_traits<C>::find_data_type
  220. >
  221. inline
  222. ws_dword_t
  223. remove_directory_recurse_impl(
  224. C const* dir
  225. , ws_int_t (*pfn)(void* param, C const* subDir, FD const* st, DWORD err)
  226. , void* param
  227. )
  228. {
  229. typedef C char_type;
  230. typedef filesystem_traits<C> traits_t;
  231. #ifdef _ATL_MIN_CRT
  232. typedef ss_typename_type_k stlsoft_ns_qual(allocator_selector)<C>::allocator_type allocator_t;
  233. typedef basic_file_path_buffer< char_type
  234. , allocator_t
  235. > file_path_buffer_t;
  236. #else /* ? _ATL_MIN_CRT */
  237. typedef basic_file_path_buffer<char_type> file_path_buffer_t;
  238. #endif /* _ATL_MIN_CRT */
  239. ws_dword_t dwRet = static_cast<ws_dword_t>(E_FAIL);
  240. if(NULL != pfn)
  241. {
  242. // starting: { param, dir, NULL, ~0 }
  243. (void)(*pfn)(param, dir, NULL, ~static_cast<ws_dword_t>(0)); // Entering
  244. }
  245. if( NULL == dir ||
  246. '\0' == *dir)
  247. {
  248. dwRet = ERROR_DIRECTORY;
  249. if(NULL != pfn)
  250. {
  251. // failed: { param, dir, NULL, error-code }
  252. (void)(*pfn)(param, dir, NULL, dwRet);
  253. }
  254. }
  255. else
  256. {
  257. if(!traits_t::file_exists(dir))
  258. {
  259. // The given path does not exist, so this is treated as success, but
  260. // reporting ERROR_PATH_NOT_FOUND
  261. dwRet = ERROR_PATH_NOT_FOUND;
  262. if(NULL != pfn)
  263. {
  264. // failed: { param, dir, NULL, error-code }
  265. (void)(*pfn)(param, dir, NULL, dwRet);
  266. }
  267. }
  268. else
  269. {
  270. if(traits_t::is_file(dir))
  271. {
  272. // The given path exists as a file. This is failure
  273. dwRet = ERROR_FILE_EXISTS;
  274. if(NULL != pfn)
  275. {
  276. // failed: { param, dir, NULL, error-code }
  277. (void)(*pfn)(param, dir, NULL, dwRet);
  278. }
  279. }
  280. else
  281. {
  282. // Otherwise, we attempt to remove it
  283. if(traits_t::remove_directory(dir))
  284. {
  285. dwRet = ERROR_SUCCESS;
  286. if(NULL != pfn)
  287. {
  288. // succeeded: { param, dir, NULL, ERROR_SUCCESS }
  289. (void)(*pfn)(param, dir, NULL, dwRet); // Deleted
  290. }
  291. }
  292. else
  293. {
  294. const DWORD removeError = traits_t::get_last_error();
  295. if( ERROR_DIR_NOT_EMPTY != removeError &&
  296. ERROR_SHARING_VIOLATION != removeError)
  297. {
  298. dwRet = removeError;
  299. if(NULL != pfn)
  300. {
  301. // failed: { param, dir, NULL, error-code }
  302. (void)(*pfn)(param, dir, NULL, dwRet);
  303. }
  304. }
  305. else
  306. {
  307. // It has some contents, so we need to remove them
  308. ss_typename_type_k traits_t::stat_data_type st;
  309. file_path_buffer_t sz;
  310. HANDLE hSrch;
  311. ws_size_t n;
  312. ws_size_t dirLen = traits_t::str_len(dir);
  313. ws_size_t allLen = traits_t::str_len(traits_t::pattern_all());
  314. traits_t::char_copy(&sz[0], dir, dirLen);
  315. sz[dirLen] = '\0';
  316. traits_t::ensure_dir_end(&sz[0]);
  317. n = traits_t::str_len(sz.c_str());
  318. WINSTL_ASSERT(n + traits_t::str_len(traits_t::pattern_all()) <= file_path_buffer_t::max_size());
  319. traits_t::char_copy(&sz[n], traits_t::pattern_all(), allLen);
  320. sz[n + allLen] = '\0';
  321. hSrch = traits_t::find_first_file(sz.c_str(), &st);
  322. if(INVALID_HANDLE_VALUE == hSrch)
  323. {
  324. dwRet = traits_t::get_last_error();
  325. }
  326. else
  327. {
  328. dwRet = ERROR_SUCCESS;
  329. do
  330. {
  331. if(!traits_t::is_dots(st.cFileName))
  332. {
  333. ws_size_t filenameLen = traits_t::str_len(st.cFileName);
  334. traits_t::char_copy(&sz[n], st.cFileName, filenameLen);
  335. sz[n + filenameLen] = '\0';
  336. if(traits_t::is_file(sz.c_str()))
  337. {
  338. // If it's a file, the pfn must be consulted, otherwise
  339. // it's an automatic failure
  340. ws_int_t r = 0;
  341. if( NULL == pfn ||
  342. 0 == (r = (*pfn)(param, dir, &st, ERROR_SUCCESS)))
  343. {
  344. dwRet = ERROR_DIR_NOT_EMPTY;
  345. if(NULL != pfn)
  346. {
  347. // failed: { param, dir, &entry, error-code }
  348. (void)(*pfn)(param, dir, &st, dwRet);
  349. }
  350. break;
  351. }
  352. else
  353. {
  354. if(r > 0)
  355. {
  356. if(!traits_t::delete_file(sz.c_str()))
  357. {
  358. dwRet = traits_t::get_last_error();
  359. if(NULL != pfn)
  360. {
  361. // failed: { param, dir, &entry, error-code }
  362. (void)(*pfn)(param, dir, &st, dwRet);
  363. }
  364. break;
  365. }
  366. }
  367. }
  368. }
  369. else
  370. {
  371. ws_int_t r = 1;
  372. // If it's a directory, then pfn is consulted, otherwise
  373. // it's an automatic attempt to recursively delete
  374. if( NULL != pfn &&
  375. 0 == (r = (*pfn)(param, dir, &st, ERROR_SUCCESS)))
  376. {
  377. dwRet = ERROR_DIR_NOT_EMPTY;
  378. if(NULL != pfn)
  379. {
  380. // failed: { param, dir, &entry, error-code }
  381. (void)(*pfn)(param, dir, &st, dwRet);
  382. }
  383. break;
  384. }
  385. else
  386. {
  387. if(r > 0)
  388. {
  389. dwRet = remove_directory_recurse_impl(sz.c_str(), pfn, param);
  390. }
  391. }
  392. }
  393. }
  394. } while(traits_t::find_next_file(hSrch, &st));
  395. traits_t::find_file_close(hSrch);
  396. if(ERROR_SUCCESS == dwRet)
  397. {
  398. if(traits_t::remove_directory(dir))
  399. {
  400. if(NULL != pfn)
  401. {
  402. // succeeded: { param, dir, NULL, ERROR_SUCCESS }
  403. (void)(*pfn)(param, dir, NULL, ERROR_SUCCESS); // Deleted
  404. }
  405. }
  406. else
  407. {
  408. dwRet = traits_t::get_last_error();
  409. }
  410. }
  411. }
  412. }
  413. }
  414. }
  415. }
  416. }
  417. return dwRet;
  418. }
  419. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  420. /* /////////////////////////////////////////////////////////////////////////
  421. * Functions
  422. */
  423. /** Creates the given directory, including all its parent directories, applying
  424. * the given mode.
  425. *
  426. * \ingroup group__library__filesystem
  427. *
  428. * \param dir The path of the directory to create
  429. * \param lpsa The security attributes with which each directory is to be created
  430. */
  431. inline ws_bool_t create_directory_recurse(ws_char_a_t const* dir, LPSECURITY_ATTRIBUTES lpsa = NULL)
  432. {
  433. return create_directory_recurse_impl(dir, lpsa);
  434. }
  435. /** Creates the given directory, including all its parent directories, applying
  436. * the given mode.
  437. *
  438. * \ingroup group__library__filesystem
  439. *
  440. * \param dir The path of the directory to create
  441. * \param lpsa The security attributes with which each directory is to be created
  442. */
  443. inline ws_bool_t create_directory_recurse(ws_char_w_t const* dir, LPSECURITY_ATTRIBUTES lpsa = NULL)
  444. {
  445. return create_directory_recurse_impl(dir, lpsa);
  446. }
  447. /** Creates the given directory, including all its parent directories, applying
  448. * the given mode.
  449. *
  450. * \ingroup group__library__filesystem
  451. *
  452. * \param dir The path of the directory to create
  453. * \param lpsa The security attributes with which each directory is to be created
  454. */
  455. template <ss_typename_param_k S>
  456. inline ws_bool_t create_directory_recurse(S const& dir, LPSECURITY_ATTRIBUTES lpsa = NULL)
  457. {
  458. return create_directory_recurse(stlsoft_ns_qual(c_str_ptr)(dir), lpsa);
  459. }
  460. /** Removes the given directory, and all its subdirectories.
  461. *
  462. * \ingroup group__library__filesystem
  463. *
  464. * \param dir The path of the directory to remove.
  465. * \param pfn Pointer to a callback function, which will receive
  466. * notifications and requests for file/directory deletion. The semantics
  467. * of the parameters are specified in the note below.
  468. * \param param Caller-supplied parameter, always passed through to the
  469. * callback function \c pfn.
  470. *
  471. * \note If no callback function is specified, then the function will remove
  472. * only empty subdirectories, i.e. no files will be removed. To remove
  473. * files, a function must be supplied, and may take additional measures
  474. * (such as changing file attributes) before the deletion is attempted by
  475. * <code>remove_directory_recurse()</code>. Do not delete the file in the
  476. * callback, otherwise the attempt within
  477. * <code>remove_directory_recurse()</code> will fail, and the function
  478. * will report overall failure of the operation.
  479. *
  480. * \note The semantics of the callback function's parameters are as follows:
  481. * \li If the err param is ~0 (-1 on UNIX), then the \c dir param specifies
  482. * the name of the current directory being traversed. All other params are
  483. * unspecified (except \c param). The return value is ignored.
  484. * \li If the err param is 0 and the \c st param is NULL, then \c dir
  485. * specifies the name of a directory that has been successfully removed.
  486. * All other params are unspecified (except \c param). The return value is
  487. * ignored.
  488. * \li If the err param is 0 and the \c st param is not NULL, then \c dir
  489. * specifies the name of the currently traversing directory, and \c st
  490. * specifies the stat information for the entry to be deleted. Return true
  491. * to enable removal of this entry, or false to prevent removal (and
  492. * cancel the overall operation). All other params are unspecified (except
  493. * \c param). The return value is ignored.
  494. * \li If the err param is any other value, and the \c st param is NULL,
  495. * then the \c dir param specifies the name of a directory that could not
  496. * be deleted and err specifies the errno value associated with the
  497. * failure. All other params are unspecified (except \c param). The return
  498. * value is ignored.
  499. * \li If the err param is any other value, and the \c st param is not NULL,
  500. * then the \c dir param specifies the name of a directory within which an
  501. * entry could not be deleted, \c st specifies the stat information of the
  502. * entry that could not be deleted, and err specifies the errno value
  503. * associated with the failure. All other params are unspecified (except
  504. * \c param). The return value is ignored.
  505. */
  506. inline
  507. ws_bool_t
  508. remove_directory_recurse(
  509. ws_char_a_t const* dir
  510. , ws_int_t (*pfn)(void* param, ws_char_a_t const* subDir, WIN32_FIND_DATAA const* st, DWORD err)
  511. , void* param
  512. )
  513. {
  514. typedef filesystem_traits<ws_char_a_t> traits_t;
  515. ws_dword_t dwRet = remove_directory_recurse_impl<ws_char_a_t, WIN32_FIND_DATAA>(dir, pfn, param);
  516. traits_t::set_last_error(dwRet);
  517. return ERROR_SUCCESS == dwRet;
  518. }
  519. /** Removes the given directory, and all its subdirectories.
  520. *
  521. * \ingroup group__library__filesystem
  522. */
  523. inline ws_bool_t remove_directory_recurse(ws_char_a_t const* dir)
  524. {
  525. return remove_directory_recurse(dir, NULL, NULL);
  526. }
  527. /** Removes the given directory, and all its subdirectories.
  528. *
  529. * \ingroup group__library__filesystem
  530. */
  531. inline ws_bool_t remove_directory_recurse(
  532. ws_char_w_t const* dir
  533. , ws_int_t (*pfn)(void* param, ws_char_w_t const* subDir, WIN32_FIND_DATAW const* st, DWORD err)
  534. , void* param
  535. )
  536. {
  537. typedef filesystem_traits<ws_char_w_t> traits_t;
  538. ws_dword_t dwRet = remove_directory_recurse_impl<ws_char_w_t, WIN32_FIND_DATAW>(dir, pfn, param);
  539. traits_t::set_last_error(dwRet);
  540. return ERROR_SUCCESS == dwRet;
  541. }
  542. /** Removes the given directory, and all its subdirectories.
  543. *
  544. * \ingroup group__library__filesystem
  545. */
  546. inline ws_bool_t remove_directory_recurse(ws_char_w_t const* dir)
  547. {
  548. return remove_directory_recurse(dir, NULL, NULL);
  549. }
  550. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  551. /** Removes the given directory, and all its subdirectories.
  552. *
  553. * \ingroup group__library__filesystem
  554. */
  555. template <ss_typename_param_k S>
  556. inline ws_bool_t remove_directory_recurse(S const& dir)
  557. {
  558. typedef filesystem_traits<ws_char_w_t> traits_t;
  559. ws_dword_t dwRet = remove_directory_recurse(stlsoft_ns_qual(c_str_ptr)(dir), NULL, NULL);
  560. traits_t::set_last_error(dwRet);
  561. return ERROR_SUCCESS == dwRet;
  562. }
  563. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  564. /* /////////////////////////////////////////////////////////////////////////
  565. * Unit-testing
  566. */
  567. #ifdef STLSOFT_UNITTEST
  568. # include "./unittest/directory_functions_unittest_.h"
  569. #endif /* STLSOFT_UNITTEST */
  570. /* ////////////////////////////////////////////////////////////////////// */
  571. #ifndef _WINSTL_NO_NAMESPACE
  572. # if defined(_STLSOFT_NO_NAMESPACE) || \
  573. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  574. } // namespace winstl
  575. # else
  576. } // namespace winstl_project
  577. } // namespace stlsoft
  578. # endif /* _STLSOFT_NO_NAMESPACE */
  579. #endif /* !_WINSTL_NO_NAMESPACE */
  580. /* ////////////////////////////////////////////////////////////////////// */
  581. #endif /* WINSTL_INCL_WINSTL_FILESYSTEM_HPP_DIRECTORY_FUNCTIONS */
  582. /* ///////////////////////////// end of file //////////////////////////// */