如何使getdents的行为类似于目录上的read[K&R第8.6节]

如何解决如何使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()时“记住”流中下一个条目的位置的问题。

所以我的问题如下:

  1. 我是否正确地理解,不能使getdents()表现得像read()那样,就意味着它只能一次读取一个条目并处理“记住下一个位置”?
  2. 如果确实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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-