我已经处理了几个星期的问题,现在更新需要独立于系统的20年代码(适用于Linux和Windows).它涉及检查时间,使用时间(TOCTOU)问题.我在这里做了一个帖子,但它没有走得太远,经过一段时间的反复思考并深入研究这个问题,我想我更好地理解了我的问题.也许我可以再问一下......
根据我的阅读,代码需要检查文件是否存在,是否可访问,打开文件,执行某些操作,最后关闭文件.似乎最好的方法是调用lstat(),调用fopen(),调用fstat()(以排除TOCTOU),然后执行操作并关闭文件.
但是,我一直认为lstat()并且fstat()是POSIX定义的,而不是 C标准定义的,排除了它们用于系统不可知程序的用法,同样open()不应该用于交叉兼容性.你会如何实现这个?
如果你看看我的第一篇文章,你可以看到20年前的开发人员使用C预处理器将代码切换成交叉兼容的部分,但即使我这样做,我也不知道要替换什么lstat()或者fstat()用什么(他们的windows同行).
编辑:为此帖添加了相关代码; 如果有什么不清楚请转到原始帖子
#ifdef WIN32
struct _stat buf;
#else
struct stat buf;
#endif //WIN32
FILE *fp;
char data[2560];
// Make sure file exists and is readable
#ifdef WIN32
if (_access(file.c_str(), R_OK) == -1) {
#else
if (access(file.c_str(), R_OK) == -1) {
#endif //WIN32
char message[2560];
sprintf(message, "File '%s' Not Found or Not Readable", file.c_str());
throw message;
}
// Get the file status information
#ifdef WIN32
if (_stat(file.c_str(), &buf) != 0) {
#else
if (stat(file.c_str(), &buf) != 0) {
#endif //WIN32
char message[2560];
sprintf(message, "File '%s' No Status Available", file.c_str());
throw message;
}
// Open the file for reading
fp = fopen(file.c_str(), "r");
if (fp == NULL) {
char message[2560];
sprintf(message, "File '%s' Cound Not be Opened", file.c_str());
throw message;
}
// Read the file
MvString s, ss;
while (fgets(data, sizeof(data), fp) != (char *)0) {
s = data;
s.trimBoth();
if (s.compare( 0, 5, "GROUP" ) == 0) {
//size_t t = s.find_last_of( ":" );
size_t t = s.find( ":" );
if (t != string::npos) {
ss = s.substr( t+1 ).c_str();
ss.trimBoth();
ss = ss.substr( 1, ss.length() - 3 ).c_str();
group_list.push_back( ss );
}
}
}
// Close the file
fclose(fp);
}
Run Code Online (Sandbox Code Playgroud)
检查文件是否存在且可以打开的可靠方法是尝试打开它.如果它被打开,一切都很好.如果它没有打开,你可以考虑花时间分析出了什么问题.
这个access()函数正式地从你的想法中提出了一个不同的问题; 它询问'真实用户ID或真实组ID是否可以访问该文件',但程序将使用有效用户ID或有效组ID来访问该文件.如果您的程序没有运行SUID或SGID,并且没有从运行SUID或SGID的程序启动 - 这是正常情况 - 那么没有区别.但问题是不同的.
使用stat()或
lstat()似乎没有帮助.特别是,lstat()只告诉您是否从符号链接开始,但代码并不关心它.
无论是access()和stat()电话为您提供漏洞TOCTOU窗口; 文件可以在报告存在后删除,也可以在报告不存在后创建.
你应该打电话fopen(),看看它是否有效; 代码将更简单,更能抵抗TOCTOU问题.您可能需要考虑是否使用open()其所有额外控件(O_EXCL等),然后将文件描述符转换为文件指针(fdopen()).
所有这些都适用于Unix方面.
细节将有所不同,但在Windows方面,您仍然最好尝试打开文件并对故障作出适当的反应.
在两个系统中,确保提供给open函数的选项是合适的.