Plain C: opening a directory with fopen ()

I have a program that 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.\n", argv[1]); fclose(fd); exit(1); } 

Now, at least under Linux, fopen() returns a valid file descriptor when opening a directory. This leads to the return of the -1 operation (or, as unsigned size_t , 0xFFFFFFFF on a 64-bit system).

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

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

+6
source share
2 answers

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

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

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

Instead, the code should be

 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 the libc-2.17 and 3.10.6 kernel, the codes work fine when argv[1] is /tmp ; unexpectedly, flen is LONG_MAX ie 0x7fffffffffffffff

By the way, in Linux directories are a special case of files. Use stat (2) in the file path (and fstat to the file descriptor , possibly obtained with fileno (3) from some FILE* ) to find out more metadata about a file, including its "type" (via its mode ) You want opendir (3) , readdir (3), and closedir (3) to work with the contents of the directory. See also inode (7) .

+3
source

From 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. 

At least on Linux, if you try fopen("dirname", "wb") , you will get an EISDIR error. I also tried with a directory with permissions d -------- and I still get EISDIR (and not EACCES.)

+6
source

Source: https://habr.com/ru/post/951576/


All Articles