linux 无法读取K&R2中所示的“结构直接”

klsxnrf1  于 2022-11-22  发布在  Linux
关注(0)|答案(1)|浏览(80)

实现自己的readdir的示例如K&R2所示:

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

#define NAME_MAX 14 /*longest filenames component; system-dependent */

#ifndef DIRSIZ
#define DIRSIZ 14
#endif

typedef struct {
    long ino; /*inode number */
    char name[NAME_MAX+1]; /*name + '\0' terminator */
} my_dirent;

typedef struct {
    int fd; /* file descriptor for directory */
    my_dirent d; /*the directory entry */
} MY_DIR;

/*
 * opendir: open a directory for readdir calls 
 */
MY_DIR *my_opendir(char *dirname)
{
    int fd;
    struct stat stbuf;
    MY_DIR *dp;

    if((fd = open(dirname, O_RDONLY, 0)) == -1
        || fstat(fd, &stbuf) == -1
        || (stbuf.st_mode & S_IFMT) != S_IFDIR
        || (dp = malloc(sizeof(MY_DIR))) == NULL) 
        return NULL;
    dp->fd = fd;
    return dp;
}

/*
 * closedir: close directory opened by opendir 
 */
void my_closedir(MY_DIR *dp)
{
    if(dp) {
        close(dp->fd);
        free(dp);
    }
}

#include <sys/dir.h>
/*
 * readdir: read directory entries in sequence 
 */
my_dirent *my_readdir(MY_DIR *dp)
{
    struct direct dirbuf; /* local directory structure */
    static my_dirent d; /* portable structure */

    // HERE BELOW: the body of while loop never executes (I have no idea why) so NULL is returned and causes segfault when dereferencing in printf
    while(read(dp->fd, (char*) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf)) {
        if(dirbuf.d_ino == 0) /* slot not in use */
            continue;
        d.ino = dirbuf.d_ino;
        strncpy(d.name, dirbuf.d_name, DIRSIZ);
        d.name[DIRSIZ] = '\0';
        return &d;
    }
    return NULL;
}

int main()
{
    MY_DIR *dp = my_opendir(".");
    my_dirent *dent = my_readdir(dp);
    printf("directory info:\nname: %s; fd: %d; ino: %ld\n", dent->name, dp->fd, dent->ino);
}

我做了调试,所以我知道为什么。

while(read(dp->fd, (char*) &dirbuf, sizeof(dirbuf)) == sizeof(dirbuf)) {
...
}

Is失败,所以函数返回NULL,在printf中被取消引用。所以问题是如何读取该结构。

#define direct  dirent

因此该结构实际上是dirent,其具有以下定义dirent.h

struct dirent
  {
#ifndef __USE_FILE_OFFSET64
    __ino_t d_ino;
    __off_t d_off;
#else
    __ino64_t d_ino;
    __off64_t d_off;
#endif
    unsigned short int d_reclen;
    unsigned char d_type;
    char d_name[256];       /* We must not include limits.h! */
  };

但是这并不重要,因为在read(2)中,我使用的是sizeof,它将获得正确的大小。那么为什么while头文件会失败呢?

6uxekuva

6uxekuva1#

K&R 2是35年前写的,除了讨论ANSI C aka C89,其中大部分(但不是全部)仍然适用于现代C,K&R还讨论了许多没有标准化但特定于UNIX的特性,或者更确切地说,特定于当时的UNIX。
在以前,访问目录条目的方式是:通过打开()像文件一样读取目录,并以某种指定的格式从其中阅读数据。K&R自己说,他们使用的格式是特定于Version 7和System V UNIX的,因此根本没有理由期望它能与UNIX的其他版本一起工作,更不用说与完全独立发展的Linux一起工作了。事实上,使用read()来获取目录项的整个思想现在已经过时,并通过readdirgetdents等更标准化的API将这些数据提供给用户空间。
K&R是一部经典之作,有很多东西可以从中学到,但它的时代确实表明了这一点,当他们所说的一些话不适用于当今时,你不会感到惊讶。
请注意,当系统调用失败时,确定原因的第一步应该是检查errno的值,可能使用perror()。如果是这样,您会发现它是EISDIR "Is a directory"。参考read(2)手册页,指出当“fd引用目录”时会出现此错误,这意味着通常不允许从目录中获取read()。这至少可以帮助您将注意力从“如何读取该结构体”转移到“既然我不能读取该结构体,那么应该通过什么方法来获取目录项呢?”

相关问题