普通 C:用 fopen() 打开一个目录 [英] plain C: opening a directory with fopen()

查看:89
本文介绍了普通 C:用 fopen() 打开一个目录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

FILE* fd = fopen(argv[1], "rb");fseek(fd, 0, SEEK_END);size_t flen = ftell(fd);如果(flen ==((size_t)-1)){printf("%s 是一个目录.
", argv[1]);fclose(fd);退出(1);}

现在,至少在 Linux 下,fopen() 在打开目录时返回一个有效的文件描述符.这导致搜索操作返回 -1(或者,由于 size_t 是无符号的,0xFFFFFFFFFFFFFFFF=264-1 在 64 位系统上).

不幸的是,上面代码中的条件 (flen == ((size_t)-1)) 没有捕捉到这种情况,flen == 0xFFFFFFFF (应该是 0xFFFFFFFFFFFFFFFF).printf()-使用%x ord %d 作为格式字符串的命令表明比较的两边应该具有相同的值.>

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

解决方案

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");如果(!fd){ perror(argv[1]);退出(EXIT_FAILURE);};如果(fseek(fd,0,SEEK_END)<0){ perror("fseek");退出(EXIT_FAILURE);};长 flen = ftell(fd);如果(flen == -1L){ perror("ftell");退出(EXIT_FAILURE);};

顺便说一句,在带有 libc-2.17 和 3.10.6 内核的 Linux/Debian/Sid/AMD64 上,当 argv[1]/tmp;令人惊讶的是,flenLONG_MAX0x7fffffffffffffff

顺便说一句,在 Linux 上,目录是文件的一种特殊情况.在文件路径上使用 stat(2)(和 文件描述符上的>fstat,可能通过fileno(3) from some FILE*) 了解更多元有关某个文件的数据,包括其类型"(通过其模式).你想要 opendir(3), readdir(3) &closedir(3) 对目录内容进行操作.另请参阅 inode(7).

I have a program which opens a file and checks its length.

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.
", argv[1]);
    fclose(fd);
    exit(1);
}

Now, at least under Linux, fopen() returns a valid file descriptor when opening a directory. This results in the seek operation returning -1 (or, as size_t is unsigned, 0xFFFFFFFFFFFFFFFF=264-1 on a 64-bit system).

Unfortunately, the condition in the above code (flen == ((size_t)-1)) does not catch that case, neither does flen == 0xFFFFFFFF (EDIT: should be 0xFFFFFFFFFFFFFFFF). printf()-Commands with %x ord %d as format string show that both sides of the comparison should have the same value.

Why does the comparison operator behave in such a strange way, even when both sides are of the same type (size_t)? I am using gcc 4.8.1 as compiler.

解决方案

Directories do not exist in the C99 standard (or the C2011 one). So by definition, fopen-ing a directory is either implementation specific or undefined behavior.

fopen(3) can fail (giving a NULL result). fseek(3) can also fail (by returning -1). And then you should preferably check errno(3) or use perror(3)

ftell is documented to return a long, and -1L on failure. On 64 bits Linux this is 0xffffffffffffffff.

You code should be instead

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); };

BTW, On Linux/Debian/Sid/AMD64 with libc-2.17 and 3.10.6 kernel, that codes runs ok when argv[1] is /tmp; surprizingly, flen is LONG_MAX i.e. 0x7fffffffffffffff

BTW, on Linux, directories are a special case of files. Use stat(2) on a file path (and fstat on a file descriptor, perhaps obtained with fileno(3) from some FILE*) to know more meta data about some file, including its "type" (thru its mode). You want opendir(3), readdir(3) & closedir(3) to operate on directory contents. See also inode(7).

这篇关于普通 C:用 fopen() 打开一个目录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆