检查 Windows 文件是否重定向到自身

Check if Windows file is redirected to itself

我正在尝试找出如何测试文件是否被重定向到自身,例如.\command.exe file1 > file1

在 *nix 世界中,我会使用这样的东西:

// Language agnostic...
if (file_dev == out_dev && file_ino == out_ino) {
    printf("%s\n", "same file!");
}

但是在 Windows 中,如果我尝试这样做:

// This (language) is Go...
// create fileStat...

// now stat stdout
outStat, err := os.Stdout.Stat()
// error check

if os.SameFile(fileStat, outStat) {
    fmt.Println("same file!")
}

...我收到 IncorrectFunction 错误。

我读了这个 () 问题,据我所知,你不能统计 stdout?

这是一个主要与语言无关的问题 -- 我可以将任何内容翻译成 Go(我正在使用的语言)。我主要关心 如何,使用 Windows' ABI(API?),我会找到 stdout 被重定向到的位置。

好吧,首先,我不认为你在 UNIX 领域的方法实际上 会保护你。

当您的代码开始检查设备和 inode 时,shell 已经 截断了文件。 负责处理输出重定向,它会在 之前 你的程序甚至开始,这样你就可以得到一个新的输出文件.

我怀疑您在 Windows 中会遇到同样的问题,因为 cmd.exe 甚至会在您的脚本开始之前截断您的文件 运行。

话虽如此,我相信在某些时候您将不得不相信用户知道他们在做什么:-)

另一种选择当然不是执行输出重定向,而是要求输入和输出文件作为参数:

cmd.exe myscipt myscript

这样,您可以检测用户是否要写入输入文件(使用规范化文件名或索引节点)并阻止它。

虽然仍然不会阻止用户做一些愚蠢的事情,比如:

cmd.exe myscipt >myscript

吹走你的脚本你有机会通知他们他们应该提供两个参数而不是一个之前。

我认为最重要的是,如果用户进行了输出重定向,您的程序将无法在为时已晚之前捕捉到它。

这个答案是 Windows 特定的,但正如你所标记的那样 "windows" 我认为没问题。

我帮不了 Go,但在 C/C++ 中你可以这样做:

#include <tchar.h>
#include <Windows.h>
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    wchar_t chPath[MAX_PATH];
    if (GetFinalPathNameByHandle(GetStdHandle(STD_OUTPUT_HANDLE), chPath, MAX_PATH, 0))
        std::wcout << L"stdout = " << chPath << std::endl;
    else
        std::cout << "stdout not redirected" << std::endl;

    return 0;
}
如果 stdout 是控制台句柄,

GetFinalPathNameByHandle 将失败,但如果它被重定向到文件,它将 return 文件路径。

您可以调用HANDLE GetStdHandle( DWORD stdHandle ) with STD_INPUT_HANDLE and STD_OUTPUT_HANDLE打开文件句柄。

然后调用DWORD GetFileType( HANDLE hFile ) to check if the returned type is FILE_TYPE_DISK

最后,致电

DWORD WINAPI GetFinalPathNameByHandle( _In_ HANDLE hFile, _Out_ LPTSTR lpszFilePath, _In_ DWORD cchFilePath, _In_ DWORD dwFlags );

获取文件路径名并比较名称是否等价。