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.

2099 lines
60 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/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: 5th August 2012
  9. *
  10. * Thanks: To Sergey Nikulov, for spotting a preprocessor typo that
  11. * broke GCC -pedantic; to Michal Makowski and Zar Eindl for
  12. * reporting GCC 4.5+ problem with use of NULL in return
  13. * of invalid_file_handle_value().
  14. *
  15. * Home: http://stlsoft.org/
  16. *
  17. * Copyright (c) 2002-2012, Matthew Wilson and Synesis Software
  18. * All rights reserved.
  19. *
  20. * Redistribution and use in source and binary forms, with or without
  21. * modification, are permitted provided that the following conditions are
  22. * met:
  23. *
  24. * - Redistributions of source code must retain the above copyright notice,
  25. * this list of conditions and the following disclaimer.
  26. * - Redistributions in binary form must reproduce the above copyright
  27. * notice, this list of conditions and the following disclaimer in the
  28. * documentation and/or other materials provided with the distribution.
  29. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the
  30. * names of any contributors may be used to endorse or promote products
  31. * derived from this software without specific prior written permission.
  32. *
  33. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  34. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  35. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  36. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  37. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  38. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  39. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  40. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  41. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  42. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  43. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. *
  45. * ////////////////////////////////////////////////////////////////////// */
  46. /** \file unixstl/filesystem/filesystem_traits.hpp
  47. *
  48. * \brief [C++ only] Definition of the unixstl::filesystem_traits traits
  49. * class
  50. * (\ref group__library__filesystem "File System" Library).
  51. */
  52. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  53. #define UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  54. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  55. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 4
  56. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 10
  57. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 4
  58. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 133
  59. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  60. /* /////////////////////////////////////////////////////////////////////////
  61. * Includes
  62. */
  63. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  64. # include <unixstl/unixstl.h>
  65. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  66. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
  67. # include <stlsoft/memory/auto_buffer.hpp>
  68. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
  69. #ifndef UNIXSTL_INCL_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS
  70. # include <unixstl/system/system_traits.hpp>
  71. #endif /* !UNIXSTL_INCL_UNIXSTL_SYSTEM_HPP_SYSTEM_TRAITS */
  72. #ifdef _WIN32
  73. # include <ctype.h>
  74. #endif /* _WIN32 */
  75. #ifndef STLSOFT_INCL_H_ERRNO
  76. # define STLSOFT_INCL_H_ERRNO
  77. # include <errno.h>
  78. #endif /* !STLSOFT_INCL_H_ERRNO */
  79. #ifndef STLSOFT_INCL_H_FCNTL
  80. # define STLSOFT_INCL_H_FCNTL
  81. # include <fcntl.h>
  82. #endif /* !STLSOFT_INCL_H_FCNTL */
  83. #ifdef _WIN32
  84. # include <io.h>
  85. # if defined(STLSOFT_COMPILER_IS_INTEL) || \
  86. defined(STLSOFT_COMPILER_IS_MSVC)
  87. # include <direct.h>
  88. # endif /* os && compiler */
  89. #endif /* _WIN32 */
  90. #ifndef STLSOFT_INCL_H_DLFCN
  91. # define STLSOFT_INCL_H_DLFCN
  92. # include <dlfcn.h>
  93. #endif /* !STLSOFT_INCL_H_DLFCN */
  94. #ifndef STLSOFT_INCL_H_DIRENT
  95. # define STLSOFT_INCL_H_DIRENT
  96. # include <dirent.h>
  97. #endif /* !STLSOFT_INCL_H_DIRENT */
  98. #ifndef STLSOFT_INCL_H_LIMITS
  99. # define STLSOFT_INCL_H_LIMITS
  100. # include <limits.h>
  101. #endif /* !STLSOFT_INCL_H_LIMITS */
  102. #ifndef STLSOFT_INCL_H_STDIO
  103. # define STLSOFT_INCL_H_STDIO
  104. # include <stdio.h>
  105. #endif /* !STLSOFT_INCL_H_STDIO */
  106. #ifndef STLSOFT_INCL_H_STDLIB
  107. # define STLSOFT_INCL_H_STDLIB
  108. # include <stdlib.h>
  109. #endif /* !STLSOFT_INCL_H_STDLIB */
  110. #ifndef STLSOFT_INCL_H_STRING
  111. # define STLSOFT_INCL_H_STRING
  112. # include <string.h>
  113. #endif /* !STLSOFT_INCL_H_STRING */
  114. #ifndef STLSOFT_INCL_H_UNISTD
  115. # define STLSOFT_INCL_H_UNISTD
  116. # include <unistd.h>
  117. #endif /* !STLSOFT_INCL_H_UNISTD */
  118. #ifndef STLSOFT_INCL_H_WCHAR
  119. # define STLSOFT_INCL_H_WCHAR
  120. # include <wchar.h>
  121. #endif /* !STLSOFT_INCL_H_WCHAR */
  122. #ifndef STLSOFT_INCL_SYS_H_TYPES
  123. # define STLSOFT_INCL_SYS_H_TYPES
  124. # include <sys/types.h>
  125. #endif /* !STLSOFT_INCL_SYS_H_TYPES */
  126. #ifndef STLSOFT_INCL_SYS_H_STAT
  127. # define STLSOFT_INCL_SYS_H_STAT
  128. # include <sys/stat.h>
  129. #endif /* !STLSOFT_INCL_SYS_H_STAT */
  130. /* /////////////////////////////////////////////////////////////////////////
  131. * Namespace
  132. */
  133. #ifndef _UNIXSTL_NO_NAMESPACE
  134. # if defined(_STLSOFT_NO_NAMESPACE) || \
  135. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  136. /* There is no stlsoft namespace, so must define ::unixstl */
  137. namespace unixstl
  138. {
  139. # else
  140. /* Define stlsoft::unixstl_project */
  141. namespace stlsoft
  142. {
  143. namespace unixstl_project
  144. {
  145. # endif /* _STLSOFT_NO_NAMESPACE */
  146. #endif /* !_UNIXSTL_NO_NAMESPACE */
  147. /* /////////////////////////////////////////////////////////////////////////
  148. * Classes
  149. */
  150. #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
  151. /** \brief Traits class for file-system operations
  152. *
  153. * \ingroup group__library__filesystem
  154. *
  155. * filesystem_traits is a traits class for determining the correct file-system
  156. * structures and functions for a given character type.
  157. *
  158. * \param C The character type (e.g. \c char, \c wchar_t)
  159. */
  160. template <ss_typename_param_k C>
  161. struct filesystem_traits
  162. : public system_traits<C>
  163. {
  164. /// \name Types
  165. /// @{
  166. private:
  167. typedef system_traits<C> parent_class_type;
  168. public:
  169. /// \brief The character type
  170. typedef C char_type;
  171. /// \brief The size type
  172. typedef us_size_t size_type;
  173. /// \brief The difference type
  174. typedef us_ptrdiff_t difference_type;
  175. /// \brief The stat data type
  176. typedef struct stat stat_data_type;
  177. /// \brief The fstat data type
  178. typedef struct stat fstat_data_type;
  179. /// \brief The current instantion of the type
  180. typedef filesystem_traits<C> class_type;
  181. /// \brief The (signed) integer type
  182. typedef us_int_t int_type;
  183. /// \brief The Boolean type
  184. typedef us_bool_t bool_type;
  185. /// \brief The type of a system file handle
  186. typedef int file_handle_type;
  187. /// \brief The type of a handle to a dynamically loaded module
  188. typedef void* module_type;
  189. /// \brief The type of system error codes
  190. typedef int error_type;
  191. /// \brief The mode type
  192. #ifdef _WIN32
  193. typedef unsigned short mode_type;
  194. #else /* ? _WIN32 */
  195. typedef mode_t mode_type;
  196. #endif /* _WIN32 */
  197. /// @}
  198. /// \name Member Constants
  199. /// @{
  200. public:
  201. #ifdef PATH_MAX
  202. enum
  203. {
  204. maxPathLength = PATH_MAX //!< The maximum length of a path for the current file system
  205. };
  206. #endif /* PATH_MAX */
  207. enum
  208. {
  209. pathComparisonIsCaseSensitive = true
  210. };
  211. /// @}
  212. /// \name General string handling
  213. /// @{
  214. public:
  215. /// Compares the contents of \c src and \c dest, according to the
  216. /// lexicographical ordering on the host operating system.
  217. static int_type str_fs_compare(char_type const* s1, char_type const* s2);
  218. /// Compares the contents of \c src and \c dest up to \c cch
  219. /// characters. according to the lexicographical ordering on the host
  220. /// operating system.
  221. static int_type str_fs_n_compare(char_type const* s1, char_type const* s2, size_type cch);
  222. /// @}
  223. /// \name File-system entry names
  224. /// @{
  225. public:
  226. /// \brief Appends a path name separator to \c dir if one does not exist
  227. ///
  228. /// \see \link #path_name_separator path_name_separator() \endlink
  229. static char_type* ensure_dir_end(char_type* dir);
  230. /// \brief Removes the path name separator from the end of \c dir, if it has it
  231. ///
  232. /// \see \link #path_name_separator path_name_separator() \endlink
  233. static char_type* remove_dir_end(char_type* dir);
  234. /// \brief Returns \c true if \c dir has trailing path name separator
  235. ///
  236. /// \see \link #path_name_separator path_name_separator() \endlink
  237. static bool_type has_dir_end(char_type const* dir);
  238. /// Returns pointer to the next path_name_separator, or \c NULL if none found.
  239. static char_type const* find_next_path_name_separator(char_type const* path);
  240. /// Returns pointer to the last path_name_separator, or \c NULL if none found.
  241. static char_type const* find_last_path_name_separator(char_type const* path);
  242. /// \brief Returns \c true if dir is \c "." or \c ".."
  243. static bool_type is_dots(char_type const* dir);
  244. /// \brief Returns \c true if path is rooted
  245. ///
  246. /// \note Only enough characters of the path pointed to by \c path as are
  247. /// necessary to detect the presence or absence of the operating system's
  248. /// root character sequence(s).
  249. static bool_type is_path_rooted(char_type const* path);
  250. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  251. static bool_type is_path_rooted(
  252. char_type const* path
  253. , size_t cchPath
  254. );
  255. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  256. /// \brief Returns \c true if path is an absolute path
  257. ///
  258. /// \note Only enough characters of the path pointed to by \c path as are
  259. /// necessary to detect the presence or absence of the operating system's
  260. /// absolute path character sequence(s).
  261. static bool_type is_path_absolute(char_type const* path);
  262. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  263. static bool_type is_path_absolute(
  264. char_type const* path
  265. , size_t cchPath
  266. );
  267. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  268. /// \brief Returns \c true if path is a UNC path
  269. ///
  270. /// \note Only enough characters of the path pointed to by \c path as are
  271. /// necessary to detect the presence or absence of the UNC character sequence(s).
  272. static bool_type is_path_UNC(char_type const* path);
  273. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  274. static bool_type is_path_UNC(
  275. char_type const* path
  276. , size_t cchPath
  277. );
  278. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  279. /// \brief Indicates whether the given path is the root designator.
  280. ///
  281. /// The root designator is one of the following:
  282. /// - the slash character <code>/</code>
  283. ///
  284. /// The function returns false if the path contains any part of a
  285. /// file name (or extension), directory, or share.
  286. static bool_type is_root_designator(char_type const* path);
  287. /// \brief Returns \c true if the character is a path-name separator
  288. static bool_type is_path_name_separator(char_type ch);
  289. /// \brief Returns the path separator
  290. ///
  291. /// This is the separator that is used to separate multiple paths on the operating system. On UNIX it is ':'
  292. static char_type path_separator();
  293. /// \brief Returns the path name separator
  294. ///
  295. /// This is the separator that is used to separate parts of a path on the operating system. On UNIX it is '/'
  296. static char_type path_name_separator();
  297. /// \brief Returns the wildcard pattern that represents all possible matches
  298. ///
  299. /// \note On UNIX it is '*'
  300. static char_type const* pattern_all();
  301. /// \brief The maximum length of a path on the file-system
  302. ///
  303. /// \note Because not all systems support fixed maximum path lengths, the value of this function is notionally dynamic
  304. static size_type path_max();
  305. /// \brief Gets the full path name into the given buffer, returning a pointer to the file-part
  306. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile);
  307. /// \brief Gets the full path name into the given buffer
  308. static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer);
  309. /// \brief Gets the full path name into the given buffer
  310. ///
  311. /// \deprecated The other overload is now the preferred form
  312. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer);
  313. /// \brief Gets the short path name into the given buffer
  314. static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer);
  315. /// @}
  316. /// \name File-system enumeration
  317. /// @{
  318. public:
  319. // opendir/readdir API
  320. /// \brief Initiate a file-system search
  321. static DIR* open_dir(char_type const* dir);
  322. /// \brief Read an entry from the file-system search
  323. static struct dirent const* read_dir(DIR* h);
  324. /// \brief Closes the handle of the file-system search
  325. static void close_dir(DIR* h);
  326. /// @}
  327. /// \name File-system control
  328. /// @{
  329. public:
  330. /// \brief Sets the current directory to \c dir
  331. static bool_type set_current_directory(char_type const* dir);
  332. /// \brief Retrieves the name of the current directory into \c buffer up to a maximum of \c cchBuffer characters
  333. ///
  334. /// \deprecated The other overload is now the preferred form
  335. static size_type get_current_directory(size_type cchBuffer, char_type* buffer);
  336. /// \brief Retrieves the name of the current directory into \c buffer up to a maximum of \c cchBuffer characters
  337. static size_type get_current_directory(char_type* buffer, size_type cchBuffer);
  338. /// @}
  339. /// \name File-system state
  340. /// @{
  341. public:
  342. /// \brief Returns whether a file exists or not
  343. static bool_type file_exists(char_type const* path);
  344. /// \brief Returns whether the given path represents a file
  345. static bool_type is_file(char_type const* path);
  346. /// \brief Returns whether the given path represents a directory
  347. static bool_type is_directory(char_type const* path);
  348. #ifndef _WIN32
  349. /// \brief Returns whether the given path represents a socket
  350. static bool_type is_socket(char_type const* path);
  351. #endif /* OS */
  352. /// \brief Returns whether the given path represents a link
  353. static bool_type is_link(char_type const* path);
  354. /// \brief Gets the information for a particular file system entry
  355. static bool_type stat(char_type const* path, stat_data_type* stat_data);
  356. /// \brief Gets the information for a particular file system entry
  357. static bool_type lstat(char_type const* path, stat_data_type* stat_data);
  358. /// \brief Gets the information for a particular open file
  359. static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data);
  360. /// \brief Returns whether the given stat info represents a file
  361. static bool_type is_file(stat_data_type const* stat_data);
  362. /// \brief Returns whether the given stat info represents a directory
  363. static bool_type is_directory(stat_data_type const* stat_data);
  364. #ifndef _WIN32
  365. /// \brief Returns whether the given stat info represents a socket
  366. static bool_type is_socket(stat_data_type const* stat_data);
  367. #endif /* OS */
  368. /// \brief Returns whether the given stat info represents a link
  369. static bool_type is_link(stat_data_type const* stat_data);
  370. /// \brief Returns whether the given stat info represents a read-only entry
  371. static bool_type is_readonly(stat_data_type const* stat_data);
  372. /// @}
  373. /// \name File-system control
  374. /// @{
  375. public:
  376. /// \brief Creates a directory
  377. static bool_type create_directory(char_type const* dir);
  378. /// \brief Deletes a directory
  379. static bool_type remove_directory(char_type const* dir);
  380. /// \brief Delete a file
  381. static bool_type unlink_file(char_type const* file);
  382. /// \brief Delete a file
  383. ///
  384. /// \deprecated Users should use unlink_file()
  385. static bool_type delete_file(char_type const* file);
  386. /// \brief Rename a file
  387. static bool_type rename_file(char_type const* currentName, char_type const* newName);
  388. /// \brief Copy a file
  389. // static bool_type copy_file(char_type const* sourceName, char_type const* newName, bool_type bFailIfExists = false);
  390. /// The value returned by open_file() that indicates that the
  391. /// operation failed
  392. static file_handle_type invalid_file_handle_value();
  393. /// \brief Create / open a file
  394. static file_handle_type open_file(char_type const* fileName, int oflag, int pmode);
  395. /// \brief Closes the given operating system handle
  396. static bool_type close_file(file_handle_type fd);
  397. /// \brief Create / open a file
  398. ///
  399. /// \deprecated Users should use open_file()
  400. static file_handle_type open(char_type const* fileName, int oflag, int pmode);
  401. /// \brief Closes the given operating system handle
  402. ///
  403. /// \deprecated Users should use close_file()
  404. static bool_type close(file_handle_type fd);
  405. #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
  406. /// \brief Gets the size of the file
  407. static us_uint64_t get_file_size(file_handle_type fd);
  408. /// \brief Gets the size of the file
  409. static us_uint64_t get_file_size(stat_data_type const& sd);
  410. /// \brief Gets the size of the file
  411. ///
  412. /// \pre (NULL != psd)
  413. static us_uint64_t get_file_size(stat_data_type const* psd);
  414. #else /* ? STLSOFT_CF_64BIT_INT_SUPPORT */
  415. private:
  416. /// Not currently supported
  417. static void get_file_size(stat_data_type const*);
  418. /// Not currently supported
  419. static void get_file_size(stat_data_type const&);
  420. #endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
  421. /// @}
  422. };
  423. #else /* ? STLSOFT_DOCUMENTATION_SKIP_SECTION */
  424. #if 0
  425. struct filesystem_traits_util_
  426. {
  427. public:
  428. typedef struct stat stat_data_type;
  429. typedef us_bool_t bool_type;
  430. #ifdef _WIN32
  431. typedef unsigned short mode_type;
  432. #else /* ? _WIN32 */
  433. typedef mode_t mode_type;
  434. #endif /* _WIN32 */
  435. #if 1
  436. protected:
  437. #else /* ? 0 */
  438. public:
  439. #endif /* 0 */
  440. static bool_type is_file_type_(
  441. stat_data_type const* stat_data
  442. , mode_type typeModeBits
  443. )
  444. {
  445. return typeModeBits == (stat_data->st_mode & S_IFMT);
  446. }
  447. template <ss_typename_param_k C>
  448. static bool_type is_file_type_(
  449. C const* path
  450. , bool_type (*pfnstat)(C const*, stat_data_type*)
  451. , mode_type typeModeBits
  452. )
  453. {
  454. stat_data_type sd;
  455. return (*pfnstat)(path, &sd) && is_file_type_(&sd, typeModeBits);
  456. }
  457. };
  458. #endif /* 0 */
  459. template <ss_typename_param_k C>
  460. struct filesystem_traits;
  461. STLSOFT_TEMPLATE_SPECIALISATION
  462. struct filesystem_traits<us_char_a_t>
  463. : public system_traits<us_char_a_t>
  464. #if 0
  465. , protected filesystem_traits_util_
  466. #endif /* 0 */
  467. {
  468. public:
  469. typedef us_char_a_t char_type;
  470. typedef us_size_t size_type;
  471. typedef us_ptrdiff_t difference_type;
  472. typedef struct stat stat_data_type;
  473. typedef struct stat fstat_data_type;
  474. typedef filesystem_traits<us_char_a_t> class_type;
  475. typedef us_int_t int_type;
  476. typedef us_bool_t bool_type;
  477. typedef int file_handle_type;
  478. typedef void* module_type;
  479. typedef int error_type;
  480. #ifdef _WIN32
  481. typedef unsigned short mode_type;
  482. #else /* ? _WIN32 */
  483. typedef mode_t mode_type;
  484. #endif /* _WIN32 */
  485. private:
  486. typedef stlsoft_ns_qual(auto_buffer_old)<char_type> buffer_type_;
  487. public:
  488. #ifdef PATH_MAX
  489. enum
  490. {
  491. maxPathLength = PATH_MAX //!< The maximum length of a path for the current file system
  492. };
  493. #endif /* PATH_MAX */
  494. enum
  495. {
  496. #ifdef _WIN32
  497. pathComparisonIsCaseSensitive = false
  498. #else /* ? _WIN32 */
  499. pathComparisonIsCaseSensitive = true
  500. #endif /* _WIN32 */
  501. };
  502. public:
  503. static int_type str_fs_compare(char_type const* s1, char_type const* s2)
  504. {
  505. #ifdef _WIN32
  506. return str_compare_no_case(s1, s2);
  507. #else /* ? _WIN32 */
  508. return str_compare(s1, s2);
  509. #endif /* _WIN32 */
  510. }
  511. static int_type str_fs_n_compare(char_type const* s1, char_type const* s2, size_type cch)
  512. {
  513. #ifdef _WIN32
  514. return str_n_compare_no_case(s1, s2, cch);
  515. #else /* ? _WIN32 */
  516. return str_n_compare(s1, s2, cch);
  517. #endif /* _WIN32 */
  518. }
  519. static char_type* ensure_dir_end(char_type* dir)
  520. {
  521. UNIXSTL_ASSERT(NULL != dir);
  522. char_type* end = str_end(dir);
  523. if( dir < end &&
  524. !is_path_name_separator(*(end - 1)))
  525. {
  526. *end = path_name_separator();
  527. *(end + 1) = '\0';
  528. }
  529. return dir;
  530. }
  531. static char_type* remove_dir_end(char_type* dir)
  532. {
  533. UNIXSTL_ASSERT(NULL != dir);
  534. #ifdef _WIN32
  535. // Don't trim drive roots ...
  536. if( isalpha(dir[0]) &&
  537. ':' == dir[1] &&
  538. is_path_name_separator(dir[2]) &&
  539. '\0' == dir[3])
  540. {
  541. return dir;
  542. }
  543. // ... or UNC roots
  544. if( '\\' == dir[0] &&
  545. '\\' == dir[1] &&
  546. '\0' == dir[3])
  547. {
  548. return dir;
  549. }
  550. #endif /* _WIN32 */
  551. char_type* end = str_end(dir);
  552. if( dir < end &&
  553. is_path_name_separator(*(end - 1)))
  554. {
  555. *(end - 1) = '\0';
  556. }
  557. return dir;
  558. }
  559. static bool_type has_dir_end(char_type const* dir)
  560. {
  561. UNIXSTL_ASSERT(NULL != dir);
  562. size_type len = str_len(dir);
  563. return (0 < len) && is_path_name_separator(dir[len - 1]);
  564. }
  565. static
  566. char_type const*
  567. find_next_path_name_separator(char_type const* path)
  568. {
  569. char_type* pFile = str_chr(path, path_name_separator());
  570. #if defined(_WIN32)
  571. char_type* pFile2 = str_chr(path, '\\');
  572. if(NULL == pFile)
  573. {
  574. pFile = pFile2;
  575. }
  576. else if(NULL != pFile2)
  577. {
  578. if(pFile2 < pFile)
  579. {
  580. pFile = pFile2;
  581. }
  582. }
  583. #endif /* _WIN32 */
  584. return pFile;
  585. }
  586. static
  587. char_type const*
  588. find_last_path_name_separator(char_type const* path)
  589. {
  590. char_type* pFile = str_rchr(path, path_name_separator());
  591. #if defined(_WIN32)
  592. char_type* pFile2 = str_rchr(path, '\\');
  593. if(NULL == pFile)
  594. {
  595. pFile = pFile2;
  596. }
  597. else if(NULL != pFile2)
  598. {
  599. if(pFile2 > pFile)
  600. {
  601. pFile = pFile2;
  602. }
  603. }
  604. #endif /* _WIN32 */
  605. return pFile;
  606. }
  607. static bool_type is_dots(char_type const* dir)
  608. {
  609. UNIXSTL_ASSERT(NULL != dir);
  610. return dir[0] == '.' &&
  611. ( dir[1] == '\0' ||
  612. ( dir[1] == '.' &&
  613. dir[2] == '\0'));
  614. }
  615. static bool_type is_path_rooted(char_type const* path)
  616. {
  617. UNIXSTL_ASSERT(NULL != path);
  618. #ifdef _WIN32
  619. // It might be a UNC path. This is handled by the second test below, but
  620. // this is a bit clearer, and since this is a debug kind of thing, we're
  621. // not worried about the cost
  622. if( '\\' == path[0] &&
  623. '\\' == path[1])
  624. {
  625. return true;
  626. }
  627. // If it's really on Windows, then we need to skip the drive, if present
  628. if( isalpha(path[0]) &&
  629. ':' == path[1])
  630. {
  631. path += 2;
  632. }
  633. // If it's really on Windows, then we need to account for the fact that
  634. // the slash might be backwards, but that's taken care of for us by
  635. // is_path_name_separator()
  636. #endif /* _WIN32 */
  637. return is_path_name_separator(*path);
  638. }
  639. static bool_type is_path_rooted(
  640. char_type const* path
  641. , size_t cchPath
  642. )
  643. {
  644. UNIXSTL_ASSERT(NULL != path);
  645. #ifdef _WIN32
  646. if(cchPath >= 2)
  647. {
  648. // It might be a UNC path. This is handled by the second test below, but
  649. // this is a bit clearer, and since this is a debug kind of thing, we're
  650. // not worried about the cost
  651. if( '\\' == path[0] &&
  652. '\\' == path[1])
  653. {
  654. return true;
  655. }
  656. }
  657. if(cchPath >= 2)
  658. {
  659. // If it's really on Windows, then we need to skip the drive, if present
  660. if( isalpha(path[0]) &&
  661. ':' == path[1])
  662. {
  663. path += 2;
  664. cchPath -= 2;
  665. }
  666. }
  667. // If it's really on Windows, then we need to account for the fact that
  668. // the slash might be backwards, but that's taken care of for us by
  669. // is_path_name_separator()
  670. #endif /* _WIN32 */
  671. return 0 != cchPath && is_path_name_separator(*path);
  672. }
  673. static bool_type is_path_absolute(char_type const* path)
  674. {
  675. UNIXSTL_ASSERT(NULL != path);
  676. #ifdef _WIN32
  677. // If it's really on Windows, then it can only be absolute if ...
  678. //
  679. // ... it's a UNC path, or ...
  680. if(is_path_UNC(path))
  681. {
  682. return true;
  683. }
  684. // ... it's got drive + root slash, or
  685. if( isalpha(path[0]) &&
  686. ':' == path[1] &&
  687. is_path_name_separator(path[2]))
  688. {
  689. return true;
  690. }
  691. // ... it's got root forward slash
  692. if('/' == path[0])
  693. {
  694. return true;
  695. }
  696. return false;
  697. #else /* ? _WIN32 */
  698. return is_path_rooted(path);
  699. #endif /* _WIN32 */
  700. }
  701. static bool_type is_path_absolute(
  702. char_type const* path
  703. , size_t cchPath
  704. )
  705. {
  706. if(0 == cchPath)
  707. {
  708. return false;
  709. }
  710. #ifdef _WIN32
  711. // If it's really on Windows, then it can only be absolute if ...
  712. //
  713. // ... it's a UNC path, or ...
  714. if(is_path_UNC(path, cchPath))
  715. {
  716. return true;
  717. }
  718. if(cchPath >= 3)
  719. {
  720. // ... it's got drive + root slash, or
  721. if( isalpha(path[0]) &&
  722. ':' == path[1] &&
  723. is_path_name_separator(path[2]))
  724. {
  725. return true;
  726. }
  727. }
  728. // ... it's got root forward slash
  729. if('/' == path[0])
  730. {
  731. return true;
  732. }
  733. return false;
  734. #else /* ? _WIN32 */
  735. return is_path_rooted(path, cchPath);
  736. #endif /* _WIN32 */
  737. }
  738. static bool_type is_path_UNC(char_type const* path)
  739. {
  740. UNIXSTL_ASSERT(NULL != path);
  741. #ifdef _WIN32
  742. size_type const cchPath = str_len(path);
  743. return is_path_UNC(path, cchPath);
  744. #else /* ? _WIN32 */
  745. STLSOFT_SUPPRESS_UNUSED(path);
  746. return false;
  747. #endif /* _WIN32 */
  748. }
  749. static bool_type is_path_UNC(
  750. char_type const* path
  751. , size_t cchPath
  752. )
  753. {
  754. #ifdef _WIN32
  755. switch(cchPath)
  756. {
  757. case 0:
  758. case 1:
  759. return false;
  760. default:
  761. return '\\' == path[0] && '\\' == path[1];
  762. }
  763. #else /* ? _WIN32 */
  764. STLSOFT_SUPPRESS_UNUSED(path);
  765. STLSOFT_SUPPRESS_UNUSED(cchPath);
  766. return false;
  767. #endif /* _WIN32 */
  768. }
  769. private:
  770. static bool_type is_root_drive_(char_type const* path)
  771. {
  772. #ifdef _WIN32
  773. if( isalpha(path[0]) &&
  774. ':' == path[1] &&
  775. is_path_name_separator(path[2]) &&
  776. '\0' == path[3])
  777. {
  778. return true;
  779. }
  780. #else /* ? _WIN32 */
  781. STLSOFT_SUPPRESS_UNUSED(path);
  782. #endif /* _WIN32 */
  783. return false;
  784. }
  785. static bool_type is_root_UNC_(char_type const* path)
  786. {
  787. #ifdef _WIN32
  788. if(is_path_UNC(path))
  789. {
  790. char_type const* sep = str_pbrk(path + 2, "\\/");
  791. if( NULL == sep ||
  792. '\0' == sep[1])
  793. {
  794. return true;
  795. }
  796. }
  797. #else /* ? _WIN32 */
  798. STLSOFT_SUPPRESS_UNUSED(path);
  799. #endif /* _WIN32 */
  800. return false;
  801. }
  802. static bool_type is_root_directory_(char_type const* path)
  803. {
  804. if( is_path_name_separator(path[0]) &&
  805. '\0' == path[1])
  806. {
  807. return true;
  808. }
  809. return false;
  810. }
  811. public:
  812. static bool_type is_root_designator(char_type const* path)
  813. {
  814. UNIXSTL_ASSERT(NULL != path);
  815. return is_root_directory_(path) || is_root_drive_(path) || is_root_UNC_(path);
  816. }
  817. static bool_type is_path_name_separator(char_type ch)
  818. {
  819. #ifdef _WIN32
  820. if('\\' == ch)
  821. {
  822. return true;
  823. }
  824. #endif /* _WIN32 */
  825. return '/' == ch;
  826. }
  827. static char_type path_separator()
  828. {
  829. return ':';
  830. }
  831. static char_type path_name_separator()
  832. {
  833. return '/';
  834. }
  835. static char_type const* pattern_all()
  836. {
  837. return "*";
  838. }
  839. static size_type path_max()
  840. {
  841. #if defined(PATH_MAX)
  842. return PATH_MAX;
  843. #else /* ? PATH_MAX */
  844. return 1 + pathconf("/", _PC_PATH_MAX);
  845. #endif /* PATH_MAX */
  846. }
  847. private:
  848. // TODO: promote this to public
  849. static
  850. size_type
  851. get_root_len_(
  852. char_type const* path
  853. , size_type len
  854. )
  855. {
  856. if(0 == len)
  857. {
  858. return 0;
  859. }
  860. #ifdef _WIN32
  861. // If it's really on Windows, then we need to check for drive designator
  862. if( iswalpha(path[0]) &&
  863. ':' == path[1] &&
  864. is_path_name_separator(path[2]))
  865. {
  866. return 3;
  867. }
  868. // If it's really on Windows, then we need to skip the drive, if present
  869. if( '\\' == path[0] &&
  870. '\\' == path[1])
  871. {
  872. char_type const* slash2 = find_next_path_name_separator(path + 2);
  873. if(NULL == slash2)
  874. {
  875. #if 0
  876. SetLastError(ERROR_INVALID_ARGUMENT);
  877. #endif /* 0 */
  878. return 0;
  879. }
  880. else
  881. {
  882. return 1 + (slash2 - path);
  883. }
  884. }
  885. #endif /* _WIN32 */
  886. return is_path_name_separator(path[0]) ? 1 : 0;
  887. }
  888. static
  889. size_type
  890. get_root_len_(
  891. char_type const* path
  892. )
  893. {
  894. UNIXSTL_ASSERT(NULL != path);
  895. size_type const len = str_len(path);
  896. return get_root_len_(path, len);
  897. }
  898. static
  899. size_type
  900. get_full_path_name_impl2(
  901. char_type const* fileName
  902. , us_size_t const len
  903. , char_type* buffer
  904. , size_type cchBuffer
  905. )
  906. {
  907. if( NULL != buffer &&
  908. 0 == cchBuffer)
  909. {
  910. return 0;
  911. }
  912. // The next thing to so is determine whether the path is absolute, in
  913. // which case we'll just copy it into the buffer
  914. if(is_path_rooted(fileName))
  915. {
  916. // Given path is absolute, so simply copy into buffer
  917. if(NULL == buffer)
  918. {
  919. return len;
  920. }
  921. else if(cchBuffer < len + 1)
  922. {
  923. char_copy(&buffer[0], fileName, cchBuffer);
  924. return cchBuffer;
  925. }
  926. else
  927. {
  928. // Given buffer is large enough, so copy
  929. char_copy(&buffer[0], fileName, len);
  930. buffer[len] = '\0';
  931. return len;
  932. }
  933. }
  934. else
  935. {
  936. // Given path is relative, so get the current directory, and then concatenate
  937. buffer_type_ directory(1 + path_max());
  938. if(0 == directory.size())
  939. {
  940. set_last_error(ENOMEM);
  941. return 0;
  942. }
  943. else
  944. {
  945. size_type lenDir = get_current_directory(&directory[0], directory.size());
  946. if(0 == lenDir)
  947. {
  948. // The call failed, so indicate that to caller
  949. return 0;
  950. }
  951. else
  952. {
  953. if( '.' == fileName[0] &&
  954. ( 1 == len ||
  955. ( 2 == len &&
  956. '.' == fileName[1])))
  957. {
  958. if(1 == len)
  959. {
  960. // '.'
  961. if(NULL == buffer)
  962. {
  963. return lenDir;
  964. }
  965. }
  966. else
  967. if(2 == len)
  968. {
  969. // '..'
  970. size_t const rootLen = get_root_len_(directory.data(), lenDir);
  971. // Remove trailing slash, if any
  972. if( lenDir > rootLen &&
  973. has_dir_end(directory.data() + (lenDir - 1)))
  974. {
  975. remove_dir_end(directory.data() + (lenDir - 1));
  976. --lenDir;
  977. }
  978. if(lenDir > rootLen)
  979. {
  980. char_type* const lastSlash = const_cast<char_type*>(find_last_path_name_separator(directory.data() + rootLen));
  981. if(NULL != lastSlash)
  982. {
  983. size_t const newLen = lastSlash - directory.data();
  984. directory[newLen] = '\0';
  985. lenDir = newLen;
  986. }
  987. else
  988. {
  989. directory[rootLen] = '\0';
  990. lenDir = rootLen;
  991. }
  992. }
  993. if(NULL == buffer)
  994. {
  995. return lenDir;
  996. }
  997. }
  998. if(cchBuffer < lenDir + 1)
  999. {
  1000. char_copy(&buffer[0], directory.data(), cchBuffer);
  1001. return cchBuffer;
  1002. }
  1003. else
  1004. {
  1005. // Given buffer is large enough, so copy
  1006. char_copy(buffer, directory.data(), lenDir);
  1007. buffer[lenDir] = '\0';
  1008. return lenDir;
  1009. }
  1010. // For some reason OS-X's GCC needs this : it's confused.
  1011. #if defined(STLSOFT_COMPILER_IS_GCC) && \
  1012. STLSOFT_GCC_VER >= 40200 && \
  1013. STLSOFT_GCC_VER < 40300
  1014. UNIXSTL_ASSERT(0); // should never get here
  1015. return 0;
  1016. #endif
  1017. }
  1018. else
  1019. {
  1020. lenDir += str_len(ensure_dir_end(&directory[0] + (lenDir - 1))) - 1;
  1021. size_type const required = len + lenDir;
  1022. if(NULL == buffer)
  1023. {
  1024. return required;
  1025. }
  1026. else
  1027. {
  1028. if(cchBuffer < lenDir + 1)
  1029. {
  1030. char_copy(&buffer[0], directory.data(), cchBuffer);
  1031. return cchBuffer;
  1032. }
  1033. else
  1034. {
  1035. char_copy(&buffer[0], directory.data(), lenDir);
  1036. if(cchBuffer < required + 1)
  1037. {
  1038. char_copy(&buffer[0] + lenDir, fileName, cchBuffer - lenDir);
  1039. return cchBuffer;
  1040. }
  1041. else
  1042. {
  1043. char_copy(&buffer[0] + lenDir, fileName, len);
  1044. buffer[lenDir + len] = '\0';
  1045. return required;
  1046. }
  1047. }
  1048. }
  1049. }
  1050. }
  1051. }
  1052. }
  1053. }
  1054. static size_type get_full_path_name_impl(char_type const* fileName, us_size_t len, char_type* buffer, size_type cchBuffer)
  1055. {
  1056. UNIXSTL_ASSERT(len > 0);
  1057. if(NULL != class_type::str_pbrk(fileName, "<>|*?"))
  1058. {
  1059. errno = ENOENT;
  1060. return 0;
  1061. }
  1062. if('\0' != fileName[len])
  1063. {
  1064. buffer_type_ fileName_(1 + (len - 1));
  1065. // May be being compiled absent exception support, so need to check the
  1066. // file path buffers. (This _could_ be done with a compile-time #ifdef,
  1067. // but it's best not, since some translators support exceptions but yet
  1068. // don't throw on mem exhaustion, and in any case a user could change
  1069. // ::new)
  1070. if(0 == fileName_.size())
  1071. {
  1072. set_last_error(ENOMEM);
  1073. return 0;
  1074. }
  1075. else
  1076. {
  1077. fileName_[len] = '\0';
  1078. return get_full_path_name_impl2(char_copy(&fileName_[0], fileName, len)
  1079. , len
  1080. , buffer
  1081. , cchBuffer);
  1082. }
  1083. }
  1084. else
  1085. {
  1086. return get_full_path_name_impl2(fileName, len, buffer, cchBuffer);
  1087. }
  1088. }
  1089. public:
  1090. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
  1091. {
  1092. UNIXSTL_ASSERT(NULL != ppFile);
  1093. size_type r = get_full_path_name(fileName, buffer, cchBuffer);
  1094. *ppFile = NULL;
  1095. if( NULL != buffer &&
  1096. 0 != r &&
  1097. r <= cchBuffer)
  1098. {
  1099. size_type cchRequired = get_full_path_name(fileName, static_cast<char_type*>(NULL), 0);
  1100. if(r == cchRequired)
  1101. {
  1102. // Now search for the file separator
  1103. char_type* pFile = const_cast<char_type*>(find_last_path_name_separator(buffer));
  1104. if(NULL != (*ppFile = pFile))
  1105. {
  1106. (*ppFile)++;
  1107. }
  1108. }
  1109. }
  1110. return r;
  1111. }
  1112. static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  1113. {
  1114. UNIXSTL_ASSERT(NULL != fileName);
  1115. UNIXSTL_ASSERT(0 == cchBuffer || NULL != buffer);
  1116. if('\0' == *fileName)
  1117. {
  1118. static const char s_dot[2] = { '.', '\0' };
  1119. fileName = s_dot;
  1120. }
  1121. // Can't call realpath(), since that requires that the file exists
  1122. return get_full_path_name_impl(fileName, str_len(fileName), buffer, cchBuffer);
  1123. }
  1124. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  1125. {
  1126. return get_full_path_name(fileName, buffer, cchBuffer);
  1127. }
  1128. static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  1129. {
  1130. return get_full_path_name(fileName, cchBuffer, buffer);
  1131. }
  1132. // File-system enumeration
  1133. static DIR* open_dir(char_type const* dir)
  1134. {
  1135. return ::opendir(dir);
  1136. }
  1137. static struct dirent const* read_dir(DIR* h)
  1138. {
  1139. return ::readdir(h);
  1140. }
  1141. static void close_dir(DIR* h)
  1142. {
  1143. ::closedir(h);
  1144. }
  1145. // File-system state
  1146. static bool_type set_current_directory(char_type const* dir)
  1147. {
  1148. #if defined(_WIN32) && \
  1149. ( defined(STLSOFT_COMPILER_IS_MSVC) || \
  1150. defined(STLSOFT_COMPILER_IS_INTEL))
  1151. return 0 == ::_chdir(dir);
  1152. #else /* ? _WIN32 */
  1153. return 0 == ::chdir(dir);
  1154. #endif /* _WIN32 */
  1155. }
  1156. static size_type get_current_directory(size_type cchBuffer, char_type* buffer)
  1157. {
  1158. return get_current_directory(buffer, cchBuffer);
  1159. }
  1160. private:
  1161. static char_type const* call_getcwd_(char_type* buffer, size_type cchBuffer)
  1162. {
  1163. #if defined(STLSOFT_COMPILER_IS_INTEL) || \
  1164. defined(STLSOFT_COMPILER_IS_MSVC)
  1165. return ::_getcwd(buffer, cchBuffer);
  1166. #else /* ? compiler */
  1167. return ::getcwd(buffer, cchBuffer);
  1168. #endif /* compiler */
  1169. }
  1170. public:
  1171. static size_type get_current_directory(char_type* buffer, size_type cchBuffer)
  1172. {
  1173. #if defined(_WIN32)
  1174. char_type local[1 + _MAX_PATH];
  1175. size_type const cchLocal = STLSOFT_NUM_ELEMENTS(local);
  1176. #elif defined(PATH_MAX)
  1177. char_type local[1 + PATH_MAX];
  1178. size_type const cchLocal = STLSOFT_NUM_ELEMENTS(local);
  1179. #else
  1180. struct path_max_buffer
  1181. {
  1182. public:
  1183. typedef class_type traits_type_;
  1184. public:
  1185. path_max_buffer()
  1186. : n(traits_type_::path_max())
  1187. , p(new traits_type_::char_type[n + 1])
  1188. {
  1189. // check, for non-throwing new
  1190. if(NULL == p)
  1191. {
  1192. n = 0;
  1193. }
  1194. }
  1195. ~path_max_buffer() stlsoft_throw_0()
  1196. {
  1197. delete [] p;
  1198. }
  1199. private:
  1200. path_max_buffer(path_max_buffer const&) {}
  1201. path_max_buffer& operator =(path_max_buffer const&) { return *this; }
  1202. public:
  1203. size_type size() const
  1204. {
  1205. return n;
  1206. }
  1207. operator char_type* ()
  1208. {
  1209. return p;
  1210. }
  1211. private:
  1212. size_type n;
  1213. char_type* p;
  1214. };
  1215. path_max_buffer local;
  1216. size_type const cchLocal = local.size();
  1217. #endif /* _WIN32 */
  1218. char_type const* const dir = call_getcwd_(local, cchLocal);
  1219. if(NULL == dir)
  1220. {
  1221. return 0;
  1222. }
  1223. else
  1224. {
  1225. size_type const len = str_len(dir);
  1226. if(0 == cchBuffer)
  1227. {
  1228. return len;
  1229. }
  1230. else
  1231. {
  1232. size_type const n = (len < cchBuffer) ? len : cchBuffer;
  1233. char_copy(buffer, dir, n);
  1234. if(n < cchBuffer)
  1235. {
  1236. buffer[n] = '\0';
  1237. }
  1238. return n;
  1239. }
  1240. }
  1241. }
  1242. static bool_type file_exists(char_type const* fileName)
  1243. {
  1244. stat_data_type sd;
  1245. return class_type::stat(fileName, &sd) /* || errno != ENOENT */;
  1246. }
  1247. static bool_type is_file(char_type const* path)
  1248. {
  1249. stat_data_type sd;
  1250. return class_type::stat(path, &sd) && S_IFREG == (sd.st_mode & S_IFMT);
  1251. }
  1252. static bool_type is_directory(char_type const* path)
  1253. {
  1254. stat_data_type sd;
  1255. return class_type::stat(path, &sd) && S_IFDIR == (sd.st_mode & S_IFMT);
  1256. }
  1257. #ifndef _WIN32
  1258. static bool_type is_socket(char_type const* path)
  1259. {
  1260. stat_data_type sd;
  1261. return class_type::stat(path, &sd) && S_IFSOCK == (sd.st_mode & S_IFMT);
  1262. }
  1263. #endif /* OS */
  1264. static bool_type is_link(char_type const* path)
  1265. {
  1266. #ifdef _WIN32
  1267. STLSOFT_SUPPRESS_UNUSED(path);
  1268. return false;
  1269. #else /* ? _WIN32 */
  1270. stat_data_type sd;
  1271. return class_type::lstat(path, &sd) && S_IFLNK == (sd.st_mode & S_IFMT);
  1272. #endif /* _WIN32 */
  1273. }
  1274. static bool_type stat(char_type const* path, stat_data_type* stat_data)
  1275. {
  1276. UNIXSTL_ASSERT(NULL != path);
  1277. UNIXSTL_ASSERT(NULL != stat_data);
  1278. #ifdef _WIN32
  1279. if(NULL != class_type::str_pbrk(path, "*?"))
  1280. {
  1281. // Sometimes the VC6 CRT libs crash with a wildcard stat
  1282. set_last_error(EBADF);
  1283. return false;
  1284. }
  1285. if(has_dir_end(path))
  1286. {
  1287. // Win32 impl does not like a trailing slash
  1288. size_type len = str_len(path);
  1289. if( len > 3 ||
  1290. ( is_path_name_separator(*path) &&
  1291. len > 2))
  1292. {
  1293. buffer_type_ directory(1 + len);
  1294. if(0 == directory.size())
  1295. {
  1296. set_last_error(ENOMEM);
  1297. return false;
  1298. }
  1299. else
  1300. {
  1301. char_copy(&directory[0], path, len);
  1302. directory[len] = '\0';
  1303. class_type::remove_dir_end(&directory[0]);
  1304. return class_type::stat(directory.data(), stat_data);
  1305. }
  1306. }
  1307. }
  1308. #endif /* _WIN32 */
  1309. return 0 == ::stat(path, stat_data);
  1310. }
  1311. static bool_type lstat(char_type const* path, stat_data_type* stat_data)
  1312. {
  1313. UNIXSTL_ASSERT(NULL != path);
  1314. UNIXSTL_ASSERT(NULL != stat_data);
  1315. #ifdef _WIN32
  1316. return 0 == class_type::stat(path, stat_data);
  1317. #else /* ? _WIN32 */
  1318. return 0 == ::lstat(path, stat_data);
  1319. #endif /* _WIN32 */
  1320. }
  1321. static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data)
  1322. {
  1323. UNIXSTL_ASSERT(-1 != fd);
  1324. UNIXSTL_ASSERT(NULL != fstat_data);
  1325. return 0 == ::fstat(fd, fstat_data);
  1326. }
  1327. static bool_type is_file(stat_data_type const* stat_data)
  1328. {
  1329. #if 1
  1330. return S_IFREG == (stat_data->st_mode & S_IFMT);
  1331. #else
  1332. return filesystem_traits_util_::is_file_type_(stat_data, S_IFREG);
  1333. #endif
  1334. }
  1335. static bool_type is_directory(stat_data_type const* stat_data)
  1336. {
  1337. #if 1
  1338. return S_IFDIR == (stat_data->st_mode & S_IFMT);
  1339. #else /* ? 0 */
  1340. return filesystem_traits_util_::is_file_type_(stat_data, S_IFDIR);
  1341. #endif /* 0 */
  1342. }
  1343. #ifndef _WIN32
  1344. static bool_type is_socket(stat_data_type const* stat_data)
  1345. {
  1346. #if 1
  1347. return S_IFSOCK == (stat_data->st_mode & S_IFMT);
  1348. #else /* ? 0 */
  1349. return filesystem_traits_util_::is_file_type_(stat_data, S_IFSOCK);
  1350. #endif /* 0 */
  1351. }
  1352. #endif /* OS */
  1353. static bool_type is_link(stat_data_type const* stat_data)
  1354. {
  1355. #ifdef _WIN32
  1356. STLSOFT_SUPPRESS_UNUSED(stat_data);
  1357. return false;
  1358. #else /* ? _WIN32 */
  1359. #if 1
  1360. return S_IFLNK == (stat_data->st_mode & S_IFMT);
  1361. #else /* ? 0 */
  1362. return filesystem_traits_util_::is_file_type_(stat_data, S_IFLNK);
  1363. #endif /* 0 */
  1364. #endif /* _WIN32 */
  1365. }
  1366. static bool_type is_readonly(stat_data_type const* stat_data)
  1367. {
  1368. #ifdef _WIN32
  1369. return S_IREAD == (stat_data->st_mode & (S_IREAD | S_IWRITE));
  1370. #else /* ? _WIN32 */
  1371. return S_IRUSR == (stat_data->st_mode & (S_IRUSR | S_IWUSR));
  1372. #endif /* _WIN32 */
  1373. }
  1374. static bool_type create_directory(char_type const* dir)
  1375. {
  1376. mode_type mode = 0;
  1377. #ifdef _WIN32
  1378. mode = S_IREAD | S_IWRITE | S_IEXEC;
  1379. #else /* ? _WIN32 */
  1380. mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
  1381. #endif /* _WIN32 */
  1382. return create_directory(dir, mode);
  1383. }
  1384. static bool_type create_directory(char_type const* dir, mode_type permissions)
  1385. {
  1386. #if defined(_WIN32) && \
  1387. ( defined(STLSOFT_COMPILER_IS_INTEL) || \
  1388. defined(STLSOFT_COMPILER_IS_GCC) || \
  1389. defined(STLSOFT_COMPILER_IS_MSVC))
  1390. STLSOFT_SUPPRESS_UNUSED(permissions);
  1391. return 0 == ::_mkdir(dir);
  1392. #else /* ? _WIN32 */
  1393. return 0 == ::mkdir(dir, permissions);
  1394. #endif /* _WIN32 */
  1395. }
  1396. static bool_type remove_directory(char_type const* dir)
  1397. {
  1398. #if defined(_WIN32) && \
  1399. ( defined(STLSOFT_COMPILER_IS_INTEL) || \
  1400. defined(STLSOFT_COMPILER_IS_MSVC))
  1401. return 0 == ::_rmdir(dir);
  1402. #else /* ? _WIN32 */
  1403. return 0 == ::rmdir(dir);
  1404. #endif /* _WIN32 */
  1405. }
  1406. static bool_type unlink_file(char_type const* file)
  1407. {
  1408. return 0 == ::remove(file);
  1409. }
  1410. static bool_type delete_file(char_type const* file)
  1411. {
  1412. return unlink_file(file);
  1413. }
  1414. static bool_type rename_file(char_type const* currentName, char_type const* newName)
  1415. {
  1416. return 0 == ::rename(currentName, newName);
  1417. }
  1418. #if ( defined(STLSOFT_COMPILER_IS_MSVC) || \
  1419. defined(STLSOFT_COMPILER_IS_INTEL)) && \
  1420. defined(STLSOFT_USING_SAFE_STR_FUNCTIONS)
  1421. # if _MSC_VER >= 1200
  1422. # pragma warning(push)
  1423. # endif /* compiler */
  1424. # pragma warning(disable : 4996)
  1425. #endif /* compiler */
  1426. static file_handle_type invalid_file_handle_value()
  1427. {
  1428. return -1;
  1429. }
  1430. static file_handle_type open_file(char_type const* fileName, int oflag, int pmode)
  1431. {
  1432. #if defined(_WIN32) && \
  1433. ( defined(STLSOFT_COMPILER_IS_INTEL) || \
  1434. defined(STLSOFT_COMPILER_IS_MSVC))
  1435. return ::_open(fileName, oflag, pmode);
  1436. #else /* ? _WIN32 */
  1437. return ::open(fileName, oflag, pmode);
  1438. #endif /* _WIN32 */
  1439. }
  1440. #if ( defined(STLSOFT_COMPILER_IS_MSVC) || \
  1441. defined(STLSOFT_COMPILER_IS_INTEL)) && \
  1442. defined(STLSOFT_USING_SAFE_STR_FUNCTIONS)
  1443. # if _MSC_VER >= 1200
  1444. # pragma warning(pop)
  1445. # else /* ? compiler */
  1446. # pragma warning(default : 4996)
  1447. # endif /* _MSC_VER */
  1448. #endif /* compiler */
  1449. static bool_type close_file(file_handle_type fd)
  1450. {
  1451. #if defined(_WIN32) && \
  1452. ( defined(STLSOFT_COMPILER_IS_INTEL) || \
  1453. defined(STLSOFT_COMPILER_IS_MSVC))
  1454. return 0 == ::_close(fd);
  1455. #else /* ? _WIN32 */
  1456. return 0 == ::close(fd);
  1457. #endif /* _WIN32 */
  1458. }
  1459. static file_handle_type open(char_type const* fileName, int oflag, int pmode)
  1460. {
  1461. return class_type::open_file(fileName, oflag, pmode);
  1462. }
  1463. static bool_type close(file_handle_type fd)
  1464. {
  1465. return class_type::close_file(fd);
  1466. }
  1467. #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
  1468. static us_uint64_t get_file_size(file_handle_type fd)
  1469. {
  1470. struct stat st;
  1471. return class_type::fstat(fd, &st) ? st.st_size : 0;
  1472. }
  1473. static us_uint64_t get_file_size(stat_data_type const& sd)
  1474. {
  1475. return sd.st_size;
  1476. }
  1477. static us_uint64_t get_file_size(stat_data_type const* psd)
  1478. {
  1479. UNIXSTL_ASSERT(NULL != psd);
  1480. return get_file_size(*psd);
  1481. }
  1482. #endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
  1483. };
  1484. STLSOFT_TEMPLATE_SPECIALISATION
  1485. struct filesystem_traits<us_char_w_t>
  1486. : public system_traits<us_char_w_t>
  1487. #if 0
  1488. , protected filesystem_traits_util_
  1489. #endif /* 0 */
  1490. {
  1491. public:
  1492. typedef us_char_w_t char_type;
  1493. typedef us_size_t size_type;
  1494. #ifdef PATH_MAX
  1495. enum
  1496. {
  1497. maxPathLength = PATH_MAX //!< The maximum length of a path for the current file system
  1498. };
  1499. #endif /* PATH_MAX */
  1500. enum
  1501. {
  1502. #ifdef _WIN32
  1503. pathComparisonIsCaseSensitive = false
  1504. #else /* ? _WIN32 */
  1505. pathComparisonIsCaseSensitive = true
  1506. #endif /* _WIN32 */
  1507. };
  1508. public:
  1509. static int_type str_fs_compare(char_type const* s1, char_type const* s2)
  1510. {
  1511. #ifdef _WIN32
  1512. return str_compare_no_case(s1, s2);
  1513. #else /* ? _WIN32 */
  1514. return str_compare(s1, s2);
  1515. #endif /* _WIN32 */
  1516. }
  1517. static int_type str_fs_n_compare(char_type const* s1, char_type const* s2, size_type cch)
  1518. {
  1519. #ifdef _WIN32
  1520. return str_n_compare_no_case(s1, s2, cch);
  1521. #else /* ? _WIN32 */
  1522. return str_n_compare(s1, s2, cch);
  1523. #endif /* _WIN32 */
  1524. }
  1525. static char_type* ensure_dir_end(char_type* dir)
  1526. {
  1527. UNIXSTL_ASSERT(NULL != dir);
  1528. char_type* end = str_end(dir);
  1529. if( dir < end &&
  1530. !is_path_name_separator(*(end - 1)))
  1531. {
  1532. *end = path_name_separator();
  1533. *(end + 1) = L'\0';
  1534. }
  1535. return dir;
  1536. }
  1537. static char_type* remove_dir_end(char_type* dir)
  1538. {
  1539. UNIXSTL_ASSERT(NULL != dir);
  1540. #ifdef _WIN32
  1541. // Don't trim drive roots ...
  1542. if( iswalpha(dir[0]) &&
  1543. L':' == dir[1] &&
  1544. is_path_name_separator(dir[2]) &&
  1545. L'\0' == dir[3])
  1546. {
  1547. return dir;
  1548. }
  1549. // ... or UNC roots
  1550. if( L'\\' == dir[0] &&
  1551. L'\\' == dir[1] &&
  1552. L'\0' == dir[3])
  1553. {
  1554. return dir;
  1555. }
  1556. #endif /* _WIN32 */
  1557. char_type* end = str_end(dir);
  1558. if( dir < end &&
  1559. is_path_name_separator(*(end - 1)))
  1560. {
  1561. *(end - 1) = L'\0';
  1562. }
  1563. return dir;
  1564. }
  1565. static bool_type has_dir_end(char_type const* dir)
  1566. {
  1567. UNIXSTL_ASSERT(NULL != dir);
  1568. size_type len = str_len(dir);
  1569. return (0 < len) && is_path_name_separator(dir[len - 1]);
  1570. }
  1571. static
  1572. char_type const*
  1573. find_next_path_name_separator(char_type const* path)
  1574. {
  1575. char_type* pFile = str_chr(path, path_name_separator());
  1576. #if defined(_WIN32)
  1577. char_type* pFile2 = str_chr(path, L'\\');
  1578. if(NULL == pFile)
  1579. {
  1580. pFile = pFile2;
  1581. }
  1582. else if(NULL != pFile2)
  1583. {
  1584. if(pFile2 < pFile)
  1585. {
  1586. pFile = pFile2;
  1587. }
  1588. }
  1589. #endif /* _WIN32 */
  1590. return pFile;
  1591. }
  1592. static
  1593. char_type const*
  1594. find_last_path_name_separator(char_type const* path)
  1595. {
  1596. char_type* pFile = str_rchr(path, path_name_separator());
  1597. #if defined(_WIN32)
  1598. char_type* pFile2 = str_rchr(path, L'\\');
  1599. if(NULL == pFile)
  1600. {
  1601. pFile = pFile2;
  1602. }
  1603. else if(NULL != pFile2)
  1604. {
  1605. if(pFile2 > pFile)
  1606. {
  1607. pFile = pFile2;
  1608. }
  1609. }
  1610. #endif /* _WIN32 */
  1611. return pFile;
  1612. }
  1613. static bool_type is_dots(char_type const* dir)
  1614. {
  1615. UNIXSTL_ASSERT(NULL != dir);
  1616. return dir[0] == '.' &&
  1617. ( dir[1] == L'\0' ||
  1618. ( dir[1] == L'.' &&
  1619. dir[2] == L'\0'));
  1620. }
  1621. static bool_type is_path_rooted(char_type const* path)
  1622. {
  1623. UNIXSTL_ASSERT(NULL != path);
  1624. #ifdef _WIN32
  1625. // If it's really on Windows, then we need to skip the drive, if present
  1626. if( iswalpha(path[0]) &&
  1627. ':' == path[1])
  1628. {
  1629. path += 2;
  1630. }
  1631. // If it's really on Windows, then we need to account for the fact that
  1632. // the slash might be backwards
  1633. if('\\' == *path)
  1634. {
  1635. return true;
  1636. }
  1637. #endif /* _WIN32 */
  1638. return '/' == *path;
  1639. }
  1640. static bool_type is_path_rooted(
  1641. char_type const* path
  1642. , size_t cchPath
  1643. )
  1644. {
  1645. UNIXSTL_ASSERT(NULL != path);
  1646. #ifdef _WIN32
  1647. if(cchPath >= 2)
  1648. {
  1649. // It might be a UNC path. This is handled by the second test below, but
  1650. // this is a bit clearer, and since this is a debug kind of thing, we're
  1651. // not worried about the cost
  1652. if( L'\\' == path[0] &&
  1653. L'\\' == path[1])
  1654. {
  1655. return true;
  1656. }
  1657. }
  1658. if(cchPath >= 2)
  1659. {
  1660. // If it's really on Windows, then we need to skip the drive, if present
  1661. if( iswalpha(path[0]) &&
  1662. L':' == path[1])
  1663. {
  1664. path += 2;
  1665. cchPath -= 2;
  1666. }
  1667. }
  1668. // If it's really on Windows, then we need to account for the fact that
  1669. // the slash might be backwards, but that's taken care of for us by
  1670. // is_path_name_separator()
  1671. #endif /* _WIN32 */
  1672. return 0 != cchPath && is_path_name_separator(*path);
  1673. }
  1674. static bool_type is_path_absolute(char_type const* path)
  1675. {
  1676. UNIXSTL_ASSERT(NULL != path);
  1677. #ifdef _WIN32
  1678. return is_path_absolute(path, str_len(path));
  1679. #else /* ? _WIN32 */
  1680. return is_path_rooted(path);
  1681. #endif /* _WIN32 */
  1682. }
  1683. static bool_type is_path_absolute(
  1684. char_type const* path
  1685. , size_t cchPath
  1686. )
  1687. {
  1688. if(0 == cchPath)
  1689. {
  1690. return false;
  1691. }
  1692. #ifdef _WIN32
  1693. // If it's really on Windows, then it can only be absolute if ...
  1694. //
  1695. // ... it's a UNC path, or ...
  1696. if(is_path_UNC(path, cchPath))
  1697. {
  1698. return true;
  1699. }
  1700. if(cchPath >= 3)
  1701. {
  1702. // ... it's got drive + root slash, or
  1703. if( iswalpha(path[0]) &&
  1704. L':' == path[1] &&
  1705. is_path_name_separator(path[2]))
  1706. {
  1707. return true;
  1708. }
  1709. }
  1710. // ... it's got root forward slash
  1711. if(L'/' == path[0])
  1712. {
  1713. return true;
  1714. }
  1715. return false;
  1716. #else /* ? _WIN32 */
  1717. return is_path_rooted(path, cchPath);
  1718. #endif /* _WIN32 */
  1719. }
  1720. static bool_type is_path_UNC(char_type const* path)
  1721. {
  1722. UNIXSTL_ASSERT(NULL != path);
  1723. #ifdef _WIN32
  1724. size_type const cchPath = str_len(path);
  1725. return is_path_UNC(path, cchPath);
  1726. #else /* ? _WIN32 */
  1727. STLSOFT_SUPPRESS_UNUSED(path);
  1728. return false;
  1729. #endif /* _WIN32 */
  1730. }
  1731. static bool_type is_path_UNC(
  1732. char_type const* path
  1733. , size_t cchPath
  1734. )
  1735. {
  1736. #ifdef _WIN32
  1737. switch(cchPath)
  1738. {
  1739. case 0:
  1740. case 1:
  1741. return false;
  1742. default:
  1743. return L'\\' == path[0] && L'\\' == path[1];
  1744. }
  1745. #else /* ? _WIN32 */
  1746. STLSOFT_SUPPRESS_UNUSED(path);
  1747. STLSOFT_SUPPRESS_UNUSED(cchPath);
  1748. return false;
  1749. #endif /* _WIN32 */
  1750. }
  1751. static bool_type is_path_name_separator(char_type ch)
  1752. {
  1753. #ifdef _WIN32
  1754. if(L'\\' == ch)
  1755. {
  1756. return true;
  1757. }
  1758. #endif /* _WIN32 */
  1759. return L'/' == ch;
  1760. }
  1761. static char_type path_separator()
  1762. {
  1763. return L':';
  1764. }
  1765. static char_type path_name_separator()
  1766. {
  1767. return L'/';
  1768. }
  1769. static char_type const* pattern_all()
  1770. {
  1771. return L"*";
  1772. }
  1773. static size_type path_max()
  1774. {
  1775. #if defined(PATH_MAX)
  1776. return PATH_MAX;
  1777. #else /* ? PATH_MAX */
  1778. return 1 + pathconf("/", _PC_PATH_MAX);
  1779. #endif /* PATH_MAX */
  1780. }
  1781. #if 0
  1782. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile);
  1783. static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
  1784. {
  1785. char_type* pFile;
  1786. return get_full_path_name(fileName, cchBuffer, buffer, &pFile);
  1787. }
  1788. static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  1789. {
  1790. return get_full_path_name(fileName, buffer, cchBuffer);
  1791. }
  1792. static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
  1793. {
  1794. return get_full_path_name(fileName, cchBuffer, buffer);
  1795. }
  1796. #endif /* 0 */
  1797. // File-system state
  1798. static bool_type set_current_directory(char_type const* dir);
  1799. static size_type get_current_directory(size_type cchBuffer, char_type* buffer);
  1800. static size_type get_current_directory(char_type* buffer, size_type cchBuffer);
  1801. };
  1802. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1803. /* /////////////////////////////////////////////////////////////////////////
  1804. * Unit-testing
  1805. */
  1806. #ifdef STLSOFT_UNITTEST
  1807. # include "./unittest/filesystem_traits_unittest_.h"
  1808. #endif /* STLSOFT_UNITTEST */
  1809. /* ////////////////////////////////////////////////////////////////////// */
  1810. #ifndef _UNIXSTL_NO_NAMESPACE
  1811. # if defined(_STLSOFT_NO_NAMESPACE) || \
  1812. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1813. } // namespace unixstl
  1814. # else
  1815. } // namespace unixstl_project
  1816. } // namespace stlsoft
  1817. # endif /* _STLSOFT_NO_NAMESPACE */
  1818. #endif /* !_UNIXSTL_NO_NAMESPACE */
  1819. /* ////////////////////////////////////////////////////////////////////// */
  1820. #endif /* UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  1821. /* ///////////////////////////// end of file //////////////////////////// */