From 3788ed23ca9dfe2d4af0d93e618b60eb6e142bac Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 7 Jan 2013 01:56:40 +0000 Subject: [PATCH] improve support for windows XP and earlier --- ChangeLog | 1 + src/file.cpp | 56 ++++++++++++++++++++++++-------- src/file_pool.cpp | 82 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 115 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index c00210406..9e4001fdc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * improve support for windows XP and earlier * introduce global connection priority for improved swarm performance * make files deleted alert non-discardable * make built-in sha functions not conflict with libcrypto diff --git a/src/file.cpp b/src/file.cpp index e5fe9e004..ec848d647 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1813,25 +1813,53 @@ namespace libtorrent return false; } } -#if _WIN32_WINNT >= 0x501 + if ((m_open_mode & sparse) == 0) { - // only allocate the space if the file - // is not fully allocated - DWORD high_dword = 0; - offs.LowPart = GetCompressedFileSize(m_path.c_str(), &high_dword); - offs.HighPart = high_dword; - ec.assign(GetLastError(), get_system_category()); - if (ec) return false; - if (offs.QuadPart != s) + typedef DWORD (WINAPI *GetCompressedFileSizeW_t)(LPCWSTR lpFileName, LPDWORD lpFileSizeHigh); + typedef BOOL (WINAPI *SetFileValidData_t)(HANDLE hFile, LONGLONG ValidDataLength); + + static GetCompressedFileSizeW_t GetCompressedFileSizeW = NULL; + static SetFileValidData_t SetFileValidData = NULL; + + static bool failed_kernel32 = false; + + if ((GetCompressedFileSizeW == NULL) && !failed_kernel32) { - // if the user has permissions, avoid filling - // the file with zeroes, but just fill it with - // garbage instead - SetFileValidData(m_file_handle, offs.QuadPart); + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + if (kernel32) + { + GetCompressedFileSizeW = (GetCompressedFileSizeW_t)GetProcAddress(kernel32, "GetCompressedFileSizeW"); + SetFileValidData = (SetFileValidData_t)GetProcAddress(kernel32, "SetFileValidData"); + if ((GetCompressedFileSizeW == NULL) || (SetFileValidData == NULL)) + { + failed_kernel32 = true; + } + } + else + { + failed_kernel32 = true; + } + } + + if (!failed_kernel32 && GetCompressedFileSizeW && SetFileValidData) + { + // only allocate the space if the file + // is not fully allocated + DWORD high_dword = 0; + offs.LowPart = GetCompressedFileSize(m_path.c_str(), &high_dword); + offs.HighPart = high_dword; + ec.assign(GetLastError(), get_system_category()); + if (ec) return false; + if (offs.QuadPart != s) + { + // if the user has permissions, avoid filling + // the file with zeroes, but just fill it with + // garbage instead + SetFileValidData(m_file_handle, offs.QuadPart); + } } } -#endif // _WIN32_WINNT >= 0x501 #else // NON-WINDOWS struct stat st; if (fstat(m_fd, &st) != 0) diff --git a/src/file_pool.cpp b/src/file_pool.cpp index 11dd8fee0..79d0f0003 100644 --- a/src/file_pool.cpp +++ b/src/file_pool.cpp @@ -101,6 +101,73 @@ namespace libtorrent } #endif +#ifdef TORRENT_WINDOWS + void set_low_priority(boost::intrusive_ptr const& f) + { + // file prio is only supported on vista and up + // so load the functions dynamically + typedef enum _FILE_INFO_BY_HANDLE_CLASS { + FileBasicInfo, + FileStandardInfo, + FileNameInfo, + FileRenameInfo, + FileDispositionInfo, + FileAllocationInfo, + FileEndOfFileInfo, + FileStreamInfo, + FileCompressionInfo, + FileAttributeTagInfo, + FileIdBothDirectoryInfo, + FileIdBothDirectoryRestartInfo, + FileIoPriorityHintInfo, + FileRemoteProtocolInfo, + MaximumFileInfoByHandleClass + } FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS; + + typedef enum _PRIORITY_HINT { + IoPriorityHintVeryLow = 0, + IoPriorityHintLow, + IoPriorityHintNormal, + MaximumIoPriorityHintType + } PRIORITY_HINT; + + typedef struct _FILE_IO_PRIORITY_HINT_INFO { + PRIORITY_HINT PriorityHint; + } FILE_IO_PRIORITY_HINT_INFO, *PFILE_IO_PRIORITY_HINT_INFO; + + typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize); + static SetFileInformationByHandle_t SetFileInformationByHandle = NULL; + + static bool failed_kernel_load = false; + + if (failed_kernel_load) return; + + if (SetFileInformationByHandle == NULL) + { + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + if (kernel32 == NULL) + { + failed_kernel_load = true; + return; + } + + SetFileInformationByHandle = (SetFileInformationByHandle_t)GetProcAddress(kernel32, "SetFileInformationByHandle"); + if (SetFileInformationByHandle == NULL) + { + failed_kernel_load = true; + return; + } + } + + TORRENT_ASSERT(SetFileInformationByHandle); + + FILE_IO_PRIORITY_HINT_INFO io_hint; + io_hint.PriorityHint = IoPriorityHintLow; + SetFileInformationByHandle(f->native_handle(), + FileIoPriorityHintInfo, &io_hint, sizeof(io_hint)); + } +#endif // TORRENT_WINDOWS + boost::intrusive_ptr file_pool::open_file(void* st, std::string const& p , file_storage::iterator fe, file_storage const& fs, int m, error_code& ec) { @@ -154,17 +221,8 @@ namespace libtorrent return boost::intrusive_ptr(); } #ifdef TORRENT_WINDOWS -// file prio is supported on vista and up -#if _WIN32_WINNT >= 0x0600 if (m_low_prio_io) - { - // TODO: load this function dynamically from Kernel32.dll - FILE_IO_PRIORITY_HINT_INFO priorityHint; - priorityHint.PriorityHint = IoPriorityHintLow; - SetFileInformationByHandle(e.file_ptr->native_handle(), - FileIoPriorityHintInfo, &priorityHint, sizeof(priorityHint)); - } -#endif + set_low_priority(e.file_ptr); #endif TORRENT_ASSERT(e.file_ptr->is_open()); e.mode = m; @@ -189,6 +247,10 @@ namespace libtorrent std::string full_path = combine_path(p, fs.file_path(*fe)); if (!e.file_ptr->open(full_path, m, ec)) return boost::intrusive_ptr(); +#ifdef TORRENT_WINDOWS + if (m_low_prio_io) + set_low_priority(e.file_ptr); +#endif e.mode = m; e.key = st; m_files.insert(std::make_pair(std::make_pair(st, fs.file_index(*fe)), e));