问题描述
我是编程和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 (将#修改为@)