use NtSetInformationFile to truncate files in unbuffered mode (to avoid having to close and re-open them)
This commit is contained in:
parent
99a209e3c9
commit
32dfc469c3
91
src/file.cpp
91
src/file.cpp
|
@ -1082,7 +1082,16 @@ namespace libtorrent
|
||||||
size += i->iov_len;
|
size += i->iov_len;
|
||||||
}
|
}
|
||||||
error_code code;
|
error_code code;
|
||||||
if (eof) TORRENT_ASSERT(file_offset + size >= get_size(code));
|
if (eof)
|
||||||
|
{
|
||||||
|
size_type fsize = get_size(code);
|
||||||
|
if (code) printf("get_size: %s\n", code.message().c_str());
|
||||||
|
if (file_offset + size < fsize)
|
||||||
|
{
|
||||||
|
printf("offset: %d size: %d get_size: %d\n", int(file_offset), int(size), int(fsize));
|
||||||
|
TORRENT_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1388,31 +1397,79 @@ namespace libtorrent
|
||||||
|
|
||||||
if (file_size > 0)
|
if (file_size > 0)
|
||||||
{
|
{
|
||||||
HANDLE f = CreateFile_(m_path.c_str(), GENERIC_WRITE
|
#define FileEndOfFileInformation 20
|
||||||
, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING
|
#ifndef NT_SUCCESS
|
||||||
, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0);
|
#define NT_SUCCESS(x) (!((x) & 0x80000000))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// for NtSetInformationFile, see:
|
||||||
|
// http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/NtSetInformationFile.html
|
||||||
|
|
||||||
if (f == INVALID_HANDLE_VALUE)
|
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)
|
||||||
{
|
{
|
||||||
ec.assign(GetLastError(), get_system_category());
|
HMODULE nt = LoadLibraryA("ntdll");
|
||||||
return -1;
|
if (nt)
|
||||||
|
{
|
||||||
|
NtSetInformationFile = (NtSetInformationFile_t)GetProcAddress(nt, "NtSetInformationFile");
|
||||||
|
if (NtSetInformationFile == 0) failed_ntdll = true;
|
||||||
|
}
|
||||||
|
else failed_ntdll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LARGE_INTEGER offs;
|
if (failed_ntdll || NtSetInformationFile == 0)
|
||||||
offs.QuadPart = file_size;
|
|
||||||
if (SetFilePointerEx(f, offs, &offs, FILE_BEGIN) == FALSE)
|
|
||||||
{
|
{
|
||||||
|
// 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);
|
CloseHandle(f);
|
||||||
ec.assign(GetLastError(), get_system_category());
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
if (::SetEndOfFile(f) == FALSE)
|
else
|
||||||
{
|
{
|
||||||
ec.assign(GetLastError(), get_system_category());
|
ULONG_PTR Iosb[2];
|
||||||
CloseHandle(f);
|
LARGE_INTEGER fsize;
|
||||||
return -1;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CloseHandle(f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue