plain C:用fopen()打开一个目录

Hei*_*ica 7 c linux io types

我有一个打开文件并检查其长度的程序.

FILE* fd = fopen(argv[1], "rb");
fseek(fd, 0, SEEK_END);
size_t flen = ftell(fd);
if (flen == ((size_t)-1)) {
    printf("%s is a directory.\n", argv[1]);
    fclose(fd);
    exit(1);
}
Run Code Online (Sandbox Code Playgroud)

现在,至少在Linux下,fopen()在打开目录时返回有效的文件描述符.这导致查找操作返回-1(或者,如64位系统上的size_t无符号,0xFFFFFFFFFFFFFFFF= 2 64 -1).

不幸的是,上面的代码(flen == ((size_t)-1))中的条件没有捕获到这种情况,也没有flen == 0xFFFFFFFF(编辑:应该0xFFFFFFFFFFFFFFFF).printf()- 使用%xord %d作为格式字符串的命令显示比较的两侧应具有相同的值.

为什么比较运算符的行为方式如此奇怪,即使双方的类型相同(size_t)?我使用gcc 4.8.1作为编译器.

小智 8

来自http://pubs.opengroup.org/onlinepubs/7908799/xsh/fopen.html:

The fopen() function will fail if: 
[EISDIR] The named file is a directory and mode requires write access.
Run Code Online (Sandbox Code Playgroud)

至少在Linux上,如果你试图fopen("dirname", "wb")得到EISDIR错误.我也试过一个带有d --------访问权限的目录,我仍然得到EISDIR(而不是EACCES.)


Bas*_*tch 7

C99 标准(或 C2011 标准)中不存在目录。因此,根据定义,fopen-ing 目录要么是特定于实现的行为,要么是未定义的行为。

fopen(3)可能会失败(给出NULL结果)。fseek(3)也可能失败(通过返回 -1)。然后你最好检查errno(3)或使用perror(3)

ftell记录为返回long, 并-1L在失败时返回。在 64 位 Linux 上,这是0xffffffffffffffff.

你的代码应该是

FILE* fd = fopen(argv[1], "rb");
if (!fd) 
  { perror(argv[1]); exit(EXIT_FAILURE); };
if (fseek(fd, 0, SEEK_END)<0) 
  { perror("fseek"); exit(EXIT_FAILURE); };
long flen = ftell(fd);
if (flen == -1L)
  { perror("ftell"); exit(EXIT_FAILURE); };
Run Code Online (Sandbox Code Playgroud)

顺便说一句,在Linux / Debian的/ SID / AMD64用的libc-2.17和3.10.6内核,该代码运行时确定argv[1]/tmp; 令人惊讶的flen是,LONG_MAX0x7fffffffffffffff

顺便说一句,在 Linux 上,目录是文件的一种特殊情况。使用统计(2)文件路径(和fstat上一个文件描述符,也许得到的fileno(3)一些FILE*)了解一些文件的更多元数据,包括“类型”(直通其模式)。您希望opendir(3)readdir(3)closedir(3)对目录内容进行操作。另见inode(7)