linux下的opendir,readdir,closedir

 

enum
{
  DT_UNKNOWN = 0,
#define DT_UNKNOWN DT_UNKNOWN  //未知的类型
  DT_FIFO = 1,
#define DT_FIFO DT_FIFO        //命名管道或FIFO
  DT_CHR = 2,
#define DT_CHR DT_CHR          //字符设备文件
  DT_DIR = 4,
#define DT_DIR DT_DIR          //普通目录
  DT_BLK = 6,
#define DT_BLK DT_BLK          //块设备文件
  DT_REG = 8,
#define DT_REG DT_REG          //普通文件
  DT_LNK = 10,
#define DT_LNK DT_LNK          //快捷方式
  DT_SOCK = 12,
#define DT_SOCK DT_SOCK        //本地套接口
  DT_WHT = 14
#define DT_WHT DT_WHT          //whiteout
};
/*
whiteout 概念存在于联合文件系统(UnionFS)中,代表某一类占位符形态的特殊文件,
当用户文件夹与系统文件夹的共通部分联合到一个目录时(例如 bin 目录),
用户可删除归属于自己的某些系统文件副本,但归属于系统级的原件仍存留于同一个联合目录中,
此时系统将产生一份 whiteout 文件,表示该文件在当前用户目录中已删除,但系统目录中仍然保留。
*/

可以这些写一个类似于Linux中Tree类似功能的程序,而且貌似st_mode比dtype要判断的精确,误差更小。
stat  返回lnk所指向的文件信息
lstat 返回lnk的信息
其他都一样

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>


#define PATH_LENGTH 2000
#define FILE_MAXN 1000
#define NAME_LENGTH 255

struct OPT
{
  int Show_Hidden_File;
  int Show_File;
};
void Print_TAB(int Dep)
{
  for (int i = 1; i < Dep; i++)
    printf("|   ");
  printf("|-- ");
}
int Is_Hidden_File(const char * Str)
{
  if (Str[0] == '.')
    return 1;
  return 0;
}
//int Reg = 0, Chr = 0, Blk = 0, Sock = 0, Fifo = 0;

int Is_File(char * File_Path)
{
  struct stat S_Buf;
  if (lstat(File_Path, &S_Buf) < 0)
    return 1;
#if 0
  if (S_ISREG(S_Buf.st_mode))
    Reg++;
  if (S_ISCHR(S_Buf.st_mode))
    Chr++;
  if (S_ISBLK(S_Buf.st_mode))
    Blk++;
  if (S_ISSOCK(S_Buf.st_mode))
    Sock++;
  if (S_ISFIFO(S_Buf.st_mode))
    Fifo++;
#endif
    if (S_ISREG(S_Buf.st_mode) || S_ISCHR(S_Buf.st_mode) || S_ISBLK(S_Buf.st_mode) || S_ISFIFO(S_Buf.st_mode) || S_ISSOCK(S_Buf.st_mode))
    return 1;
  if (S_ISLNK(S_Buf.st_mode))
  {
    if (stat(File_Path, &S_Buf) < 0)
      return 1;
#if 0
    if (S_ISREG(S_Buf.st_mode))
      Reg++;
    if (S_ISCHR(S_Buf.st_mode))
      Chr++;
    if (S_ISBLK(S_Buf.st_mode))
      Blk++;
    if (S_ISSOCK(S_Buf.st_mode))
      Sock++;
    if (S_ISFIFO(S_Buf.st_mode))
      Fifo++;
#endif
    if (S_ISREG(S_Buf.st_mode) || S_ISCHR(S_Buf.st_mode) || S_ISBLK(S_Buf.st_mode) || S_ISFIFO(S_Buf.st_mode) || S_ISSOCK(S_Buf.st_mode))
      return 1;
  }
  return 0;
}

int Is_Dir(char * File_Path)
{
  struct stat S_Buf;
  stat(File_Path, &S_Buf);

  if (S_ISDIR(S_Buf.st_mode) || S_ISSOCK(S_Buf.st_mode))
    return 1;
  return 0;
}

int Is_Lnk(char * File_Path)
{
  struct stat S_Buf;
  lstat(File_Path, &S_Buf);
  //!! use lstat 
  if (S_ISLNK(S_Buf.st_mode))
    return 1;
  return 0;
}

int Cmp(const char * Str1, const char * Str2)
{
  for (int i = 0; Str1[i] && Str2[i]; i++)
  {
    if (Str1[i] > Str2[i])
      return 1;
    if (Str1[i] < Str2[i])
      return 0;
  }
  return 1;
}
/*
  用stat之后结果会准确很多,但是在/proc/self/task这个文件夹下面有个fd的文件夹和一个fdinfo的文件夹,
  里面分别有两个软连接,tree只会打开其中一个,我的两个无法打开
*/
void Tree_Maker(const char * Cur_Path, int Depth, OPT Opt, int * Dir_Num, int * File_Num)
{
  
  DIR            *dir;
  struct dirent  *node;

  if ((dir = opendir(Cur_Path)) == NULL)
    return;
  /*
  char File[FILE_MAXN][NAME_LENGTH];
  int Cnt = 0;
  while ((node = readdir(dir)) != NULL)
    strcpy(File[++Cnt], node->d_name);
  closedir(dir);
  
  for (int i = 1; i <= Cnt; i++)
    for (int j = i + 1; j <= Cnt; j++)
      if (Cmp(File[i], File[j]))
      {
        char Tmp[PATH_LENGTH];
        strcpy(Tmp, File[i]);
        strcpy(File[i], File[j]);
        strcpy(File[j], Tmp);
      }
  */

  while ((node = readdir(dir)) != NULL)
  {
    char File_Path[PATH_LENGTH];
    
    strcpy(File_Path, Cur_Path);
    strcat(File_Path, "/");
    strcat(File_Path, node->d_name);
    int Sym_File = Is_File(File_Path);
    if (strcmp(node->d_name, ".") == 0 || strcmp(node->d_name, "..") == 0)
      continue;
    //Ignore dot and dot-dot
    if (Is_Hidden_File(node->d_name) && !Opt.Show_Hidden_File)
      continue;
    if (Sym_File && !Opt.Show_File)
      continue;

    Print_TAB(Depth);
    printf("%s", node->d_name);

    if (Sym_File)
      (*File_Num)++;
    else
    {
      (*Dir_Num)++;
      //printf("!!!");
    }
    putchar('\n');
    if (Is_Dir(File_Path) && !Is_Lnk(File_Path))
      Tree_Maker(File_Path, Depth + 1, Opt, Dir_Num, File_Num);
  }
  closedir(dir);
}

int main(int argc, char* argv[])
{
  if (argc > 3)
  {
    puts("参数过多");
    return -1;
  }
  OPT Opt = { 0,1 };
  char Path[PATH_LENGTH] = ".";
  if (argc == 2)
  {
    if (argv[1][0] == '-')
    {
      if (strcmp(argv[1], "-a") == 0)
        Opt.Show_Hidden_File = 1;
      if (strcmp(argv[1], "-d") == 0)
        Opt.Show_File = 0;
    }
    else
      strcpy(Path, argv[1]);
  }
  if (argc == 3)
  {
    if (strcmp(argv[1], "-a") == 0)
      Opt.Show_Hidden_File = 1;
    if (strcmp(argv[1], "-d") == 0)
      Opt.Show_File = 0;
    strcpy(Path, argv[2]);
  }

  int Dir_Num = 0, File_Num = 0;
  puts(Path);
  Tree_Maker(Path, 1, Opt, &Dir_Num, &File_Num);
  printf("\n%d directories, %d files\n", Dir_Num, File_Num);
  //printf("Reg: %d Chr: %d Blk: %d Sock: %d Fifo: %d\n", Reg, Chr, Blk, Sock, Fifo);
  return 0;
}