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