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

huangapple go评论93阅读模式
英文:

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错误。

我阅读了这个问题(How to check if stdout has been redirected to NUL on Windows (a.k.a. /dev/null on Linux)?),据我了解,你不能对stdout进行状态检查?

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

英文:

I'm trying to figure out how I can test if a file is being redirected to itself, e.g. .\command.exe file1 > file1

In the *nix world, I'd just use something like this:

<!-- language: c -->

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

But in Windows, if I try to do this:

<!-- language: lang-go -->

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

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

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

...I get the IncorrectFunction error.

I read this (How to check if stdout has been redirected to NUL on Windows (a.k.a. /dev/null on Linux)?) question, and from what I gather you can't stat stdout?

This is a mostly language agnostic question -- I can translate whatever to Go (the language I'm using). I'm mostly concerned about how, using Windows' ABI (API?), I would find where stdout is being redirected to.

答案1

得分: 1

这个答案是针对Windows的,但是你已经标记了[tag: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将失败,但如果它被重定向到一个文件,它将返回文件路径。

英文:

This answer is Windows-specific but as you've tagged [tag:windows] I figure that's ok.

I can't help with Go, but in C/C++ you can do something like this:

<!-- language: lang-c -->

#include &lt;tchar.h&gt;
#include &lt;Windows.h&gt;
#include &lt;iostream&gt;

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

	return 0;
}

GetFinalPathNameByHandle will fail if stdout is a console handle, but if it's been redirected to a file it will return the file path.

答案2

得分: 1

你可以使用[HANDLE GetStdHandle(DWORD stdHandle)函数并传入STD_INPUT_HANDLESTD_OUTPUT_HANDLE参数来打开文件句柄。

然后调用[DWORD GetFileType(HANDLE hFile)函数来检查返回的类型是否为FILE_TYPE_DISK

最后,调用[DWORD WINAPI GetFinalPathNameByHandle(HANDLE hFile, LPTSTR lpszFilePath, DWORD cchFilePath, DWORD dwFlags)函数来获取文件路径名,并比较名称是否相等。

英文:

You can call HANDLE GetStdHandle( DWORD stdHandle ) with STD_INPUT_HANDLE and STD_OUTPUT_HANDLE to open the file handle.

Then call DWORD GetFileType( HANDLE hFile ) to check if the returned type is FILE_TYPE_DISK

Finally, call

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

to obtain the file pathname and compare the names for equivalency.

答案3

得分: 0

首先,我认为在UNIX环境中,你的方法实际上并不能保护你。

当你的代码检查设备和inode时,shell已经截断了文件。它负责处理输出重定向,并且在你的程序开始之前就完成了这个过程,所以你会得到一个全新的文件作为输出。

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

话虽如此,我相信在某个时候你必须相信用户知道他们在做什么 检查Windows文件是否被重定向到自身。

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

cmd.exe myscipt myscript

这样,你可以检测用户是否要写入输入文件(使用规范化的文件名或inode)并阻止它。

尽管如此,这仍然无法阻止用户做一些愚蠢的事情,比如:

cmd.exe myscipt >myscript

在你有机会通知他们应该提供两个参数而不是一个之前,将你的脚本彻底删除。

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

英文:

Well, first up, I don't think your method in UNIX-land is actually going to protect you.

By the time your code gets to checking devices and inodes, the shell has already truncated the file. It is responsible for processing the output redirections and it does this before your program even starts, so that you're given a fresh file for your output.

I suspect you'd have the same problem in Windows in that cmd.exe will truncate your file before your script even started running.

Having said that, I believe at some point you're going to have to trust that the user knows what they're doing 检查Windows文件是否被重定向到自身。

The other alternative is, of course, not to do output redirection but instead to require the input and output files as arguments:

cmd.exe myscipt myscript

That way, you could detect if the user was going to write to the input file (using canonicalised file names or inodes) and prevent it.

Although that still won't prevent the user from doing something silly like:

cmd.exe myscipt &gt;myscript

blowing away your script before you get a chance to notify them they should have provided two arguments rather than one.

I think the bottom line is, if the user does output redirection, there's no way for your program to catch it before it's too late.

huangapple
  • 本文由 发表于 2015年3月31日 13:06:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/29360969.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定