00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00049 #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
00050 #define WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
00051
00052 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00053 # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MAJOR 4
00054 # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_MINOR 5
00055 # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_REVISION 10
00056 # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS_EDIT 120
00057 #endif
00058
00059
00060
00061
00062
00063 #ifndef WINSTL_INCL_WINSTL_H_WINSTL
00064 # include <winstl/winstl.h>
00065 #endif
00066
00067 #ifdef WINSTL_OS_IS_WIN64
00068 # define _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
00069 #endif
00070
00071 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
00072 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00073 # ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_CAST
00074 # include <stlsoft/conversion/truncation_cast.hpp>
00075 # endif
00076 # else
00077 # ifndef STLSOFT_INCL_STLSOFT_CONVERSION_HPP_TRUNCATION_TEST
00078 # include <stlsoft/conversion/truncation_test.hpp>
00079 # endif
00080 # endif
00081 #endif
00082
00083 #ifndef STLSOFT_INCL_STLSOFT_HPP_MEMORY_AUTO_BUFFER
00084 # include <stlsoft/memory/auto_buffer.hpp>
00085 #endif
00086 #ifndef WINSTL_INCL_WINSTL_SYSTEM_HPP_SYSTEM_TRAITS
00087 # include <winstl/system/system_traits.hpp>
00088 #endif
00089
00090 #ifndef STLSOFT_INCL_H_CTYPE
00091 # define STLSOFT_INCL_H_CTYPE
00092 # include <ctype.h>
00093 #endif
00094 #ifndef STLSOFT_INCL_H_STRING
00095 # define STLSOFT_INCL_H_STRING
00096 # include <string.h>
00097 #endif
00098 #ifndef STLSOFT_INCL_H_WCHAR
00099 # define STLSOFT_INCL_H_WCHAR
00100 # include <wchar.h>
00101 #endif
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00115
00116 #if !defined(_WINSTL_NO_FINDVOLUME_API)
00117 # if !defined(_WIN32_WINNT) || \
00118 (_WIN32_WINNT < 0x0500) || \
00119 !defined(FindFirstVolume) || \
00120 !defined(FindNextVolume)
00121
00122 # define WINSTL_FINDVOLUME_API_NOT_DECLARED
00123
00124 HANDLE WINAPI FindFirstVolumeA(
00125 LPSTR lpszVolumeName,
00126 DWORD cchBufferLength
00127 );
00128
00129 HANDLE WINAPI FindFirstVolumeW(
00130 LPWSTR lpszVolumeName,
00131 DWORD cchBufferLength
00132 );
00133
00134 BOOL WINAPI FindNextVolumeA(
00135 HANDLE hFindVolume,
00136 LPSTR lpszVolumeName,
00137 DWORD cchBufferLength
00138 );
00139
00140 BOOL WINAPI FindNextVolumeW(
00141 HANDLE hFindVolume,
00142 LPWSTR lpszVolumeName,
00143 DWORD cchBufferLength
00144 );
00145
00146 BOOL WINAPI FindVolumeClose(
00147 HANDLE hFindVolume
00148 );
00149
00150 # endif
00151 # endif
00152
00153 #endif
00154
00155
00156
00157
00158
00159 #ifndef _WINSTL_NO_NAMESPACE
00160 # if defined(_STLSOFT_NO_NAMESPACE) || \
00161 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00162
00163 namespace winstl
00164 {
00165 # else
00166
00167
00168 namespace stlsoft
00169 {
00170
00171 namespace winstl_project
00172 {
00173
00174 # endif
00175 #endif
00176
00177
00178
00179
00180
00181 #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
00182
00191 template <ss_typename_param_k C>
00192 struct filesystem_traits
00193 : public system_traits<C>
00194 {
00197 private:
00198 typedef system_traits<C> parent_class_type;
00199 public:
00201 typedef C char_type;
00203 typedef ws_size_t size_type;
00205 typedef ws_ptrdiff_t difference_type;
00207 typedef WIN32_FIND_DATA find_data_type;
00209 typedef WIN32_FIND_DATA stat_data_type;
00211 typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
00213 typedef filesystem_traits<C> class_type;
00214
00216 typedef ws_int_t int_type;
00218 typedef ws_bool_t bool_type;
00220 typedef HANDLE file_handle_type;
00222 typedef HINSTANCE module_type;
00224 typedef DWORD error_type;
00226
00229 public:
00230 enum
00231 {
00232 maxPathLength = 1 + WINSTL_CONST_MAX_PATH
00233 };
00235
00238 public:
00242 static char_type* ensure_dir_end(char_type* dir);
00246 static char_type* remove_dir_end(char_type* dir);
00250 static bool_type has_dir_end(char_type const* dir);
00251
00253 static bool_type is_dots(char_type const* dir);
00259 static bool_type is_path_rooted(char_type const* path);
00265 static bool_type is_path_absolute(char_type const* path);
00270 static bool_type is_path_UNC(char_type const* path);
00281 static bool_type is_root_designator(char_type const* path);
00285 static bool_type is_path_name_separator(char_type ch);
00286
00290 static char_type path_separator();
00294 static char_type path_name_separator();
00298 static char_type const* pattern_all();
00302 static size_type path_max();
00304 static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile);
00306 static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer);
00310 static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer);
00314 static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer);
00316 static size_type get_short_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer);
00318
00321 public:
00322
00323
00325 static HANDLE find_first_file(char_type const* spec, find_data_type* findData);
00326 #if _WIN32_WINNT >= 0x0400
00328 static HANDLE find_first_file_ex(char_type const* spec, FINDEX_SEARCH_OPS flags, find_data_type* findData);
00329 #endif
00331 static bool_type find_next_file(HANDLE h, find_data_type* findData);
00333 static void find_file_close(HANDLE h);
00334
00335
00336
00337 #ifndef _WINSTL_NO_FINDVOLUME_API
00339 static HANDLE find_first_volume(char_type* volume_name, size_type cch_volume_name);
00341 static bool_type find_next_volume(HANDLE h, char_type* volume_name, size_type cch_volume_name);
00343 static void find_volume_close(HANDLE h);
00344 #endif // !_WINSTL_NO_FINDVOLUME_API
00346
00349 public:
00351 static bool_type set_current_directory(char_type const* dir);
00355 static size_type get_current_directory(size_type cchBuffer, char_type* buffer);
00357 static size_type get_current_directory(char_type* buffer, size_type cchBuffer);
00359
00362 public:
00364 static bool_type file_exists(char_type const* path);
00366 static bool_type is_file(char_type const* path);
00368 static bool_type is_directory(char_type const* path);
00370 static bool_type stat(char_type const* path, stat_data_type* stat_data);
00372 static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data);
00373
00375 static bool_type is_file(stat_data_type const* stat_data);
00376 static bool_type is_file(fstat_data_type const* stat_data);
00378 static bool_type is_directory(stat_data_type const* stat_data);
00379 static bool_type is_directory(fstat_data_type const* stat_data);
00381 static bool_type is_link(stat_data_type const* stat_data);
00382 static bool_type is_link(fstat_data_type const* stat_data);
00384 static bool_type is_readonly(stat_data_type const* stat_data);
00385 static bool_type is_readonly(fstat_data_type const* stat_data);
00386
00388 static bool_type drive_exists(char_type driveLetter);
00392 static DWORD get_drive_type(char_type driveLetter);
00394
00397 public:
00399 static bool_type create_directory(char_type const* dir);
00401 static bool_type create_directory(char_type const* dir, LPSECURITY_ATTRIBUTES lpsa);
00403 static bool_type remove_directory(char_type const* dir);
00404
00406 static bool_type unlink_file(char_type const* file);
00410 static bool_type delete_file(char_type const* file);
00412 static bool_type rename_file(char_type const* currentName, char_type const* newName);
00414 static bool_type copy_file(char_type const* sourceName, char_type const* newName, bool_type bFailIfExists = false);
00415
00417 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);
00419 static bool_type close_file(file_handle_type h);
00420 #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
00422 static ws_uint64_t get_file_size(file_handle_type h);
00423 #endif
00424 private:
00426 static void get_file_size(stat_data_type const*);
00428 static void get_file_size(stat_data_type const&);
00430 };
00431
00432 #else
00433
00434 template <ss_typename_param_k C>
00435 struct filesystem_traits;
00436
00437 struct filesystem_traits_
00438 : public system_traits_
00439 {
00440 public:
00441 typedef ws_size_t size_type;
00442 typedef ws_ptrdiff_t difference_type;
00443 typedef filesystem_traits_ class_type;
00444 typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
00445 typedef ws_int_t int_type;
00446 typedef ws_bool_t bool_type;
00447 typedef HANDLE file_handle_type;
00448 typedef HINSTANCE module_type;
00449 typedef DWORD error_type;
00450
00451 enum
00452 {
00453 maxPathLength = 1 + WINSTL_CONST_MAX_PATH
00454 };
00455
00456 public:
00457 static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data)
00458 {
00459 return FALSE != ::GetFileInformationByHandle(fd, fstat_data);
00460 }
00461
00462 static bool_type is_file(fstat_data_type const* stat_data)
00463 {
00464 return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
00465 }
00466 static bool_type is_directory(fstat_data_type const* stat_data)
00467 {
00468 return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
00469 }
00470 static bool_type is_link(fstat_data_type const* )
00471 {
00472 return false;
00473 }
00474 static bool_type is_readonly(fstat_data_type const* stat_data)
00475 {
00476 return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
00477 }
00478
00479 #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
00480 static ws_uint64_t get_file_size(file_handle_type h)
00481 {
00482 DWORD dwHigh;
00483 DWORD dwLow = ::GetFileSize(h, &dwHigh);
00484
00485 if( 0xFFFFFFFF == dwLow &&
00486 ERROR_SUCCESS != ::GetLastError())
00487 {
00488 dwHigh = 0xFFFFFFFF;
00489 }
00490
00491 return (static_cast<ws_uint64_t>(dwHigh) << 32) | dwLow;
00492 }
00493 #endif
00494 };
00495
00496 STLSOFT_TEMPLATE_SPECIALISATION
00497 struct filesystem_traits<ws_char_a_t>
00498 : public system_traits<ws_char_a_t>
00499 {
00500 public:
00501 typedef ws_char_a_t char_type;
00502 typedef ws_size_t size_type;
00503 typedef ws_ptrdiff_t difference_type;
00504 typedef WIN32_FIND_DATAA find_data_type;
00505 typedef WIN32_FIND_DATAA stat_data_type;
00506 typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
00507 typedef filesystem_traits<char_type> class_type;
00508 typedef ws_int_t int_type;
00509 typedef ws_bool_t bool_type;
00510 typedef HANDLE file_handle_type;
00511 typedef HINSTANCE module_type;
00512 typedef DWORD error_type;
00513 private:
00514 #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
00515 _MSC_VER >= 1200
00516 typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_type_;
00517 #endif
00518 public:
00519
00520 enum
00521 {
00522 maxPathLength = 1 + WINSTL_CONST_MAX_PATH
00523 };
00524
00525 public:
00526 static char_type* ensure_dir_end(char_type* dir)
00527 {
00528 WINSTL_ASSERT(NULL != dir);
00529
00530 char_type* end = str_end(dir);
00531
00532 if( dir < end &&
00533 !is_path_name_separator(*(end - 1)))
00534 {
00535 *end = path_name_separator();
00536 *(end + 1) = '\0';
00537 }
00538
00539 return dir;
00540 }
00541
00542 static char_type* remove_dir_end(char_type* dir)
00543 {
00544 WINSTL_ASSERT(NULL != dir);
00545
00546
00547 if( isalpha(dir[0]) &&
00548 ':' == dir[1] &&
00549 is_path_name_separator(dir[2]) &&
00550 '\0' == dir[3])
00551 {
00552 return dir;
00553 }
00554
00555
00556 if( '\\' == dir[0] &&
00557 '\\' == dir[1] &&
00558 '\0' == dir[3])
00559 {
00560 return dir;
00561 }
00562
00563 char_type* end = str_end(dir);
00564
00565 if( dir < end &&
00566 is_path_name_separator(*(end - 1)))
00567 {
00568 *(end - 1) = '\0';
00569 }
00570
00571 return dir;
00572 }
00573
00574 static bool_type has_dir_end(char_type const* dir)
00575 {
00576 WINSTL_ASSERT(NULL != dir);
00577
00578 size_type len = str_len(dir);
00579
00580 return (0 < len) && is_path_name_separator(dir[len - 1]);
00581 }
00582
00583 static bool_type is_dots(char_type const* dir)
00584 {
00585 WINSTL_ASSERT(NULL != dir);
00586
00587 return dir[0] == '.' &&
00588 ( dir[1] == '\0' ||
00589 ( dir[1] == '.' &&
00590 dir[2] == '\0'));
00591 }
00592
00593 static bool_type is_path_rooted(char_type const* path)
00594 {
00595 WINSTL_ASSERT(NULL != path);
00596
00597 return is_path_name_separator(*path) || is_path_absolute(path);
00598 }
00599
00600 static bool_type is_path_absolute(char_type const* path)
00601 {
00602 WINSTL_ASSERT(NULL != path);
00603
00604 size_type len = str_len(path);
00605
00606 return is_path_UNC(path) ||
00607 ( (2 < len) &&
00608 (':' == path[1]) &&
00609 is_path_name_separator(path[2]));
00610 }
00611
00612 static bool_type is_path_UNC(char_type const* path)
00613 {
00614 WINSTL_ASSERT(NULL != path);
00615
00616 return ('\\' == path[0] && '\\' == path[1]);
00617 }
00618
00619 private:
00620 static bool_type is_root_drive_(char_type const* path)
00621 {
00622 if( isalpha(path[0]) &&
00623 ':' == path[1] &&
00624 is_path_name_separator(path[2]) &&
00625 '\0' == path[3])
00626 {
00627 return true;
00628 }
00629
00630 return false;
00631 }
00632 static bool_type is_root_UNC_(char_type const* path)
00633 {
00634 if(is_path_UNC(path))
00635 {
00636 char_type const* sep = str_pbrk(path + 2, "\\/");
00637
00638 if( NULL == sep ||
00639 '\0' == sep[1])
00640 {
00641 return true;
00642 }
00643 }
00644
00645 return false;
00646 }
00647 static bool_type is_root_directory_(char_type const* path)
00648 {
00649 if( is_path_name_separator(path[0]) &&
00650 '\0' == path[1])
00651 {
00652 return true;
00653 }
00654
00655 return false;
00656 }
00657 public:
00658 static bool_type is_root_designator(char_type const* path)
00659 {
00660 WINSTL_ASSERT(NULL != path);
00661
00662 return is_root_directory_(path) || is_root_drive_(path) || is_root_UNC_(path);
00663 }
00664
00665 static bool_type is_path_name_separator(char_type ch)
00666 {
00667 return '\\' == ch || '/' == ch;
00668 }
00669
00670 static char_type path_separator()
00671 {
00672 return ';';
00673 }
00674
00675 static char_type path_name_separator()
00676 {
00677 return '\\';
00678 }
00679
00680 static char_type const* pattern_all()
00681 {
00682 return "*.*";
00683 }
00684
00685 static size_type path_max()
00686 {
00687 return 1 + WINSTL_CONST_MAX_PATH;
00688 }
00689
00690 #if defined(STLSOFT_COMPILER_IS_MSVC) && \
00691 _MSC_VER < 1200
00692 static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
00693 {
00694 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);
00695
00696 if('"' == *fileName)
00697 {
00698
00699 const size_type len = class_type::str_len(fileName);
00700 char_type const* const closing = class_type::str_chr(fileName + 1, '"');
00701
00702
00703 if( NULL != closing &&
00704 closing - fileName == static_cast<ws_ptrdiff_t>(len - 1))
00705 {
00706 size_type res = class_type::get_full_path_name(fileName + 1, cchBuffer, buffer, ppFile);
00707
00708
00709 if( 0 != res &&
00710 res < cchBuffer)
00711 {
00712 WINSTL_ASSERT('\0' == buffer[res]);
00713
00714 char_type *const closing2 = class_type::str_chr(buffer, '"');
00715
00716
00717 if( NULL != closing2 &&
00718 closing2 - buffer == static_cast<ws_ptrdiff_t>(res - 1))
00719 {
00720 buffer[res-- - 1] = '\0';
00721
00722 return res;
00723 }
00724 }
00725 }
00726 }
00727
00728 return ::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
00729 }
00730 #else
00731 private:
00732 static size_type get_full_path_name_impl2(char_type const* fileName, size_type len, char_type* buffer, size_type cchBuffer, char_type** ppFile)
00733 {
00734 size_type r = class_type::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
00735
00736 if( 0 != r &&
00737 NULL != buffer &&
00738 r > cchBuffer)
00739 {
00740 buffer_type_ buffer_(1 + r);
00741
00742 if(0 == buffer_.size())
00743 {
00744 *ppFile = NULL;
00745
00746 return 0;
00747 }
00748 else
00749 {
00750 char_type* pFile2;
00751 size_type r2 = get_full_path_name_impl2(fileName, len, &buffer_[0], buffer_.size(), &pFile2);
00752
00753 if(0 == r2)
00754 {
00755 return 0;
00756 }
00757 else
00758 {
00759 if(r2 > cchBuffer)
00760 {
00761 r2 = cchBuffer;
00762 }
00763
00764 ::memcpy(&buffer[0], &buffer_[0], sizeof(char_type) * r2);
00765 if( NULL != pFile2 &&
00766 r2 == (r - 1) &&
00767 static_cast<size_type>(pFile2 - &buffer_[0]) < r2)
00768 {
00769 *ppFile = &buffer[0] + (pFile2 - &buffer_[0]);
00770 }
00771 else
00772 {
00773 *ppFile = NULL;
00774 }
00775
00776 return r2;
00777 }
00778 }
00779 }
00780 else
00781 {
00782 #if 0
00783 DWORD dw = ::GetLastError();
00784
00785 if( 0 == r &&
00786 0 == dw &&
00787 str_len(fileName) > WINSTL_CONST_MAX_PATH)
00788 {
00789 ::SetLastError(ERROR_FILENAME_EXCED_RANGE);
00790 }
00791 #endif
00792
00793 return r;
00794 }
00795 }
00796
00797 static size_type get_full_path_name_impl(char_type const* fileName, size_type len, char_type* buffer, size_type cchBuffer, char_type** ppFile)
00798 {
00799 WINSTL_ASSERT(len > 0);
00800
00801 if('\0' != fileName[len])
00802 {
00803 buffer_type_ fileName_(1 + (len - 1));
00804
00805
00806
00807
00808
00809
00810 if(0 == fileName_.size())
00811 {
00812 set_last_error(ERROR_OUTOFMEMORY);
00813
00814 return 0;
00815 }
00816 else
00817 {
00818 fileName_[len] = '\0';
00819
00820 return get_full_path_name_impl( static_cast<char_type*>(::memcpy(&fileName_[0], fileName, sizeof(char_type) * len))
00821 , len
00822 , buffer
00823 , cchBuffer
00824 , ppFile);
00825 }
00826 }
00827 else
00828 {
00829 return get_full_path_name_impl2(fileName, len, buffer, cchBuffer, ppFile);
00830 }
00831 }
00832
00833 public:
00834 static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
00835 {
00836 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);
00837
00838 size_type n = 0;
00839 const size_type len = class_type::str_len(fileName);
00840
00841 if(NULL != class_type::str_pbrk(fileName, "<>|*?"))
00842 {
00843 ::SetLastError(ERROR_INVALID_NAME);
00844
00845 return 0;
00846 }
00847
00848 if('"' == *fileName)
00849 {
00850
00851
00852
00853
00854 char_type const* const closing = class_type::str_chr(fileName + 1, '"');
00855
00856 if( NULL == closing ||
00857 static_cast<size_type>(closing - fileName) != len - 1)
00858 {
00859 set_last_error(ERROR_INVALID_DATA);
00860 }
00861 else
00862 {
00863 size_type r;
00864
00865 if(NULL == buffer)
00866 {
00867 r = get_full_path_name_impl(fileName, len, NULL, 0, ppFile);
00868
00869 if(0 != r)
00870 {
00871 n = 2 + r;
00872 }
00873 }
00874 else if(cchBuffer == 0)
00875 {
00876 n = 0;
00877 *ppFile = NULL;
00878 }
00879 else if(cchBuffer == 1)
00880 {
00881
00882 r = get_full_path_name_impl(fileName, len, NULL, 0, ppFile);
00883
00884 if(0 != r)
00885 {
00886 buffer[0] = '"';
00887 n = 1;
00888 *ppFile = NULL;
00889 }
00890 }
00891 else
00892 {
00893 r = get_full_path_name_impl(fileName + 1, len - 2, buffer + 1, cchBuffer - 1, ppFile);
00894
00895 if(0 != r)
00896 {
00897
00898 buffer[0] = '"';
00899
00900 if(r + 1 < cchBuffer)
00901 {
00902
00903 buffer[r + 1] = '"';
00904
00905 if(r + 2 < cchBuffer)
00906 {
00907
00908 buffer[r + 2] = '\0';
00909
00910 n = r + 2;
00911 }
00912 else
00913 {
00914 n = r + 2;
00915 }
00916 }
00917 else
00918 {
00919 n = r + 1;
00920 }
00921 }
00922 }
00923 }
00924 }
00925 else
00926 {
00927 n = get_full_path_name_impl(fileName, len, buffer, cchBuffer, ppFile);
00928 }
00929
00930
00931
00932 if( 0 == n &&
00933 0 == ::GetLastError() &&
00934 str_len(fileName) > WINSTL_CONST_MAX_PATH)
00935 {
00936 ::SetLastError(ERROR_FILENAME_EXCED_RANGE);
00937 }
00938
00939 return n;
00940 }
00941 #endif
00942
00943 static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
00944 {
00945 WINSTL_ASSERT(NULL != fileName);
00946
00947 char_type* pFile;
00948
00949 if('\0' == *fileName)
00950 {
00951 static const char s_dot[2] = { '.', '\0' };
00952
00953 fileName = s_dot;
00954 }
00955
00956 return get_full_path_name(fileName, cchBuffer, buffer, &pFile);
00957 }
00958
00959 static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
00960 {
00961 return get_full_path_name(fileName, buffer, cchBuffer);
00962 }
00963
00964 static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
00965 {
00966 return class_type::GetShortPathNameA(fileName, buffer, cchBuffer);
00967 }
00968 static size_type get_short_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
00969 {
00970 return class_type::GetShortPathNameA(fileName, buffer, cchBuffer);
00971 }
00972
00973
00974
00975 static HANDLE find_first_file(char_type const* spec, find_data_type* findData)
00976 {
00977 return ::FindFirstFileA(spec, findData);
00978 }
00979
00980 #if defined(_WIN32_WINNT) && \
00981 _WIN32_WINNT >= 0x0400
00982 static HANDLE find_first_file_ex(char_type const* spec, FINDEX_SEARCH_OPS flags, find_data_type* findData)
00983 {
00984 return ::FindFirstFileExA(spec, FindExInfoStandard, findData, flags, NULL, 0);
00985 }
00986 #endif
00987
00988 static bool_type find_next_file(HANDLE h, find_data_type* findData)
00989 {
00990 return ::FindNextFileA(h, findData) != FALSE;
00991 }
00992
00993 static void find_file_close(HANDLE h)
00994 {
00995 WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
00996
00997 ::FindClose(h);
00998 }
00999
01000 #ifndef _WINSTL_NO_FINDVOLUME_API
01001 static HANDLE find_first_volume(char_type* volume_name, size_type cch_volume_name)
01002 {
01003 return class_type::FindFirstVolumeA(volume_name, cch_volume_name);
01004 }
01005
01006 static bool_type find_next_volume(HANDLE h, char_type* volume_name, size_type cch_volume_name)
01007 {
01008 return class_type::FindNextVolumeA(h, volume_name, cch_volume_name) != FALSE;
01009 }
01010
01011 static void find_volume_close(HANDLE h)
01012 {
01013 WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
01014
01015 ::FindVolumeClose(h);
01016 }
01017 #endif // !_WINSTL_NO_FINDVOLUME_API
01018
01019
01020 static bool_type set_current_directory(char_type const* dir)
01021 {
01022 return ::SetCurrentDirectoryA(dir) != FALSE;
01023 }
01024
01025 static size_type get_current_directory(char_type* buffer, size_type cchBuffer)
01026 {
01027 return class_type::GetCurrentDirectoryA(cchBuffer, buffer);
01028 }
01029
01030 static size_type get_current_directory(size_type cchBuffer, char_type* buffer)
01031 {
01032 return class_type::get_current_directory(buffer, cchBuffer);
01033 }
01034
01035 static bool_type file_exists(char_type const* fileName)
01036 {
01037 return 0xFFFFFFFF != ::GetFileAttributesA(fileName);
01038 }
01039
01040 static bool_type is_file(char_type const* path)
01041 {
01042 DWORD attr = ::GetFileAttributesA(path);
01043
01044 return 0xFFFFFFFF != attr && 0 == (attr & FILE_ATTRIBUTE_DIRECTORY);
01045 }
01046
01047 static bool_type is_directory(char_type const* path)
01048 {
01049 DWORD attr = ::GetFileAttributesA(path);
01050
01051 return 0xFFFFFFFF != attr && 0 != (attr & FILE_ATTRIBUTE_DIRECTORY);
01052 }
01053
01054 private:
01055 static bool_type stat_direct_(char_type const* path, stat_data_type* stat_data)
01056 {
01057 WINSTL_ASSERT(NULL != path);
01058 WINSTL_ASSERT(NULL != stat_data);
01059
01060 if(is_root_drive_(path))
01061 {
01062 stat_data->dwFileAttributes = ::GetFileAttributesA(path);
01063 stat_data->ftCreationTime.dwLowDateTime = 0;
01064 stat_data->ftCreationTime.dwHighDateTime = 0;
01065 stat_data->ftLastAccessTime.dwLowDateTime = 0;
01066 stat_data->ftLastAccessTime.dwHighDateTime = 0;
01067 stat_data->ftLastWriteTime.dwLowDateTime = 0;
01068 stat_data->ftLastWriteTime.dwHighDateTime = 0;
01069 stat_data->nFileSizeHigh = 0;
01070 stat_data->nFileSizeLow = 0;
01071 { for(ws_size_t i = 0; i < 4; ++i)
01072 {
01073 stat_data->cFileName[i] = path[i];
01074 stat_data->cAlternateFileName[i] = path[i];
01075 }}
01076
01077 return 0xFFFFFFFF != stat_data->dwFileAttributes;
01078 }
01079
01080 HANDLE h = find_first_file(path, stat_data);
01081
01082 return (INVALID_HANDLE_VALUE == h) ? false : (find_file_close(h), true);
01083 }
01084 public:
01085 static bool_type stat(char_type const* path, stat_data_type* stat_data)
01086 {
01087 WINSTL_ASSERT(NULL != path);
01088 WINSTL_ASSERT(NULL != stat_data);
01089
01090 #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
01091 _MSC_VER >= 1200
01092 size_type len = class_type::str_len(path);
01093 bool_type bTryEndTest = false;
01094
01095 if(is_path_absolute(path))
01096 {
01097 if(len > 4)
01098 {
01099 bTryEndTest = true;
01100 }
01101 }
01102 else if(is_path_rooted(path))
01103 {
01104 if(len > 3)
01105 {
01106 bTryEndTest = true;
01107 }
01108 }
01109 else if(len > 2)
01110 {
01111 bTryEndTest = true;
01112 }
01113
01114 if( bTryEndTest &&
01115 class_type::has_dir_end(path + len - 2))
01116 {
01117 typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_t;
01118
01119 WINSTL_ASSERT(len > 2);
01120
01121 buffer_t buffer(1 + len);
01122
01123 if(0 == buffer.size())
01124 {
01125 return false;
01126 }
01127 else
01128 {
01129 WINSTL_ASSERT(len > 0);
01130
01131 ::memcpy(&buffer[0], path, sizeof(char_type) * (len - 1));
01132
01133 buffer[len - 1] = '\0';
01134
01135 return class_type::stat_direct_(buffer.data(), stat_data);
01136 }
01137 }
01138 else
01139 #endif
01140 {
01141 return stat_direct_(path, stat_data);
01142 }
01143 }
01144
01145 static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data)
01146 {
01147 return filesystem_traits_::fstat(fd, fstat_data);
01148 }
01149
01150 static bool_type is_file(stat_data_type const* stat_data)
01151 {
01152 return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
01153 }
01154 static bool_type is_directory(stat_data_type const* stat_data)
01155 {
01156 return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
01157 }
01158 static bool_type is_link(stat_data_type const* )
01159 {
01160 return false;
01161 }
01162 static bool_type is_readonly(stat_data_type const* stat_data)
01163 {
01164 return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
01165 }
01166
01167 static bool_type is_file(fstat_data_type const* stat_data)
01168 {
01169 return filesystem_traits_::is_file(stat_data);
01170 }
01171 static bool_type is_directory(fstat_data_type const* stat_data)
01172 {
01173 return filesystem_traits_::is_directory(stat_data);
01174 }
01175 static bool_type is_link(fstat_data_type const* stat_data)
01176 {
01177 return filesystem_traits_::is_link(stat_data);
01178 }
01179 static bool_type is_readonly(fstat_data_type const* stat_data)
01180 {
01181 return filesystem_traits_::is_readonly(stat_data);
01182 }
01183
01184 static bool_type drive_exists(char_type driveLetter)
01185 {
01186 WINSTL_ASSERT(::IsCharAlphaA(driveLetter));
01187
01188 const DWORD drivesBitmap = ::GetLogicalDrives();
01189 const int driveOrdinal = (driveLetter - (::IsCharUpperA(driveLetter) ? 'A' : 'a'));
01190
01191 return 0 != ((0x01 << driveOrdinal) & drivesBitmap);
01192 }
01193
01194 static DWORD get_drive_type(char_type driveLetter)
01195 {
01196 WINSTL_ASSERT(::IsCharAlphaA(driveLetter));
01197
01198 char_type drive[] = { '?', ':', '\\', '\0' };
01199
01200 return (drive[0] = driveLetter, ::GetDriveTypeA(drive));
01201 }
01202
01203 static bool_type create_directory(char_type const* dir)
01204 {
01205 return FALSE != ::CreateDirectoryA(dir, NULL);
01206 }
01207
01208 static bool_type create_directory(char_type const* dir, LPSECURITY_ATTRIBUTES lpsa)
01209 {
01210 return FALSE != ::CreateDirectoryA(dir, lpsa);
01211 }
01212
01213 static bool_type remove_directory(char_type const* dir)
01214 {
01215 return FALSE != ::RemoveDirectoryA(dir);
01216 }
01217
01218 static bool_type unlink_file(char_type const* file)
01219 {
01220 return FALSE != ::DeleteFileA(file);
01221 }
01222
01223 static bool_type delete_file(char_type const* file)
01224 {
01225 return unlink_file(file);
01226 }
01227
01228 static bool_type rename_file(char_type const* currentName, char_type const* newName)
01229 {
01230 return FALSE != ::MoveFileA(currentName, newName);
01231 }
01232
01233 static bool_type copy_file(char_type const* sourceName, char_type const* newName, bool_type bFailIfExists = false)
01234 {
01235 return FALSE != ::CopyFileA(sourceName, newName, bFailIfExists);
01236 }
01237
01238 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)
01239 {
01240 return ::CreateFileA(fileName, desiredAccess, shareMode, sa, creationDisposition, flagAndAttributes, hTemplateFile);
01241 }
01242
01243 static bool_type close_file(file_handle_type h)
01244 {
01245 return filesystem_traits_::close_handle(h);
01246 }
01247
01248 #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
01249 static ws_uint64_t get_file_size(file_handle_type h)
01250 {
01251 return filesystem_traits_::get_file_size(h);
01252 }
01253 #endif
01254 private:
01255 static void get_file_size(stat_data_type const*);
01256 static void get_file_size(stat_data_type const&);
01257
01258 private:
01259 static size_type GetFullPathNameA(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
01260 {
01261 WINSTL_ASSERT(NULL != fileName);
01262
01263 size_type result;
01264
01265 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01266 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01267 result = ::GetFullPathNameA(fileName, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer, ppFile);
01268 # else
01269 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
01270
01271 result = ::GetFullPathNameA(fileName, static_cast<DWORD>(cchBuffer), buffer, ppFile);
01272 # endif
01273 #else
01274 result = ::GetFullPathNameA(fileName, cchBuffer, buffer, ppFile);
01275 #endif
01276
01277 if(0 == result)
01278 {
01279 size_type requiredLen = 0;
01280
01281 requiredLen += str_len(fileName);
01282
01283 if(!is_path_rooted(fileName))
01284 {
01285 size_type cwdLen = ::GetCurrentDirectoryA(0, NULL);
01286
01287 requiredLen += cwdLen;
01288 }
01289
01290 if(requiredLen >= maxPathLength)
01291 {
01292 ::SetLastError(ERROR_FILENAME_EXCED_RANGE);
01293 }
01294 }
01295
01296 return result;
01297 }
01298
01299 static size_type GetShortPathNameA(char_type const* fileName, char_type* buffer, size_type cchBuffer)
01300 {
01301 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01302 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01303 return ::GetShortPathNameA(fileName, buffer, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer));
01304 # else
01305 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
01306
01307 return ::GetShortPathNameA(fileName, buffer, static_cast<DWORD>(cchBuffer));
01308 # endif
01309 #else
01310 return ::GetShortPathNameA(fileName, buffer, cchBuffer);
01311 #endif
01312 }
01313
01314 static HANDLE FindFirstVolumeA(char_type* volume_name, size_type cch_volume_name)
01315 {
01316 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01317 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01318 return ::FindFirstVolumeA(volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
01319 # else
01320 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
01321
01322 return ::FindFirstVolumeA(volume_name, static_cast<DWORD>(cch_volume_name));
01323 # endif
01324 #else
01325 return ::FindFirstVolumeA(volume_name, cch_volume_name);
01326 #endif
01327 }
01328 static bool_type FindNextVolumeA(HANDLE h, char_type* volume_name, size_type cch_volume_name)
01329 {
01330 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01331 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01332 return FALSE != ::FindNextVolumeA(h, volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
01333 # else
01334 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
01335
01336 return FALSE != ::FindNextVolumeA(h, volume_name, static_cast<DWORD>(cch_volume_name));
01337 # endif
01338 #else
01339 return FALSE != ::FindNextVolumeA(h, volume_name, cch_volume_name);
01340 #endif
01341 }
01342
01343 static size_type GetCurrentDirectoryA(size_type cchBuffer, char_type* buffer)
01344 {
01345 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01346 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01347 return ::GetCurrentDirectoryA(stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer);
01348 # else
01349 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
01350
01351 return ::GetCurrentDirectoryA(static_cast<DWORD>(cchBuffer), buffer);
01352 # endif
01353 #else
01354 return ::GetCurrentDirectoryA(cchBuffer, buffer);
01355 #endif
01356 }
01357 };
01358
01359 STLSOFT_TEMPLATE_SPECIALISATION
01360 struct filesystem_traits<ws_char_w_t>
01361 : public system_traits<ws_char_w_t>
01362 {
01363 public:
01364 typedef ws_char_w_t char_type;
01365 typedef ws_size_t size_type;
01366 typedef ws_ptrdiff_t difference_type;
01367 typedef WIN32_FIND_DATAW find_data_type;
01368 typedef WIN32_FIND_DATAW stat_data_type;
01369 typedef BY_HANDLE_FILE_INFORMATION fstat_data_type;
01370 typedef filesystem_traits<char_type> class_type;
01371 typedef ws_int_t int_type;
01372 typedef ws_bool_t bool_type;
01373 typedef HANDLE file_handle_type;
01374 typedef HINSTANCE module_type;
01375 typedef DWORD error_type;
01376 private:
01377 #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
01378 _MSC_VER >= 1200
01379 typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_type_;
01380 #endif
01381 public:
01382
01383 enum
01384 {
01385 maxPathLength = 1 + CONST_NT_MAX_PATH
01386 };
01387
01388 public:
01389
01390 static char_type* ensure_dir_end(char_type* dir)
01391 {
01392 WINSTL_ASSERT(NULL != dir);
01393
01394 char_type* end = str_end(dir);
01395
01396 if( dir < end &&
01397 !is_path_name_separator(*(end - 1)))
01398 {
01399 *end = path_name_separator();
01400 *(end + 1) = L'\0';
01401 }
01402
01403 return dir;
01404 }
01405
01406 static char_type* remove_dir_end(char_type* dir)
01407 {
01408 WINSTL_ASSERT(NULL != dir);
01409
01410
01411 if( isalpha(dir[0]) &&
01412 L':' == dir[1] &&
01413 is_path_name_separator(dir[2]) &&
01414 L'\0' == dir[3])
01415 {
01416 return dir;
01417 }
01418
01419
01420 if( L'\\' == dir[0] &&
01421 L'\\' == dir[1] &&
01422 L'\0' == dir[3])
01423 {
01424 return dir;
01425 }
01426
01427 char_type* end = str_end(dir);
01428
01429 if( dir < end &&
01430 is_path_name_separator(*(end - 1)))
01431 {
01432 *(end - 1) = L'\0';
01433 }
01434
01435 return dir;
01436 }
01437
01438 static bool_type has_dir_end(char_type const* dir)
01439 {
01440 WINSTL_ASSERT(NULL != dir);
01441
01442 size_type len = str_len(dir);
01443
01444 return (0 < len) && is_path_name_separator(dir[len - 1]);
01445 }
01446
01447 static bool_type is_dots(char_type const* dir)
01448 {
01449 WINSTL_ASSERT(NULL != dir);
01450
01451 return dir[0] == '.' &&
01452 ( dir[1] == L'\0' ||
01453 ( dir[1] == L'.' &&
01454 dir[2] == L'\0'));
01455 }
01456
01457 static bool_type is_path_rooted(char_type const* path)
01458 {
01459 WINSTL_ASSERT(NULL != path);
01460
01461 return is_path_name_separator(*path) || is_path_absolute(path);
01462 }
01463
01464 static bool_type is_path_absolute(char_type const* path)
01465 {
01466 WINSTL_ASSERT(NULL != path);
01467
01468 size_type len = str_len(path);
01469
01470 return is_path_UNC(path) ||
01471 ( (2 < len) &&
01472 (L':' == path[1]) &&
01473 is_path_name_separator(path[2]));
01474 }
01475
01476 static bool_type is_path_UNC(char_type const* path)
01477 {
01478 WINSTL_ASSERT(NULL != path);
01479
01480 return (L'\\' == path[0] && L'\\' == path[1]);
01481 }
01482
01483 private:
01484 static bool_type is_root_drive_(char_type const* path)
01485 {
01486 if( isalpha(path[0]) &&
01487 L':' == path[1] &&
01488 is_path_name_separator(path[2]) &&
01489 L'\0' == path[3])
01490 {
01491 return true;
01492 }
01493
01494 return false;
01495 }
01496 static bool_type is_root_UNC_(char_type const* path)
01497 {
01498 if(is_path_UNC(path))
01499 {
01500 char_type const* sep = str_pbrk(path + 2, L"\\/");
01501
01502 if( NULL == sep ||
01503 L'\0' == sep[1])
01504 {
01505 return true;
01506 }
01507 }
01508
01509 return false;
01510 }
01511 static bool_type is_root_directory_(char_type const* path)
01512 {
01513 if( is_path_name_separator(path[0]) &&
01514 L'\0' == path[1])
01515 {
01516 return true;
01517 }
01518
01519 return false;
01520 }
01521 public:
01522 static bool_type is_root_designator(char_type const* path)
01523 {
01524 WINSTL_ASSERT(NULL != path);
01525
01526 return is_root_directory_(path) || is_root_drive_(path) || is_root_UNC_(path);
01527 }
01528
01529 static bool_type is_path_name_separator(char_type ch)
01530 {
01531 return L'\\' == ch || L'/' == ch;
01532 }
01533
01534 static char_type path_separator()
01535 {
01536 return L';';
01537 }
01538
01539 static char_type path_name_separator()
01540 {
01541 return L'\\';
01542 }
01543
01544 static char_type const* pattern_all()
01545 {
01546 return L"*.*";
01547 }
01548
01549 static size_type path_max()
01550 {
01551 return (::GetVersion() & 0x80000000) ? (1 + WINSTL_CONST_MAX_PATH) : (1 + CONST_NT_MAX_PATH);
01552 }
01553
01554 static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
01555 {
01556 WINSTL_MESSAGE_ASSERT("GetFullPathNameW() will crash when the file-name and buffer parameters are the same", fileName != buffer);
01557
01558 return class_type::GetFullPathNameW(fileName, cchBuffer, buffer, ppFile);
01559 }
01560
01561 static size_type get_full_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
01562 {
01563 char_type *pFile;
01564
01565 return get_full_path_name(fileName, cchBuffer, buffer, &pFile);
01566 }
01567
01568 static size_type get_full_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
01569 {
01570 return get_full_path_name(fileName, buffer, cchBuffer);
01571 }
01572
01573 static size_type get_short_path_name(char_type const* fileName, size_type cchBuffer, char_type* buffer)
01574 {
01575 return class_type::GetShortPathNameW(fileName, buffer, cchBuffer);
01576 }
01577 static size_type get_short_path_name(char_type const* fileName, char_type* buffer, size_type cchBuffer)
01578 {
01579 return class_type::GetShortPathNameW(fileName, buffer, cchBuffer);
01580 }
01581
01582
01583 static HANDLE find_first_file(char_type const* spec, find_data_type* findData)
01584 {
01585 return ::FindFirstFileW(spec, findData);
01586 }
01587
01588 #if defined(_WIN32_WINNT) && \
01589 _WIN32_WINNT >= 0x0400
01590 static HANDLE find_first_file_ex(char_type const* spec, FINDEX_SEARCH_OPS flags, find_data_type* findData)
01591 {
01592 return ::FindFirstFileExW(spec, FindExInfoStandard, findData, flags, NULL, 0);
01593 }
01594 #endif
01595
01596 static bool_type find_next_file(HANDLE h, find_data_type* findData)
01597 {
01598 return ::FindNextFileW(h, findData) != FALSE;
01599 }
01600
01601 static void find_file_close(HANDLE h)
01602 {
01603 WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
01604
01605 ::FindClose(h);
01606 }
01607
01608
01609 #ifndef _WINSTL_NO_FINDVOLUME_API
01610 static HANDLE find_first_volume(char_type* volume_name, size_type cch_volume_name)
01611 {
01612 return class_type::FindFirstVolumeW(volume_name, cch_volume_name);
01613 }
01614
01615 static bool_type find_next_volume(HANDLE h, char_type* volume_name, size_type cch_volume_name)
01616 {
01617 return class_type::FindNextVolumeW(h, volume_name, cch_volume_name) != FALSE;
01618 }
01619
01620 static void find_volume_close(HANDLE h)
01621 {
01622 WINSTL_ASSERT(INVALID_HANDLE_VALUE != h);
01623
01624 ::FindVolumeClose(h);
01625 }
01626 #endif // !_WINSTL_NO_FINDVOLUME_API
01627
01628
01629 static bool_type set_current_directory(char_type const* dir)
01630 {
01631 return ::SetCurrentDirectoryW(dir) != FALSE;
01632 }
01633
01634 static size_type get_current_directory(char_type* buffer, size_type cchBuffer)
01635 {
01636 return class_type::GetCurrentDirectoryW(cchBuffer, buffer);
01637 }
01638
01639 static size_type get_current_directory(size_type cchBuffer, char_type* buffer)
01640 {
01641 return class_type::get_current_directory(buffer, cchBuffer);
01642 }
01643
01644 static bool_type file_exists(char_type const* fileName)
01645 {
01646 return 0xFFFFFFFF != ::GetFileAttributesW(fileName);
01647 }
01648
01649 static bool_type is_file(char_type const* path)
01650 {
01651 DWORD attr = ::GetFileAttributesW(path);
01652
01653 return 0xFFFFFFFF != attr && 0 == (attr & FILE_ATTRIBUTE_DIRECTORY);
01654 }
01655
01656 static bool_type is_directory(char_type const* path)
01657 {
01658 DWORD attr = ::GetFileAttributesW(path);
01659
01660 return 0xFFFFFFFF != attr && 0 != (attr & FILE_ATTRIBUTE_DIRECTORY);
01661 }
01662
01663 private:
01664 static bool_type stat_direct_(char_type const* path, stat_data_type* stat_data)
01665 {
01666 WINSTL_ASSERT(NULL != path);
01667 WINSTL_ASSERT(NULL != stat_data);
01668
01669 if(is_root_drive_(path))
01670 {
01671 stat_data->dwFileAttributes = ::GetFileAttributesW(path);
01672 stat_data->ftCreationTime.dwLowDateTime = 0;
01673 stat_data->ftCreationTime.dwHighDateTime = 0;
01674 stat_data->ftLastAccessTime.dwLowDateTime = 0;
01675 stat_data->ftLastAccessTime.dwHighDateTime = 0;
01676 stat_data->ftLastWriteTime.dwLowDateTime = 0;
01677 stat_data->ftLastWriteTime.dwHighDateTime = 0;
01678 stat_data->nFileSizeHigh = 0;
01679 stat_data->nFileSizeLow = 0;
01680 { for(ws_size_t i = 0; i < 4; ++i)
01681 {
01682 stat_data->cFileName[i] = path[i];
01683 stat_data->cAlternateFileName[i] = path[i];
01684 }}
01685
01686 return 0xFFFFFFFF != stat_data->dwFileAttributes;
01687 }
01688
01689 HANDLE h = find_first_file(path, stat_data);
01690
01691 return (INVALID_HANDLE_VALUE == h) ? false : (find_file_close(h), true);
01692 }
01693 public:
01694 static bool_type stat(char_type const* path, stat_data_type* stat_data)
01695 {
01696 WINSTL_ASSERT(NULL != path);
01697 WINSTL_ASSERT(NULL != stat_data);
01698
01699 #if !defined(STLSOFT_COMPILER_IS_MSVC) || \
01700 _MSC_VER >= 1200
01701 size_type len = class_type::str_len(path);
01702 bool_type bTryEndTest = false;
01703
01704 if(is_path_absolute(path))
01705 {
01706 if(len > 4)
01707 {
01708 bTryEndTest = true;
01709 }
01710 }
01711 else if(is_path_rooted(path))
01712 {
01713 if(len > 3)
01714 {
01715 bTryEndTest = true;
01716 }
01717 }
01718 else if(len > 2)
01719 {
01720 bTryEndTest = true;
01721 }
01722
01723 if( bTryEndTest &&
01724 class_type::has_dir_end(path + len - 2))
01725 {
01726 typedef stlsoft_ns_qual(auto_buffer)<char_type> buffer_t;
01727
01728 WINSTL_ASSERT(len > 2);
01729
01730 buffer_t buffer(1 + len);
01731
01732 if(0 == buffer.size())
01733 {
01734 return false;
01735 }
01736 else
01737 {
01738 WINSTL_ASSERT(len > 0);
01739
01740 ::memcpy(&buffer[0], path, sizeof(char_type) * (len - 1));
01741
01742 buffer[len - 1] = L'\0';
01743
01744 return class_type::stat_direct_(buffer.data(), stat_data);
01745 }
01746 }
01747 else
01748 #endif
01749 {
01750 return stat_direct_(path, stat_data);
01751 }
01752 }
01753
01754 static bool_type fstat(file_handle_type fd, fstat_data_type* fstat_data)
01755 {
01756 return filesystem_traits_::fstat(fd, fstat_data);
01757 }
01758
01759 static bool_type is_file(stat_data_type const* stat_data)
01760 {
01761 return FILE_ATTRIBUTE_DIRECTORY != (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
01762 }
01763 static bool_type is_directory(stat_data_type const* stat_data)
01764 {
01765 return FILE_ATTRIBUTE_DIRECTORY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
01766 }
01767 static bool_type is_link(stat_data_type const* )
01768 {
01769 return false;
01770 }
01771 static bool_type is_readonly(stat_data_type const* stat_data)
01772 {
01773 return FILE_ATTRIBUTE_READONLY == (stat_data->dwFileAttributes & FILE_ATTRIBUTE_READONLY);
01774 }
01775
01776 static bool_type is_file(fstat_data_type const* stat_data)
01777 {
01778 return filesystem_traits_::is_file(stat_data);
01779 }
01780 static bool_type is_directory(fstat_data_type const* stat_data)
01781 {
01782 return filesystem_traits_::is_directory(stat_data);
01783 }
01784 static bool_type is_link(fstat_data_type const* stat_data)
01785 {
01786 return filesystem_traits_::is_link(stat_data);
01787 }
01788 static bool_type is_readonly(fstat_data_type const* stat_data)
01789 {
01790 return filesystem_traits_::is_readonly(stat_data);
01791 }
01792
01793 static bool_type drive_exists(char_type driveLetter)
01794 {
01795 WINSTL_ASSERT(IsCharAlphaW(driveLetter));
01796
01797 const DWORD drivesBitmap = ::GetLogicalDrives();
01798 const int driveOrdinal = (driveLetter - (IsCharUpperW(driveLetter) ? L'A' : L'a'));
01799
01800 return 0 != ((0x01 << driveOrdinal) & drivesBitmap);
01801 }
01802
01803 static DWORD get_drive_type(char_type driveLetter)
01804 {
01805 WINSTL_ASSERT(IsCharAlphaW(driveLetter));
01806
01807 char_type drive[] = { L'?', L':', L'\\', L'\0' };
01808
01809 return (drive[0] = driveLetter, ::GetDriveTypeW(drive));
01810 }
01811
01812
01813
01814 static bool_type create_directory(char_type const* dir)
01815 {
01816 return FALSE != ::CreateDirectoryW(dir, NULL);
01817 }
01818
01819 static bool_type create_directory(char_type const* dir, LPSECURITY_ATTRIBUTES lpsa)
01820 {
01821 return FALSE != ::CreateDirectoryW(dir, lpsa);
01822 }
01823
01824 static bool_type remove_directory(char_type const* dir)
01825 {
01826 return FALSE != ::RemoveDirectoryW(dir);
01827 }
01828
01829 static bool_type unlink_file(char_type const* file)
01830 {
01831 return FALSE != ::DeleteFileW(file);
01832 }
01833
01834 static bool_type delete_file(char_type const* file)
01835 {
01836 return unlink_file(file);
01837 }
01838
01839 static bool_type rename_file(char_type const* currentName, char_type const* newName)
01840 {
01841 return FALSE != ::MoveFileW(currentName, newName);
01842 }
01843
01844 static bool_type copy_file(char_type const* sourceName, char_type const* newName, bool_type bFailIfExists = false)
01845 {
01846 return FALSE != ::CopyFileW(sourceName, newName, bFailIfExists);
01847 }
01848
01849 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)
01850 {
01851 return ::CreateFileW(fileName, desiredAccess, shareMode, sa, creationDisposition, flagAndAttributes, hTemplateFile);
01852 }
01853
01854 static bool_type close_file(file_handle_type h)
01855 {
01856 return filesystem_traits_::close_handle(h);
01857 }
01858
01859 #ifdef STLSOFT_CF_64BIT_INT_SUPPORT
01860 static ws_uint64_t get_file_size(file_handle_type h)
01861 {
01862 return filesystem_traits_::get_file_size(h);
01863 }
01864 #endif
01865 private:
01866 static void get_file_size(stat_data_type const*);
01867 static void get_file_size(stat_data_type const&);
01868
01869 private:
01870 static size_type GetFullPathNameW(char_type const* fileName, size_type cchBuffer, char_type* buffer, char_type** ppFile)
01871 {
01872 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01873 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01874 return ::GetFullPathNameW(fileName, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer, ppFile);
01875 # else
01876 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
01877
01878 return ::GetFullPathNameW(fileName, static_cast<DWORD>(cchBuffer), buffer, ppFile);
01879 # endif
01880 #else
01881 return ::GetFullPathNameW(fileName, cchBuffer, buffer, ppFile);
01882 #endif
01883 }
01884
01885 static size_type GetShortPathNameW(char_type const* fileName, char_type* buffer, size_type cchBuffer)
01886 {
01887 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01888 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01889 return ::GetShortPathNameW(fileName, buffer, stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer));
01890 # else
01891 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
01892
01893 return ::GetShortPathNameW(fileName, buffer, static_cast<DWORD>(cchBuffer));
01894 # endif
01895 #else
01896 return ::GetShortPathNameW(fileName, buffer, cchBuffer);
01897 #endif
01898 }
01899
01900 static HANDLE FindFirstVolumeW(char_type* volume_name, size_type cch_volume_name)
01901 {
01902 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01903 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01904 return ::FindFirstVolumeW(volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
01905 # else
01906 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
01907
01908 return ::FindFirstVolumeW(volume_name, static_cast<DWORD>(cch_volume_name));
01909 # endif
01910 #else
01911 return ::FindFirstVolumeW(volume_name, cch_volume_name);
01912 #endif
01913 }
01914 static bool_type FindNextVolumeW(HANDLE h, char_type* volume_name, size_type cch_volume_name)
01915 {
01916 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01917 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01918 return FALSE != ::FindNextVolumeW(h, volume_name, stlsoft_ns_qual(truncation_cast)<DWORD>(cch_volume_name));
01919 # else
01920 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cch_volume_name));
01921
01922 return FALSE != ::FindNextVolumeW(h, volume_name, static_cast<DWORD>(cch_volume_name));
01923 # endif
01924 #else
01925 return FALSE != ::FindNextVolumeW(h, volume_name, cch_volume_name);
01926 #endif
01927 }
01928
01929 static size_type GetCurrentDirectoryW(size_type cchBuffer, char_type* buffer)
01930 {
01931 #ifdef _WINSTL_FILESYSTEM_TRAITS_USE_TRUNCATION_TESTING
01932 # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
01933 return ::GetCurrentDirectoryW(stlsoft_ns_qual(truncation_cast)<DWORD>(cchBuffer), buffer);
01934 # else
01935 WINSTL_MESSAGE_ASSERT("buffer size out of range", stlsoft_ns_qual(truncation_test)<DWORD>(cchBuffer));
01936
01937 return ::GetCurrentDirectoryW(static_cast<DWORD>(cchBuffer), buffer);
01938 # endif
01939 #else
01940 return ::GetCurrentDirectoryW(cchBuffer, buffer);
01941 #endif
01942 }
01943 };
01944
01945 #endif
01946
01947
01948
01949
01950
01951 #ifdef STLSOFT_UNITTEST
01952 # include "./unittest/filesystem_traits_unittest_.h"
01953 #endif
01954
01955
01956
01957 #ifndef _WINSTL_NO_NAMESPACE
01958 # if defined(_STLSOFT_NO_NAMESPACE) || \
01959 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
01960 }
01961 # else
01962 }
01963 }
01964 # endif
01965 #endif
01966
01967
01968
01969 #endif
01970
01971