forked from premiere/premiere-libtorrent
windows storage fixes
This commit is contained in:
parent
344e6c8a3b
commit
4d49d0f20d
144
src/file.cpp
144
src/file.cpp
|
@ -1168,7 +1168,8 @@ namespace libtorrent
|
|||
CloseHandle(ol.hEvent);
|
||||
return -1;
|
||||
}
|
||||
if (GetOverlappedResult(m_file_handle, &ol, &ret, true) == 0)
|
||||
DWORD num_read;
|
||||
if (GetOverlappedResult(m_file_handle, &ol, &num_read, true) == 0)
|
||||
{
|
||||
if (GetLastError() != ERROR_HANDLE_EOF)
|
||||
{
|
||||
|
@ -1177,6 +1178,7 @@ namespace libtorrent
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
if (num_read < ret) ret = num_read;
|
||||
}
|
||||
CloseHandle(ol.hEvent);
|
||||
return ret;
|
||||
|
@ -1358,17 +1360,12 @@ namespace libtorrent
|
|||
ol.hEvent = CreateEvent(0, true, false, 0);
|
||||
|
||||
ret += size;
|
||||
// if file_size is > 0, the file will be opened in unbuffered
|
||||
// mode after the write completes, and truncate the file to
|
||||
// file_size.
|
||||
size_type file_size = 0;
|
||||
|
||||
if ((size & (m_page_size-1)) != 0)
|
||||
{
|
||||
// if size is not an even multiple, this must be the tail
|
||||
// of the file. Write the whole page and then open a new
|
||||
// file without FILE_FLAG_NO_BUFFERING and set the
|
||||
// file size to file_offset + size
|
||||
// of the file.
|
||||
|
||||
file_size = file_offset + size;
|
||||
size = num_pages * m_page_size;
|
||||
|
@ -1384,95 +1381,17 @@ namespace libtorrent
|
|||
CloseHandle(ol.hEvent);
|
||||
return -1;
|
||||
}
|
||||
DWORD tmp;
|
||||
if (GetOverlappedResult(m_file_handle, &ol, &tmp, true) == 0)
|
||||
DWORD num_written;
|
||||
if (GetOverlappedResult(m_file_handle, &ol, &num_written, true) == 0)
|
||||
{
|
||||
ec.assign(GetLastError(), get_system_category());
|
||||
CloseHandle(ol.hEvent);
|
||||
return -1;
|
||||
}
|
||||
if (tmp < ret) ret = tmp;
|
||||
if (num_written < ret) ret = num_written;
|
||||
}
|
||||
CloseHandle(ol.hEvent);
|
||||
|
||||
if (file_size > 0)
|
||||
{
|
||||
#define FileEndOfFileInformation 20
|
||||
#ifndef NT_SUCCESS
|
||||
#define NT_SUCCESS(x) (!((x) & 0x80000000))
|
||||
#endif
|
||||
|
||||
// for NtSetInformationFile, see:
|
||||
// http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtSetInformationFile.html
|
||||
|
||||
typedef DWORD _NTSTATUS;
|
||||
typedef _NTSTATUS (NTAPI * NtSetInformationFile_t)(HANDLE file, PULONG_PTR iosb, PVOID data, ULONG len, ULONG file_info_class);
|
||||
|
||||
static NtSetInformationFile_t NtSetInformationFile = 0;
|
||||
static bool failed_ntdll = false;
|
||||
|
||||
if (NtSetInformationFile == 0 && !failed_ntdll)
|
||||
{
|
||||
HMODULE nt = LoadLibraryA("ntdll");
|
||||
if (nt)
|
||||
{
|
||||
NtSetInformationFile = (NtSetInformationFile_t)GetProcAddress(nt, "NtSetInformationFile");
|
||||
if (NtSetInformationFile == 0) failed_ntdll = true;
|
||||
}
|
||||
else failed_ntdll = true;
|
||||
}
|
||||
|
||||
if (failed_ntdll || NtSetInformationFile == 0)
|
||||
{
|
||||
// if we fail to load NtSetInformationFile from ntdll, fall
|
||||
// back to the old re-open-file-and-truncate trick
|
||||
|
||||
// TODO: this codepath will always fail unless we close this
|
||||
// file first, and then re-open it again. Doing that though,
|
||||
// opens up for race conditions where other applications may
|
||||
// acquire an exclusive lock to the file, at which case we're screwed.
|
||||
|
||||
HANDLE f = CreateFile_(m_path.c_str(), GENERIC_WRITE
|
||||
, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING
|
||||
, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0);
|
||||
|
||||
if (f == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ec.assign(GetLastError(), get_system_category());
|
||||
return -1;
|
||||
}
|
||||
|
||||
LARGE_INTEGER offs;
|
||||
offs.QuadPart = file_size;
|
||||
if (SetFilePointerEx(f, offs, &offs, FILE_BEGIN) == FALSE)
|
||||
{
|
||||
CloseHandle(f);
|
||||
ec.assign(GetLastError(), get_system_category());
|
||||
return -1;
|
||||
}
|
||||
if (::SetEndOfFile(f) == FALSE)
|
||||
{
|
||||
ec.assign(GetLastError(), get_system_category());
|
||||
CloseHandle(f);
|
||||
return -1;
|
||||
}
|
||||
CloseHandle(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULONG_PTR Iosb[2];
|
||||
LARGE_INTEGER fsize;
|
||||
fsize.QuadPart = file_size;
|
||||
_NTSTATUS st = NtSetInformationFile(native_handle()
|
||||
, Iosb, &fsize, sizeof(fsize), FileEndOfFileInformation);
|
||||
if (!NT_SUCCESS(st))
|
||||
{
|
||||
ec.assign(INVALID_SET_FILE_POINTER, get_system_category());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file_size > 0) set_size(file_size, ec);
|
||||
return ret;
|
||||
#else
|
||||
size_type ret = lseek(m_fd, file_offset, SEEK_SET);
|
||||
|
@ -1637,6 +1556,53 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(s >= 0);
|
||||
|
||||
#ifdef TORRENT_WINDOWS
|
||||
|
||||
if ((m_open_mode & no_buffer) && (s & (size_alignment()-1)) != 0)
|
||||
{
|
||||
// the file is opened in unbuffered mode, and the size is not
|
||||
// aligned to the required cluster size. Use NtSetInformationFile
|
||||
|
||||
#define FileEndOfFileInformation 20
|
||||
#ifndef NT_SUCCESS
|
||||
#define NT_SUCCESS(x) (!((x) & 0x80000000))
|
||||
#endif
|
||||
|
||||
// for NtSetInformationFile, see:
|
||||
// http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtSetInformationFile.html
|
||||
|
||||
typedef DWORD _NTSTATUS;
|
||||
typedef _NTSTATUS (NTAPI * NtSetInformationFile_t)(HANDLE file, PULONG_PTR iosb, PVOID data, ULONG len, ULONG file_info_class);
|
||||
|
||||
static NtSetInformationFile_t NtSetInformationFile = 0;
|
||||
static bool failed_ntdll = false;
|
||||
|
||||
if (NtSetInformationFile == 0 && !failed_ntdll)
|
||||
{
|
||||
HMODULE nt = LoadLibraryA("ntdll");
|
||||
if (nt)
|
||||
{
|
||||
NtSetInformationFile = (NtSetInformationFile_t)GetProcAddress(nt, "NtSetInformationFile");
|
||||
if (NtSetInformationFile == 0) failed_ntdll = true;
|
||||
}
|
||||
else failed_ntdll = true;
|
||||
}
|
||||
|
||||
if (!failed_ntdll && NtSetInformationFile)
|
||||
{
|
||||
ULONG_PTR Iosb[2];
|
||||
LARGE_INTEGER fsize;
|
||||
fsize.QuadPart = s;
|
||||
_NTSTATUS st = NtSetInformationFile(m_file_handle
|
||||
, Iosb, &fsize, sizeof(fsize), FileEndOfFileInformation);
|
||||
if (!NT_SUCCESS(st))
|
||||
{
|
||||
ec.assign(INVALID_SET_FILE_POINTER, get_system_category());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LARGE_INTEGER offs;
|
||||
LARGE_INTEGER cur_size;
|
||||
if (GetFileSizeEx(m_file_handle, &cur_size) == FALSE)
|
||||
|
|
|
@ -1250,8 +1250,8 @@ ret:
|
|||
bytes_transferred = (int)(this->*op.unaligned_op)(file_handle, adjusted_offset
|
||||
, tmp_bufs, num_tmp_bufs, ec);
|
||||
if (op.mode == file::read_write
|
||||
&& adjusted_offset + bytes_transferred == file_iter->size
|
||||
&& file_handle->pos_alignment() > 0)
|
||||
&& adjusted_offset + bytes_transferred >= file_iter->size
|
||||
&& (file_handle->pos_alignment() > 0 || file_handle->size_alignment() > 0))
|
||||
{
|
||||
// we were writing, and we just wrote the last block of the file
|
||||
// we likely wrote a bit too much, since we're restricted to
|
||||
|
@ -1266,6 +1266,7 @@ ret:
|
|||
{
|
||||
bytes_transferred = (int)((*file_handle).*op.regular_op)(adjusted_offset
|
||||
, tmp_bufs, num_tmp_bufs, ec);
|
||||
TORRENT_ASSERT(bytes_transferred <= bufs_size(tmp_bufs, num_tmp_bufs));
|
||||
}
|
||||
file_offset = 0;
|
||||
|
||||
|
|
|
@ -487,11 +487,13 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
|
||||
// test unaligned read (where the bytes are not aligned)
|
||||
ret = s->read(piece, 0, 3, piece_size-9);
|
||||
TEST_CHECK(ret == piece_size - 9);
|
||||
if (ret != piece_size - 9) print_error(ret, s);
|
||||
TEST_CHECK(std::equal(piece, piece + piece_size-9, piece1+3));
|
||||
|
||||
// verify piece 1
|
||||
ret = s->read(piece, 0, 0, piece_size);
|
||||
TEST_CHECK(ret == piece_size);
|
||||
if (ret != piece_size) print_error(ret, s);
|
||||
TEST_CHECK(std::equal(piece, piece + piece_size, piece1));
|
||||
|
||||
|
|
Loading…
Reference in New Issue