Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
214 views
in Technique[技术] by (71.8m points)

c - Checking if a dir. entry returned by readdir is a directory, link or file. dent->d_type isn't showing the type

I am making a program which is run in a Linux shell, and accepts an argument (a directory), and displays all the files in the directory, along with their type.

Output should be like this:

 << ./Program testDirectory

 Dir directory1
 lnk linkprogram.c
 reg file.txt

If no argument is made, it uses the current directory. Here is my code:

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
  struct stat info;
  DIR *dirp;
  struct dirent* dent;

  //If no args
  if (argc == 1)
  {

    argv[1] = ".";
    dirp = opendir(argv[1]); // specify directory here: "." is the "current directory"
    do
    {
      dent = readdir(dirp);
      if (dent)
      {
        printf("%c ", dent->d_type);
        printf("%s 
", dent->d_name);

        /* if (!stat(dent->d_name, &info))
         {
         //printf("%u bytes
", (unsigned int)info.st_size);

         }*/
      }
    } while (dent);
    closedir(dirp);

  }

  //If specified directory 
  if (argc > 1)
  {
    dirp = opendir(argv[1]); // specify directory here: "." is the "current directory"
    do
    {
      dent = readdir(dirp);
      if (dent)
      {
        printf("%c ", dent->d_type);
        printf("%s 
", dent->d_name);
        /*  if (!stat(dent->d_name, &info))
         {
         printf("%u bytes
", (unsigned int)info.st_size);
         }*/
      }
    } while (dent);
    closedir(dirp);

  }
  return 0;
}

For some reason dent->d_type is not displaying the type of file. I'm not really sure what to do, any suggestions?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

d_type is a speed optimization to save on lstat(2) calls, when it's supported.

As the readdir(3) man page points out, not all filesystems return real info in the d_type field (typically because it would take an extra disk seek to read the inode, as is the case for XFS if you didn't use mkfs.xfs -n ftype=1 (implied by -m crc=1 which is not yet the default). Filesystems that always set DT_UNKNOWN are common in real life, and not something that you can ignore. XFS is not the only example.

You always need code that will fall back to using lstat(2) if d_type==DT_UNKNOWN, if the filename alone isn't enough to decide it's uninteresting. (This is the case for some callers, like find -name or expanding globs like *.c, which is why readdir doesn't incur the overhead of filling it in if it would take an extra disk read.)

The Linux getdents(2) man page has an example program that does what you're trying to do, including a chained-ternary-operator block to decode the d_type field into text strings. (As the other answers point out, your mistake is printing it out as an character, rather than comparing it against DT_REG, DT_DIR, etc.)

Anyway, the other answers mostly covered things, but missed the critical detail that you NEED a fallback for the case when d_type == DT_UNKNOWN (0 on Linux. d_type is stored in what used to be a padding byte, until Linux 2.6.4).

To be portable, your code needs to check that struct dirent even HAS a d_type field, if you use it, or your code won't even compile outside of GNU and BSD systems. (see readdir(3))


I wrote an example for finding directories with readdir, using d_type with a fallback to stat when d_type isn't available at compile time, when it's DT_UNKNOWN, and for symlinks.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...