GETDENTS - Linux手册页

时间:2019-08-20 17:58:47  来源:igfitidea点击:

Linux程序员手册 第2部分
更新日期: 2020-06-09

名称

getdents,getdents64-获取目录条目

语法

int getdents(unsigned int fd, struct linux_dirent *dirp,
             unsigned int count);
int getdents64(unsigned int fd, struct linux_dirent64 *dirp,
             unsigned int count);

注意:getdents()没有glibc包装器;请参阅注释。

说明

这些不是您感兴趣的接口。请查看readdir(3)以了解符合POSIX的C库接口。本页记录了裸内核系统调用接口。

getdents()

系统调用getdents()从打开文件描述符fd所引用的目录中读取几个linux_dirent结构到dirp所指向的缓冲区中。参数count指定该缓冲区的大小。

linux_dirent结构声明如下:

struct linux_dirent {
    unsigned long  d_ino;     /* Inode number */
    unsigned long  d_off;     /* Offset to next linux_dirent */
    unsigned short d_reclen;  /* Length of this linux_dirent */
    char           d_name[];  /* Filename (null-terminated) */
                      /* length is actually (d_reclen - 2 -
                         offsetof(struct linux_dirent, d_name)) */
    /*
    char           pad;       // Zero padding byte
    char           d_type;    // File type (only since Linux
                              // 2.6.4); offset is (d_reclen - 1)
    */
}

d_ino是一个索引节点号。 d_off是从目录开始到下一个linux_dirent的距离。 d_reclen是整个linux_dirent的大小。 d_name是一个以空值结尾的文件名。

d_type是结构末尾的字节,指示文件类型。它包含以下值之一(在中定义):

DT_BLK
这是一个块设备。
DT_CHR
这是字符设备。
DT_DIR
这是一个目录。
DT_FIFO
这是一个命名管道(FIFO)。
DT_LNK
这是一个符号链接。
DT_REG
这是一个常规文件。
DT_SOCK
这是UNIX域套接字。
DT_UNKNOWN
文件类型未知。

从Linux 2.6.4开始实现d_type字段。它占用的空间以前是linux_dirent结构中的零填充填充字节。因此,在2.6.3及以下版本的内核上,尝试访问此字段始终提供值0(DT_UNKNOWN)。

当前,只有某些文件系统(其中包括Btrfs,ext2,ext3和ext4)完全支持返回d_type中的文件类型。所有应用程序都必须正确处理DT_UNKNOWN的返回。

getdents64()

原始的Linux getdents()系统调用无法处理大型文件系统和大型文件偏移量。因此,Linux 2.4添加了getdents64(),其中d_ino和d_off字段的类型更大。另外,getdents64()支持显式的d_type字段。

getdents64()系统调用类似于getdents(),不同之处在于它的第二个参数是指向包含以下类型结构的缓冲区的指针:

struct linux_dirent64 {
    ino64_t        d_ino;    /* 64-bit inode number */
    off64_t        d_off;    /* 64-bit offset to next structure */
    unsigned short d_reclen; /* Size of this dirent */
    unsigned char  d_type;   /* File type */
    char           d_name[]; /* Filename (null-terminated) */
};

返回值

成功后,将返回读取的字节数。在目录末尾,返回0。如果出错,则返回-1,并正确设置errno。

错误说明

EBADF
无效的文件描述符fd。
EFAULT
参数指向调用过程的地址空间之外。
EINVAL
结果缓冲区太小。
ENOENT
没有这样的目录。
ENOTDIR
文件描述符不引用目录。

遵循规范

SVr4。

备注

在glibc 2.30中添加了对getdents64()的库支持。没有用于getdents()的glibc包装器。调用getdents()(或在较早的glibc版本上调用getdents64())需要使用syscall(2)。在这种情况下,您将需要自己定义linux_dirent或linux_dirent64结构。

可能您可能想使用readdir(3)而不是这些系统调用。

这些调用将取代readdir(2)。

示例

下面的程序演示了getdents()的用法。以下输出显示了我们在ext2目录上运行该程序时看到的示例:

$ ./a.out /testfs/
--------------- nread=120 ---------------
inode#    file type  d_reclen  d_off   d_name
       2  directory    16         12  .
       2  directory    16         24  ..
      11  directory    24         44  lost+found
      12  regular      16         56  a
  228929  directory    16         68  sub
   16353  directory    16         80  sub2
  130817  directory    16       4096  sub3

Program source

#define _GNU_SOURCE
#include <dirent.h>     /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

struct linux_dirent {
    unsigned long  d_ino;
    off_t          d_off;
    unsigned short d_reclen;
    char           d_name[];
};

#define BUF_SIZE 1024

int
main(int argc, char *argv[])
{
    int fd, nread;
    char buf[BUF_SIZE];
    struct linux_dirent *d;
    int bpos;
    char d_type;

    fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
    if (fd == -1)
        handle_error("open");

    for ( ; ; ) {
        nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
        if (nread == -1)
            handle_error("getdents");

        if (nread == 0)
            break;

        printf("--------------- nread=%d ---------------\n", nread);
        printf("inode#    file type  d_reclen  d_off   d_name\n");
        for (bpos = 0; bpos < nread;) {
            d = (struct linux_dirent *) (buf + bpos);
            printf("%8ld  ", d->d_ino);
            d_type = *(buf + bpos + d->d_reclen - 1);
            printf("%-10s ", (d_type == DT_REG) ?  "regular" :
                             (d_type == DT_DIR) ?  "directory" :
                             (d_type == DT_FIFO) ? "FIFO" :
                             (d_type == DT_SOCK) ? "socket" :
                             (d_type == DT_LNK) ?  "symlink" :
                             (d_type == DT_BLK) ?  "block dev" :
                             (d_type == DT_CHR) ?  "char dev" : "???");
            printf("%4d %10lld  %s\n", d->d_reclen,
                    (long long) d->d_off, d->d_name);
            bpos += d->d_reclen;
        }
    }

    exit(EXIT_SUCCESS);
}

另外参见

readdir(2),readdir(3),inode(7)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/