注意:这是对此问题的完整重写。我之前曾将一些ACL问题与我正在寻找的问题混为一谈,这可能就是没有答案的原因。
我有一个Windows服务,它使用标准的打开/关闭/写入例程来编写日志文件(它从管道中读取内容并将其填充到日志中)。每天午夜都会打开一个新的日志文件。该系统是Windows XP Embedded。
该服务作为本地系统服务运行(用户为CreateService with NULL)。
当服务最初启动时,它会创建一个日志文件并写入它而没有任何问题。此时一切正常,您可以毫无问题地重新启动服务(或计算机)。
但是,在午夜(当天更改时),该服务会创建一个新的日志文件并写入该文件。有趣的是,这个新的日志文件设置了“只读”标志。这是一个问题,因为如果服务(或计算机)重新启动,服务将无法再打开文件进行写入。
以下是系统中已发生问题的相关信息:
Directory of C:\bbbaudit
09/16/2009 12:00 AM <DIR> .
09/16/2009 12:00 AM <DIR> ..
09/16/2009 12:00 AM 437 AU090915.ADX
09/16/2009 12:00 AM 62 AU090916.ADX
attrib c:\bbbaudit\*
A C:\bbbaudit\AU090915.ADX <-- old log file (before midnight)
A R C:\bbbaudit\AU090916.ADX <-- new log file (after midnight)
cacls output:
C:\ BUILTIN\Administrators:(OI)(CI)F
NT AUTHORITY\SYSTEM:(OI)(CI)F
CREATOR OWNER:(OI)(CI)(IO)F
BUILTIN\Users:(OI)(CI)R
BUILTIN\Users:(CI)(special access:)
FILE_APPEND_DATA
BUILTIN\Users:(CI)(IO)(special access:)
FILE_WRITE_DATA
Everyone:R
C:\bbbaudit BUILTIN\Administrators:(OI)(CI)F
NT AUTHORITY\SYSTEM:(OI)(CI)F
CFN3\Administrator:F
CREATOR OWNER:(OI)(CI)(IO)F
以下是我用来打开/创建日志文件的代码:
static int open_or_create_file(char *fname, bool &alreadyExists)
{
int fdes;
// try to create new file, fail if it already exists
alreadyExists = false;
fdes = open(fname, O_WRONLY | O_APPEND | O_CREAT | O_EXCL);
if (fdes < 0)
{
// try to open existing, don't create new file
alreadyExists = true;
fdes = open(fname, O_WRONLY | O_APPEND);
}
return fdes;
}
我在弄清楚文件如何获得该只读标志时遇到了麻烦。任何可以给我一个线索或方向的人,我都非常感激。
编译器是VC 6(是的,我知道,它已经过时了,它不好笑。直到你意识到我们刚刚从NT 3.51升级到XPE)。
答案 0 :(得分:4)
open()的Microsoft实现有一个可选的第三个参数'pmode',当第二个参数'oflag'包含O_CREAT标志时,它必须存在。 pmode参数指定文件权限设置,这些设置是在第一次关闭新文件时设置的。通常你会传递S_IREAD |用于pmode的S_IWRITE,导致普通的读/写文件。
在你的情况下你已经指定了O_CREAT但省略了第三个参数,所以open()使用了在第三个参数位置的堆栈上发生的任何值。 S_IWRITE的值是0x0080,因此如果第三个参数位置的值恰好有第7位清除,则会产生只读文件。您在某些时候只获得了只读文件这一事实与作为第三个参数传递的堆栈垃圾一致。
以下是open()的Visual Studio 2010文档的链接。自VC 6以来,函数行为的这一方面没有改变。
答案 1 :(得分:0)
嗯,在这种情况下,我不知道“开放”API的根本问题是什么。为了“解决”问题,我最终转而使用Win32 API进行文件管理(CreateFile,WriteFile,CloseHandle)。