C 基于磁盘ID删除文件

C 基于磁盘ID删除文件,c,winapi,ntfs,createfile,C,Winapi,Ntfs,Createfile,如上所述,与一起使用 允许将具有打开句柄的文件设置为在关闭所有句柄时删除 但是,我试图根据和检索到的文件索引(磁盘ID)删除文件 为了安全地删除目录中仅区分大小写的文件/目录。 在我的用例中这样做是安全的,就像在NTFS系统上一样,文件索引是, 取消使用当前代码库处理的ReplaceFile 但是,当尝试删除句柄时,出现错误87(error\u INVALID\u参数)。 如果使用创建的句柄进行删除,则不会遇到任何问题。 但我不能这样做,因为Windows将无法区分相同情况下的两个文件/文件夹,

如上所述,与一起使用 允许将具有打开句柄的文件设置为在关闭所有句柄时删除

但是,我试图根据和检索到的文件索引(磁盘ID)删除文件 为了安全地删除目录中仅区分大小写的文件/目录。 在我的用例中这样做是安全的,就像在NTFS系统上一样,文件索引是, 取消使用当前代码库处理的
ReplaceFile

但是,当尝试删除句柄时,出现错误87(
error\u INVALID\u参数
)。 如果使用创建的句柄进行删除,则不会遇到任何问题。 但我不能这样做,因为Windows将无法区分相同情况下的两个文件/文件夹,即使NTFS可以

我还意识到,使用打开的硬链接文件存在歧义, 因为硬链接文件共享相同的磁盘ID。 硬链接文件的问题可以认为与此场景无关。 我将只删除ID目录,不能硬链接

我的通话中是否缺少参数或设置? 不知怎么的,在我的电话里

我尝试过的其他方法:

  • 使用句柄调用,为
    dwDesiredAccess
    提供
    DELETE
    ,并使用该句柄。 相同的
    错误\u无效\u参数
    结果
  • 与句柄一起使用,为
    dwDesiredAccess
    提供
    DELETE
    ,并使用该句柄。 相同的
    错误\u无效\u参数
    结果
  • 与手柄一起使用,为
    dwDesiredAccess
    提供
    DELETE
    ,并提供
    FILE\u标志\u DELETE\u ON\u CLOSE
    标志。 没有给出错误,但在关闭所有句柄后,文件仍保留
下面是一个最小但完整的示例,再现了问题:

#include <stdio.h>
#include <sys/stat.h>
#include <Windows.h>

DWORD getFileID(LPCWSTR path, LARGE_INTEGER *id)
{
    HANDLE h = CreateFileW(path, 0, 0, 0, OPEN_EXISTING,
        FILE_FLAG_OPEN_REPARSE_POINT |
        FILE_FLAG_BACKUP_SEMANTICS |
        FILE_FLAG_POSIX_SEMANTICS,
        0);
    if (h == INVALID_HANDLE_VALUE)
        return GetLastError();

    BY_HANDLE_FILE_INFORMATION info;
    if (!GetFileInformationByHandle(h, &info))
    {
        DWORD err = GetLastError();
        CloseHandle(h);
        return err;
    }
    id->HighPart = info.nFileIndexHigh;
    id->LowPart = info.nFileIndexLow;
    CloseHandle(h);
    return ERROR_SUCCESS;
}

DWORD deleteFileHandle(HANDLE fileHandle)
{
    FILE_DISPOSITION_INFO info;
    info.DeleteFileW = TRUE;
    if (!SetFileInformationByHandle(
        fileHandle, FileDispositionInfo, &info, sizeof(info)))
    {
        return GetLastError();
    }
    return ERROR_SUCCESS;
}

int wmain(DWORD argc, LPWSTR argv[])
{
    if (argc != 3)
    {
        fwprintf(stderr, L"Arguments: <rootpath> <path>\n");
        return 1;
    }

    DWORD err;
    HANDLE rootHandle = CreateFileW(
        argv[1], 0, 0, 0, OPEN_EXISTING,
        FILE_FLAG_OPEN_REPARSE_POINT |
        FILE_FLAG_BACKUP_SEMANTICS |
        FILE_FLAG_POSIX_SEMANTICS,
        0);
    if (rootHandle == INVALID_HANDLE_VALUE)
    {
        err = GetLastError();
        fwprintf(stderr,
            L"Could not open root directory '%s', error code %d\n",
            argv[1], err);
        return err;
    }

    LARGE_INTEGER fileID;
    err = getFileID(argv[2], &fileID);
    if (err != ERROR_SUCCESS)
    {
        fwprintf(stderr,
            L"Could not get file ID of file/directory '%s', error code %d\n",
            argv[2], err);
        CloseHandle(rootHandle);
        return err;
    }
    fwprintf(stdout,
        L"The file ID of '%s' is %lld\n",
        argv[2], fileID.QuadPart);

    FILE_ID_DESCRIPTOR idStruct;
    idStruct.Type = FileIdType;
    idStruct.FileId = fileID;
    HANDLE fileHandle = OpenFileById(
        rootHandle, &idStruct, DELETE, FILE_SHARE_DELETE, 0,
        FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
    if (fileHandle == INVALID_HANDLE_VALUE)
    {
        err = GetLastError();
        CloseHandle(rootHandle);
        fwprintf(stderr,
            L"Could not open file by ID %lld, error code %d\n",
            fileID.QuadPart, err);
        return err;
    }

    err = deleteFileHandle(fileHandle);
    if (err != ERROR_SUCCESS)
    {
        fwprintf(stderr,
            L"Could not delete file by ID '%lld', error code %d\n",
            fileID.QuadPart, err);
    }

    CloseHandle(fileHandle);
    struct _stat _tmp;
    fwprintf(stdout,
        L"File was %ssuccessfully deleted\n",
        (_wstat(argv[2], &_tmp) == 0) ? L"not " : L"");
    CloseHandle(rootHandle);
    return err;
}
#包括
#包括
#包括
DWORD getFileID(LPCWSTR路径,大整数*id)
{
HANDLE h=CreateFileW(路径,0,0,0,打开,
文件\u标志\u打开\u重新分析\u点|
文件\u标志\u备份\u语义|
文件\u标志\u位置\u语义,
0);
if(h==无效的\u句柄\u值)
返回GetLastError();
按(处理)(文件)(信息);;
if(!GetFileInformationByHandle(h,&info))
{
DWORD err=GetLastError();
闭合手柄(h);
返回错误;
}
id->HighPart=info.nFileIndexHigh;
id->LowPart=info.nFileIndexLow;
闭合手柄(h);
返回错误\成功;
}
DWORD deleteFileHandle(句柄文件句柄)
{
文件处理信息;
info.DeleteFileW=TRUE;
如果(!SetFileInformationByHandle(
fileHandle、FileDispositionInfo和info、sizeof(info)))
{
返回GetLastError();
}
返回错误\成功;
}
int wmain(DWORD argc,LPWSTR argv[])
{
如果(argc!=3)
{
fwprintf(stderr,L“参数:\n”);
返回1;
}
德沃德·厄尔;
HANDLE rootHandle=CreateFileW(
argv[1],0,0,0,打开现有的,
文件\u标志\u打开\u重新分析\u点|
文件\u标志\u备份\u语义|
文件\u标志\u位置\u语义,
0);
if(rootHandle==无效的\u句柄\u值)
{
err=GetLastError();
fwprintf(标准,
L“无法打开根目录“%s”,错误代码%d\n”,
argv[1],err);
返回错误;
}
大整数fileID;
err=getFileID(argv[2],&fileID);
如果(错误!=错误\u成功)
{
fwprintf(标准,
L“无法获取文件/目录“%s”的文件ID,错误代码%d\n”,
argv[2],err);
闭柄(rootHandle);
返回错误;
}
fwprintf(标准输出),
L““%s”的文件ID为%lld\n”,
argv[2],fileID.QuadPart);
文件\u ID\u描述符idStruct;
idStruct.Type=FileIdType;
idStruct.FileId=FileId;
HANDLE fileHandle=OpenFileById(
rootHandle,&idStruct,DELETE,文件共享\u DELETE,0,
文件(标记)打开(重新分析)点|文件(标记)备份(语义));
if(fileHandle==无效的句柄值)
{
err=GetLastError();
闭柄(rootHandle);
fwprintf(标准,
L“无法按ID%lld打开文件,错误代码%d\n”,
fileID.QuadPart,错误);
返回错误;
}
err=deleteFileHandle(fileHandle);
如果(错误!=错误\u成功)
{
fwprintf(标准,
L“无法删除ID为“%lld”的文件,错误代码为%d\n”,
fileID.QuadPart,错误);
}
CloseHandle(fileHandle);
结构统计tmp;
fwprintf(标准输出),
L“文件已成功删除%s\n”,
(_wstat(argv[2],&u tmp)=0)?L“不是”:L“);
闭柄(rootHandle);
返回错误;
}

任何解决方案都必须与Vista及以上版本配合使用。也欢迎对代码改进提出建议。

为了使
文件处理\u信息
有效,您需要在
创建文件
功能中指定删除访问权限,如下所述:

创建文件时必须指定适当的访问标志 与SetFileInformationByHandle一起使用的句柄。例如,如果 应用程序正在将文件\u处置\u信息与DeleteFile成员一起使用 如果设置为TRUE,则该文件需要在调用中请求删除访问权限 到CreateFile函数。要查看此示例,请参见示例 代码部分。有关文件权限的详细信息,请参阅文件 安全和访问权。 即

但是,似乎无法使用使用
OpenFileById()
创建的句柄,因为该函数无法接受
DELETE
标志。
从上的
OpenFileById()
可以读取: 希望

访问[输入]
对象的访问权限。访问可以是读、写或两者兼有

即使设置
DELETE
GENERIC\u ALL
功能也会失败。
如果将传递给
SetFileInformationByHandle
的句柄替换为
//...
  HANDLE hFile = CreateFile( TEXT("tempfile"), 
                             GENERIC_READ | GENERIC_WRITE | DELETE,  //Specify DELETE access!
                             0 /* exclusive access */,
                             NULL, 
                             CREATE_ALWAYS,
                             0, 
                             NULL);