Ticket #1681: ntfs_symlink.patch
File ntfs_symlink.patch, 19.2 KB (added by , 15 years ago) |
---|
-
boost/filesystem/operations.hpp
143 143 144 144 BOOST_FILESYSTEM_DECL file_status 145 145 status_api( const std::string & ph, system::error_code & ec ); 146 # ifndef BOOST_WINDOWS_API147 146 BOOST_FILESYSTEM_DECL file_status 148 147 symlink_status_api( const std::string & ph, system::error_code & ec ); 149 # endif150 148 BOOST_FILESYSTEM_DECL query_pair 151 149 is_empty_api( const std::string & ph ); 152 150 BOOST_FILESYSTEM_DECL query_pair … … 187 185 188 186 BOOST_FILESYSTEM_DECL boost::filesystem::file_status 189 187 status_api( const std::wstring & ph, system::error_code & ec ); 188 BOOST_FILESYSTEM_DECL file_status 189 symlink_status_api( const std::wstring & ph, system::error_code & ec ); 190 190 BOOST_FILESYSTEM_DECL query_pair 191 191 is_empty_api( const std::wstring & ph ); 192 192 BOOST_FILESYSTEM_DECL query_pair … … 255 255 256 256 BOOST_INLINE_FS_FUNC(file_status) 257 257 symlink_status( const Path & ph, system::error_code & ec ) 258 # ifdef BOOST_WINDOWS_API259 { return detail::status_api( ph.external_file_string(), ec ); }260 # else261 258 { return detail::symlink_status_api( ph.external_file_string(), ec ); } 262 # endif263 259 264 260 BOOST_FS_FUNC(file_status) 265 261 symlink_status( const Path & ph ) … … 318 314 } 319 315 320 316 BOOST_FS_FUNC(bool) is_symlink( 321 # ifdef BOOST_WINDOWS_API322 const Path & )323 {324 return false;325 # else326 317 const Path & ph) 327 318 { 328 319 system::error_code ec; … … 331 322 boost::throw_exception( basic_filesystem_error<Path>( 332 323 "boost::filesystem::is_symlink", ph, ec ) ); 333 324 return is_symlink( result ); 334 # endif335 325 } 336 326 337 327 // VC++ 7.0 and earlier has a serious namespace bug that causes a clash -
libs/filesystem/test/operations_test.cpp
670 670 BOOST_CHECK( fs::create_symlink( "doesnotexist", "", ec ) ); 671 671 BOOST_CHECK( ec ); 672 672 673 // directory symbolic link tests 674 from_ph = dir / "d4"; 675 BOOST_CHECK( !fs::exists( from_ph ) ); 676 fs::path to_ph( dir / "d5" ); 677 BOOST_CHECK( fs::create_directory( to_ph ) ); 678 BOOST_CHECK( fs::exists( to_ph ) ); 679 bool create_dir_symlink_ok(true); 680 try { fs::create_symlink( to_ph, from_ph ); } 681 catch ( const fs::filesystem_error & ex ) 682 { 683 create_dir_symlink_ok = false; 684 std::cout 685 << "create_symlink() attempt failed\n" 686 << "filesystem_error.what() reports: " << ex.what() << '\n' 687 << "create_symlink() for directories may not be supported on this file system\n"; 688 } 689 690 if ( create_dir_symlink_ok ) 691 { 692 std::cout << "create_symlink() succeeded for the directory\n"; 693 BOOST_CHECK( fs::exists( from_ph ) ); 694 BOOST_CHECK( fs::is_symlink( from_ph ) ); 695 BOOST_CHECK( fs::exists( to_ph ) ); 696 BOOST_CHECK( fs::equivalent( from_ph, to_ph ) ); 697 stat = fs::symlink_status( from_ph ); 698 BOOST_CHECK( fs::exists( stat ) ); 699 BOOST_CHECK( !fs::is_directory( stat ) ); 700 BOOST_CHECK( !fs::is_regular( stat ) ); 701 BOOST_CHECK( !fs::is_other( stat ) ); 702 BOOST_CHECK( fs::is_symlink( stat ) ); 703 704 // remove_all() test on symbolic link to a directory 705 fs::path child_ph( to_ph / "child"); 706 create_file( child_ph, "foobar1" ); 707 BOOST_CHECK( fs::exists( child_ph ) ); 708 BOOST_CHECK( fs::exists( from_ph / "child" ) ); 709 BOOST_CHECK( fs::remove_all( from_ph ) ); 710 BOOST_CHECK( !fs::exists( from_ph ) ); 711 BOOST_CHECK( fs::exists( child_ph ) ); 712 } 713 673 714 // there was an inital bug in directory_iterator that caused premature 674 715 // close of an OS handle. This block will detect regression. 675 716 { -
libs/filesystem/src/operations.cpp
54 54 55 55 # if defined(BOOST_WINDOWS_API) 56 56 # include <windows.h> 57 # if _WIN32_WINNT >= 0x0500 58 # include <winioctl.h> 59 # endif 57 60 # if defined(__BORLANDC__) || defined(__MWERKS__) 58 61 # if defined(__BORLANDC__) 59 62 using std::time_t; … … 117 120 } 118 121 119 122 #ifdef BOOST_WINDOWS_API 123 124 # if _WIN32_WINNT >= 0x0500 125 const DWORD mount_point_tag = 0xA0000003; 126 127 struct reparse_data_header 128 { 129 DWORD tag; 130 WORD length; 131 WORD reserved; 132 }; 133 134 struct mount_point_header 135 { 136 WORD sub_name_offset; 137 WORD sub_name_length; 138 WORD print_name_offset; 139 WORD print_name_length; 140 }; 141 142 error_code set_mount_point( HANDLE handle, 143 const wchar_t* sub_name, std::size_t sub_name_length, 144 const wchar_t* print_name, std::size_t print_name_length ) 145 { 146 std::size_t full_size = 147 sizeof(reparse_data_header) + sizeof(mount_point_header) + 148 (sub_name_length+1 + print_name_length+1) * sizeof(wchar_t); 149 150 boost::scoped_array<char> buf( new char[full_size] ); 151 char * buf_ptr = buf.get(); 152 153 reparse_data_header top_head; 154 top_head.tag = mount_point_tag; 155 top_head.length = full_size - sizeof(top_head); 156 top_head.reserved = 0; 157 std::memcpy( buf_ptr, &top_head, sizeof(top_head) ); 158 buf_ptr += sizeof(top_head); 159 160 mount_point_header mt_head; 161 mt_head.sub_name_offset = 0; 162 mt_head.sub_name_length = sub_name_length * sizeof(wchar_t); 163 mt_head.print_name_offset = mt_head.sub_name_length + sizeof(wchar_t); 164 mt_head.print_name_length = print_name_length * sizeof(wchar_t); 165 std::memcpy( buf_ptr, &mt_head, sizeof(mt_head) ); 166 buf_ptr += sizeof(mt_head); 167 168 std::memcpy( buf_ptr, sub_name, sub_name_length * sizeof(wchar_t) ); 169 buf_ptr += sub_name_length * sizeof(wchar_t); 170 std::memset( buf_ptr, 0, sizeof(wchar_t) ); 171 buf_ptr += sizeof(wchar_t); 172 173 std::memcpy( buf_ptr, print_name, print_name_length * sizeof(wchar_t) ); 174 buf_ptr += print_name_length * sizeof(wchar_t); 175 std::memset( buf_ptr, 0, sizeof(wchar_t) ); 176 177 DWORD dummy = 0; 178 if ( ::DeviceIoControl( handle, FSCTL_SET_REPARSE_POINT, 179 buf.get(), full_size, 0, 0, &dummy, 0 ) == 0 ) 180 { 181 return error_code( ::GetLastError(), system_category ); 182 } 183 184 return error_code(); 185 } 186 # endif 187 120 188 121 189 // For Windows, the xxxA form of various function names is used to avoid 122 190 // inadvertently getting wide forms of the functions. (The undecorated … … 182 250 inline bool create_hard_link( const std::wstring & to_ph, 183 251 const std::wstring & from_ph ) 184 252 { return ::CreateHardLinkW( from_ph.c_str(), to_ph.c_str(), 0 ) != 0; } 253 254 error_code create_symbolic_link( const std::wstring & from_ph, 255 const std::wstring & to_ph, DWORD flags ) 256 { 257 typedef BOOL (APIENTRY * func_type)( LPCWSTR, LPCWSTR, DWORD ); 258 259 const wchar_t* from_s = from_ph.c_str(); 260 const wchar_t* to_s = to_ph.c_str(); 261 262 error_code ec( ERROR_NOT_SUPPORTED, system_category ); 263 HMODULE dll( ::LoadLibraryA("kernel32.dll") ); 264 func_type func = reinterpret_cast<func_type>( 265 ::GetProcAddress( dll, "CreateSymbolicLinkW" ) ); 266 if ( func ) 267 { 268 BOOL res = (*func)(from_s, to_s, flags); 269 if ( res ) { ec = error_code(); } 270 else { ec = error_code( ::GetLastError(), system_category ); } 271 } 272 ::FreeLibrary( dll ); 273 return ec; 274 } 275 276 error_code set_mount_point( HANDLE handle, const std::wstring & ph ) 277 { 278 std::wstring sub_name(L"\\\?\?\\"); 279 if ((ph[0] == L'\\') && (ph[1] == L'\\')) 280 sub_name += L"UNC"; 281 sub_name += ph; 282 283 return set_mount_point( 284 handle, sub_name.c_str(), sub_name.size(), ph.c_str(), ph.size() ); 285 } 185 286 #endif 186 287 187 288 # endif // ifndef BOOST_FILESYSTEM_NARROW_ONLY 188 289 290 inline fs::file_status make_status_error( error_code & ec ) 291 { 292 ec = error_code( ::GetLastError(), system_category ); 293 if ((ec.value() == ERROR_FILE_NOT_FOUND) 294 || (ec.value() == ERROR_PATH_NOT_FOUND) 295 || (ec.value() == ERROR_INVALID_NAME) // "tools/jam/src/:sys:stat.h", "//foo" 296 || (ec.value() == ERROR_INVALID_PARAMETER) // ":sys:stat.h" 297 || (ec.value() == ERROR_BAD_PATHNAME) // "//nosuch" on Win64 298 || (ec.value() == ERROR_BAD_NETPATH)) // "//nosuch" on Win32 299 { 300 ec = error_code(); // these are not considered errors; 301 // the status is considered not found 302 return fs::file_status( fs::file_not_found ); 303 } 304 else if ((ec.value() == ERROR_SHARING_VIOLATION)) 305 { 306 ec = error_code(); // these are not considered errors; 307 // the file exists but the type is not known 308 return fs::file_status( fs::type_unknown ); 309 } 310 return fs::file_status( fs::status_unknown ); 311 } 312 189 313 template< class String > 190 fs::file_status s tatus_template( const String & ph, error_code & ec )314 fs::file_status symlink_status_template( const String & ph, error_code & ec ) 191 315 { 192 316 DWORD attr( get_file_attributes( ph.c_str() ) ); 193 317 if ( attr == 0xFFFFFFFF ) 318 { return make_status_error( ec ); } 319 ec = error_code();; 320 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) 321 return fs::file_status( fs::symlink_file ); 322 return (attr & FILE_ATTRIBUTE_DIRECTORY) 323 ? fs::file_status( fs::directory_file ) 324 : fs::file_status( fs::regular_file ); 325 } 326 327 template< class String > 328 fs::file_status status_template( const String & ph, error_code & ec ) 329 { 330 fs::file_status sf( symlink_status_template( ph, ec ) ); 331 if ( !fs::is_symlink( sf ) ) 332 return sf; 333 334 handle_wrapper hw( create_file( ph.c_str(), 0, 335 FILE_SHARE_READ|FILE_SHARE_WRITE, 0, 336 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ) ); 337 if ( hw.handle == INVALID_HANDLE_VALUE ) 338 { return make_status_error( ec ); } 339 BY_HANDLE_FILE_INFORMATION info; 340 if ( !::GetFileInformationByHandle( hw.handle, &info ) ) 194 341 { 195 342 ec = error_code( ::GetLastError(), system_category ); 196 if ((ec.value() == ERROR_FILE_NOT_FOUND)197 || (ec.value() == ERROR_PATH_NOT_FOUND)198 || (ec.value() == ERROR_INVALID_NAME) // "tools/jam/src/:sys:stat.h", "//foo"199 || (ec.value() == ERROR_INVALID_PARAMETER) // ":sys:stat.h"200 || (ec.value() == ERROR_BAD_PATHNAME) // "//nosuch" on Win64201 || (ec.value() == ERROR_BAD_NETPATH)) // "//nosuch" on Win32202 {203 ec = error_code(); // these are not considered errors;204 // the status is considered not found205 return fs::file_status( fs::file_not_found );206 }207 else if ((ec.value() == ERROR_SHARING_VIOLATION))208 {209 ec = error_code(); // these are not considered errors;210 // the file exists but the type is not known211 return fs::file_status( fs::type_unknown );212 }213 343 return fs::file_status( fs::status_unknown ); 214 344 } 215 ec = error_code(); ;216 return ( attr& FILE_ATTRIBUTE_DIRECTORY)345 ec = error_code(); 346 return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 217 347 ? fs::file_status( fs::directory_file ) 218 348 : fs::file_status( fs::regular_file ); 219 349 } … … 223 353 { return ::GetFileAttributesExA( ph, ::GetFileExInfoStandard, &fad ); } 224 354 225 355 template< class String > 356 bool symbolic_link_exists_template( const String & ph ) 357 { 358 DWORD attr( get_file_attributes( ph.c_str() ) ); 359 return ( attr != 0xFFFFFFFF ) && (attr & FILE_ATTRIBUTE_REPARSE_POINT); 360 } 361 362 template< class String > 226 363 boost::filesystem::detail::query_pair 227 364 is_empty_template( const String & ph ) 228 365 { … … 517 654 error_code 518 655 remove_template( const String & ph ) 519 656 { 520 error_code ec; 521 fs::file_status sf( fs::detail::status_api( ph, ec ) ); 522 if ( ec ) return ec; 523 if ( fs::is_directory( sf ) ) 657 DWORD attr( get_file_attributes( ph.c_str() ) ); 658 if ( attr == 0xFFFFFFFF ) 524 659 { 660 error_code ec; 661 make_status_error( ec ); 662 return ec; 663 } 664 if (attr & FILE_ATTRIBUTE_DIRECTORY) 665 { 525 666 if ( !remove_directory( ph ) ) 526 667 return error_code(::GetLastError(), system_category); 527 668 } … … 544 685 error = error_code( ::GetLastError(), system_category ); 545 686 // an error here may simply mean the postcondition is already met 546 687 if ( error.value() == ERROR_ALREADY_EXISTS 547 && fs::is_directory( fs::detail::s tatus_api( dir_ph, dummy ) ) )688 && fs::is_directory( fs::detail::symlink_status_api( dir_ph, dummy ) ) ) 548 689 return std::make_pair( error_code(), false ); 549 690 return std::make_pair( error, false ); 550 691 } … … 553 694 inline bool create_hard_link( const std::string & to_ph, 554 695 const std::string & from_ph ) 555 696 { return ::CreateHardLinkA( from_ph.c_str(), to_ph.c_str(), 0 ) != 0; } 697 698 error_code create_symbolic_link( const std::string & from_ph, 699 const std::string & to_ph, DWORD flags ) 700 { 701 typedef BOOL (APIENTRY * func_type)( LPCSTR, LPCSTR, DWORD ); 702 703 const char* from_s = from_ph.c_str(); 704 const char* to_s = to_ph.c_str(); 705 706 error_code ec( ERROR_NOT_SUPPORTED, system_category ); 707 HMODULE dll( ::LoadLibraryA("kernel32.dll") ); 708 func_type func = reinterpret_cast<func_type>( 709 ::GetProcAddress( dll, "CreateSymbolicLinkA" ) ); 710 if ( func ) 711 { 712 BOOL res = (*func)(from_s, to_s, flags); 713 if ( res ) { ec = error_code(); } 714 else { ec = error_code( ::GetLastError(), system_category ); } 715 } 716 ::FreeLibrary( dll ); 717 return ec; 718 } 719 720 error_code set_mount_point( HANDLE handle, const std::string & ph ) 721 { 722 int w_size = 723 ::MultiByteToWideChar( CP_ACP, 0, ph.c_str(), ph.size(), 0, 0 ); 724 if (w_size == 0) 725 return error_code( ::GetLastError(), system_category ); 726 727 bool is_unc = (ph[0] == '\\') && (ph[1] == '\\'); 728 729 std::size_t prefix_length = is_unc ? 7 : 4; 730 std::size_t sub_name_length = prefix_length + w_size; 731 732 boost::scoped_array<wchar_t> sub_name( new wchar_t[sub_name_length] ); 733 734 wchar_t * ptr = sub_name.get(); 735 std::memcpy(ptr, L"\\\?\?\\", 4*sizeof(wchar_t)); 736 ptr += 4; 737 if (is_unc) 738 { 739 std::memcpy(ptr, L"UNC", 3*sizeof(wchar_t)); 740 ptr += 3; 741 } 742 743 w_size = 744 ::MultiByteToWideChar( CP_ACP, 0, ph.c_str(), ph.size(), ptr, w_size ); 745 if (w_size == 0) 746 return error_code( ::GetLastError(), system_category ); 747 748 return set_mount_point( 749 handle, &sub_name[0], sub_name_length, ptr, w_size ); 750 } 556 751 #endif 557 752 558 753 #if _WIN32_WINNT >= 0x500 … … 564 759 return error_code( create_hard_link( to_ph.c_str(), from_ph.c_str() ) 565 760 ? 0 : ::GetLastError(), system_category ); 566 761 } 762 763 template<class String> 764 class remove_directory_monitor 765 { 766 public: 767 explicit remove_directory_monitor( const String & ph ) 768 : m_path(ph), m_need_remove(true) 769 { 770 } 771 772 ~remove_directory_monitor() 773 { 774 if (m_need_remove) 775 remove_directory( m_path ); 776 } 777 778 void release() 779 { 780 m_need_remove = false; 781 } 782 783 private: 784 const String & m_path; 785 bool m_need_remove; 786 }; 787 788 template<class String> 789 error_code 790 create_directory_symlink_template( 791 const String & to_ph, const String & from_ph ) 792 { 793 if ( !create_directory( from_ph ) ) 794 return error_code( ::GetLastError(), system_category ); 795 796 remove_directory_monitor<String> guard( from_ph ); 797 798 handle_wrapper hw( 799 create_file( 800 from_ph.c_str(), GENERIC_WRITE, 801 FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 802 FILE_FLAG_BACKUP_SEMANTICS, 0 ) ); 803 804 error_code ec = set_mount_point( hw.handle, to_ph ); 805 if ( !ec ) 806 guard.release(); 807 return ec; 808 } 809 810 template<class String> 811 error_code 812 create_symlink_template( 813 const String & to_ph, const String & from_ph ) 814 { 815 error_code ec; 816 fs::file_status sf( fs::detail::symlink_status_api( to_ph, ec ) ); 817 if ( ec ) return ec; 818 if ( fs::is_directory( sf ) ) 819 { 820 ec = create_symbolic_link( from_ph, to_ph, 0 ); 821 if ( ec && ( ec == error_code( ERROR_NOT_SUPPORTED, system_category ) ) ) 822 { return create_directory_symlink_template( to_ph, from_ph ); } 823 else 824 { return ec; } 825 } 826 else 827 return create_symbolic_link( from_ph, to_ph, 0 ); 828 } 567 829 #endif 568 830 569 831 #endif … … 603 865 status_api( const std::string & ph, error_code & ec ) 604 866 { return status_template( ph, ec ); } 605 867 868 BOOST_FILESYSTEM_DECL fs::file_status 869 symlink_status_api( const std::string & ph, error_code & ec ) 870 { return symlink_status_template( ph, ec ); } 871 606 872 # ifndef BOOST_FILESYSTEM_NARROW_ONLY 607 873 608 874 BOOST_FILESYSTEM_DECL fs::file_status 609 875 status_api( const std::wstring & ph, error_code & ec ) 610 876 { return status_template( ph, ec ); } 611 877 612 BOOST_FILESYSTEM_DECL bool symbolic_link_exists_api( const std::wstring & ) 613 { return false; } 878 BOOST_FILESYSTEM_DECL fs::file_status 879 symlink_status_api( const std::wstring & ph, error_code & ec ) 880 { return symlink_status_template( ph, ec ); } 614 881 882 BOOST_FILESYSTEM_DECL bool 883 symbolic_link_exists_api( const std::wstring & ph ) 884 { return symbolic_link_exists_template( ph ); } 885 615 886 BOOST_FILESYSTEM_DECL 616 887 fs::detail::query_pair is_empty_api( const std::wstring & ph ) 617 888 { return is_empty_template( ph ); } … … 662 933 { return create_hard_link_template( to_ph, from_ph ); } 663 934 #endif 664 935 936 #if _WIN32_WINNT >= 0x500 665 937 BOOST_FILESYSTEM_DECL error_code 938 create_symlink_api( const std::wstring & to_ph, 939 const std::wstring & from_ph ) 940 { return create_symlink_template( to_ph, from_ph ); } 941 #else 942 BOOST_FILESYSTEM_DECL error_code 666 943 create_symlink_api( const std::wstring & /*to_ph*/, 667 944 const std::wstring & /*from_ph*/ ) 668 945 { return error_code( ERROR_NOT_SUPPORTED, system_category ); } 946 #endif 669 947 670 948 BOOST_FILESYSTEM_DECL error_code 671 949 remove_api( const std::wstring & ph ) { return remove_template( ph ); } … … 787 1065 # endif // ifndef BOOST_FILESYSTEM_NARROW_ONLY 788 1066 789 1067 // suggested by Walter Landry 790 BOOST_FILESYSTEM_DECL bool symbolic_link_exists_api( const std::string & ) 791 { return false; } 1068 BOOST_FILESYSTEM_DECL bool 1069 symbolic_link_exists_api( const std::string & ph ) 1070 { return symbolic_link_exists_template( ph ); } 792 1071 793 1072 BOOST_FILESYSTEM_DECL 794 1073 fs::detail::query_pair is_empty_api( const std::string & ph ) … … 842 1121 } 843 1122 #endif 844 1123 1124 #if _WIN32_WINNT >= 0x500 845 1125 BOOST_FILESYSTEM_DECL error_code 1126 create_symlink_api( const std::string & to_ph, 1127 const std::string & from_ph ) 1128 { 1129 return create_symlink_template( to_ph, from_ph ); 1130 } 1131 #else 1132 BOOST_FILESYSTEM_DECL error_code 846 1133 create_symlink_api( const std::string & /*to_ph*/, 847 1134 const std::string & /*from_ph*/ ) 848 1135 { return error_code( ERROR_NOT_SUPPORTED, system_category ); } 1136 #endif 849 1137 850 1138 BOOST_FILESYSTEM_DECL error_code 851 1139 remove_api( const std::string & ph ) { return remove_template( ph ); }