如何解决如何使getdents的行为类似于目录上的read[K&R第8.6节]
我是编程和C语言的新手,目前正在K&R工作。如果这不是表征问题的最简洁方式,请提前道歉。
对于上下文,在K&R的8.6节(不是练习,而是实际章节)中,他们实现了功能fsize(),该功能以递归方式打印目录及其子目录中文件的大小。本书中的代码使用syscall read()来实现readdir()的基本版本,该版本将返回指向目录中 next 条目的指针。
直到K&R的这一部分,所有源代码都可以在我的机器上正常工作,但是,本章中的代码依赖于在目录上使用read()函数来获取其内容,根据我在此处找到的源代码[1],不适用于Linux和许多现代系统。
但是,存在一个syscall getdents(),它似乎在做大致相同的事情[2]。因此,作为练习,我尝试重新实现readdir()并遇到以下问题:
-
目录上的
- read()似乎事先知道每个条目的大小,因此它能够一次返回一个条目,并让read()每次处理“记住”下一个条目的位置的问题被称为。 另一方面,
- getdents()不预先知道每个条目的大小,因此我必须先读取整个缓冲区,然后使用成员d_reclen在readdir()中循环遍历(我从例如,在man getdents的底部),这意味着我的readdir()函数必须处理每次调用readdir()时“记住”流中下一个条目的位置的问题。
所以我的问题如下:
- 我是否正确地理解,不能使getdents()表现得像read()那样,就意味着它只能一次读取一个条目并处理“记住下一个位置”?
- 如果确实getdents()不能像read()那样运行,那么实现“记住位置”的最佳方法是什么,特别是如果需要在多个子目录上多次调用getdents()的时候?我已经展示了我下面尝试的内容的摘录:使用系统分配的文件描述符作为索引数组中getdents()结果的一种方式。但是,考虑到opendir()和closedir()的实现方式,这种尝试似乎失败了—一旦调用closedir()并在下一个子目录中调用opendir(),系统将重新分配文件描述符(并且该信息对readdir不可用) ())。
最后一点:我希望我的read_dir()实现与K&R中的readdir()完全一样。意味着我不必更改任何其他功能或结构即可使其工作。
// NTD: _direct's structure needs to match how system implements directory
// entries. After reading from file descriptor into _direct,we then
// copy only the relevant elements (d_ino and d_name) to Dirent
struct _direct { // directory entry
long d_ino; // inode number
off_t d_off; // Not included in K&R
unsigned short d_reclen; // Not included in K&R
char d_name[]; // long name does not have '\0'
};
#define BUFSIZE 4096 // Size of buffer when reading from getdents()
#define MAXFILES 1024 // Max files that read_dir() can open
struct _streamdents {
int pos;
int nread;
char *buf;
};
// read_dir: read directory entries in sequence
Dirent *read_dir(_dir *dp)
{
struct _direct *dirbuf; // local directory structure
static Dirent d; // return: portable structure
static struct _streamdents *readdents[MAXFILES];
if (dp->fd > MAXFILES - 1) {
printf("Error in read_dir: Cannot continue reading,too many directories\n");
return NULL;
}
// Check if directory has already been read; if not,create stream.
// Important if fxn is called for a sub-directory and then needs
// to return to a parent directory and continue reading.
if (readdents[dp->fd] == NULL) {
char *buf = malloc(BUFSIZE);
int nread = syscall(SYS_getdents,dp->fd,buf,BUFSIZE);
int pos = 0;
struct _streamdents *newdent = malloc(sizeof(struct _streamdents));
newdent->buf = buf;
newdent->pos = pos;
newdent->nread = nread;
readdents[dp->fd] = newdent;
}
struct _streamdents *curdent = readdents[dp->fd];
int pos = curdent->pos;
int nread = curdent->nread;
char *buf = curdent->buf;
while (pos < nread) {
dirbuf = (struct _direct *) (buf + pos);
if (dirbuf->d_ino == 0) // slot not in use
continue;
d.ino = dirbuf->d_ino;
strncpy(d.d_name,dirbuf->d_name,DIRSIZ);
curdent->pos += dirbuf->d_reclen;
return &d;
}
if (nread == -1) {
printf("Error in getdents(): %s\n",strerror(errno));
}
return NULL;
}
谢谢
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。