java-在Windows中使用SHARE属性对文件进行内存映射(因此未锁定文件以防删除)

有什么方法可以将文件内容映射到Windows中不持有文件锁的内存中(特别是可以在仍然映射时删除文件)?

Java NIO库在Windows中以这样一种方式mmap文件,使得在堆中留下任何未经垃圾回收的MappedByteBuffer引用时,无法删除映射文件. JDK团队声称这是Windows的局限性,但是仅当文件被mmap时才出现,而当它们作为常规文件打开时则没有:

https://mail.openjdk.java.net/pipermail/nio-dev/2019-January/005698.html

(显然,如果在mmap’d期间删除了文件,则在Windows文件语义世界中,对于mmap’d区域应该发生的确切情况是值得商bat的,尽管在Linux中已经定义好了.)

作为参考,在内存映射(或尚未垃圾回收)的情况下无法删除文件会在Java中造成很多问题:

http://www.mapdb.org/blog/mmap_files_alloc_and_jvm_crash/

出于安全原因,不支持取消映射操作:

https://bugs.openjdk.java.net/browse/JDK-4724038

更新:另请参见:How to unmap an mmap’d file by replacing with a mapping to empty pages

最佳答案
如前所述,如果通过2种方式创建的部分(文件映射)没有SEC_IMAGE属性,则可以删除映射文件:@eryksun

>使用FILE_FLAG_DELETE_ON_CLOSE标志打开文件-该文件是
在关闭所有句柄后立即删除
包括指定的句柄以及任何其他打开或重复的句柄
处理.或者我们可以使用NtOpenFileNtCreateFile
呼叫带有标志FILE_DELETE_ON_CLOSE.
>致电ZwDeleteFile.真的internal NtDeleteFile已打开
带有FILE_DELETE_ON_CLOSE标志和特殊内部文件的文件
性格DeleteOnly = TRUE.这是更多致电
高效比较正常的打开文件,然后关闭它的句柄.

在代码中看起来像这样.

#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,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))
    {
        OBJECT_ATTRIBUTES oa = { sizeof(oa),&ObjectName };

        NTSTATUS status = ZwDeleteFile(&oa);

        RtlFreeUnicodeString(&ObjectName);

        return status;
    }

    return STATUS_UNSUCCESSFUL;
}

请注意,呼叫DeleteFileW在这里失败,状态为STATUS_CANNOT_DELETE.我建议在这里而不是GetLastError()调用RtlGetLastNtStatus(),因为Win32将NTSTATUS映射到错误代码不是可注入的,并且经常丢失有价值的信息.说STATUS_CANNOT_DELETE映射到ERROR_ACCESS_DENIED.但是存在另一个巨大的NTSATUS代码,它们也映射到ERROR_ACCESS_DENIED. ERROR_ACCESS_DENIED不仅是STATUS_ACCESS_DENIED(拒绝实际访问).比较ERROR_ACCESS_DENIED,获得了STATUS_CANNOT_DELETE更多信息. RtlGetLastNtStatus具有与GetLastError完全相同的签名,并从ntdll.dll导出(因此包括ntdll.lib或ntdllp.lib)

extern "C" NTSYSCALLAPI NTSTATUS NTAPI RtlGetLastNtStatus();

相关文章

本文从从Bitcask存储模型讲起,谈轻量级KV系统设计与实现。从...
内部的放到gitlab pages的博客,需要统计PV,不蒜子不能准确...
PCM 自然界中的声音非常复杂,波形极其复杂,通常我们采用的...
本文介绍如何离线生成sst并在线加载,提供一种用rocksdb建立...
验证用户输入是否正确是我们应用程序中的常见功能。Spring提...
引入pdf2dom <dependency> <groupId&a...