问题
Is there any way to map a file's content into memory in Windows that does not hold a lock on the file (in particular, such that the file can be deleted while still mmap'd)?
The Java NIO libraries mmap files in Windows in such a way that the mapped file cannot be deleted while there is any non garbage collected MappedByteBuffer reference left in the heap. The JDK team claim that this is a limitation of Windows, but only when files are mmap'd, not when they are opened as regular files:
https://mail.openjdk.java.net/pipermail/nio-dev/2019-January/005698.html
(Obviously if a file is deleted while mmap'd, exactly what should happen to the mmap'd region is debatable in the world of Windows file semantics, though it's well-defined in Linux.)
For reference, the inability to delete files while they are memory mapped (or not yet garbage collected) creates a lot of problems in Java:
http://www.mapdb.org/blog/mmap_files_alloc_and_jvm_crash/
And there are security reasons why an unmap operation is not supported:
https://bugs.openjdk.java.net/browse/JDK-4724038
UPDATE: See also: How to unmap an mmap'd file by replacing with a mapping to empty pages
回答1:
as noted @eryksun we can delete mapped file, if section(file mapping) was created without SEC_IMAGE attribute in 2 ways:
- open file with FILE_FLAG_DELETE_ON_CLOSE flag - The file is to be deleted immediately after all of its handles are closed, which includes the specified handle and any other open or duplicated handles. or we can use NtOpenFile or NtCreateFile call with flag FILE_DELETE_ON_CLOSE.
- by call ZwDeleteFile. really internal
NtDeleteFile
open file withFILE_DELETE_ON_CLOSE
flag and special internal disposition DeleteOnly = TRUE. this is make call more efficient compare normal open file and then close it handle.
in code this look like.
#ifndef FILE_SHARE_VALID_FLAGS
#define FILE_SHARE_VALID_FLAGS 0x00000007
#endif
NTSTATUS Delete1(PCWSTR FileName)
{
HANDLE hFile = CreateFile(FileName, DELETE, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return RtlGetLastNtStatus();
}
CloseHandle(hFile);
return 0;
}
NTSTATUS Delete2(PCWSTR FileName)
{
UNICODE_STRING ObjectName;
if (RtlDosPathNameToNtPathName_U(FileName, &ObjectName, 0, 0))
{
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName };
NTSTATUS status = ZwDeleteFile(&oa);
RtlFreeUnicodeString(&ObjectName);
return status;
}
return STATUS_UNSUCCESSFUL;
}
note that call DeleteFileW fail here with status - STATUS_CANNOT_DELETE
. i recomendate call RtlGetLastNtStatus()
here instead GetLastError() because win32 mapping NTSTATUS
to error code is not injective and frequently lost valuable information. say STATUS_CANNOT_DELETE
mapped to ERROR_ACCESS_DENIED
. but exist huge another NTSATUS
codes which also mapped to ERROR_ACCESS_DENIED
. the ERROR_ACCESS_DENIED
not only STATUS_ACCESS_DENIED
(real access denied). got STATUS_CANNOT_DELETE
much more informative here compare ERROR_ACCESS_DENIED
. the RtlGetLastNtStatus
have exactly same signature as GetLastError
and exported from ntdll.dll ( so include ntdll.lib or ntdllp.lib)
extern "C" NTSYSCALLAPI NTSTATUS NTAPI RtlGetLastNtStatus();
来源:https://stackoverflow.com/questions/54138684/memory-mapping-a-file-in-windows-with-share-attribute-so-file-is-not-locked-aga