【问题标题】:Can I manipulate a directory stream obtained with opendir()?我可以操作使用 opendir() 获得的目录流吗?
【发布时间】:2012-02-18 18:38:38
【问题描述】:

函数opendir()返回一个指向目录流DIR *的指针,这显然是一个不透明的数据类型。实现是隐藏的。

libc manual 声明您不应该自己分配 DIR 对象并让目录函数处理分配。

在使用opendir() 获取目录流之后并将其传递给例如readdir() 之前,是否有任何方法可以操作目录流?

我基本上想用LD_PRELOAD 重载opendir() 以返回readdir() 使用的操纵目录流。

【问题讨论】:

  • 也许你可以劫持readdir并让它返回你想要的?

标签: c linux opendir


【解决方案1】:

查看LD_PRELOAD sortdir 的作用可能会有所帮助,因为它会在将目录条目提供给程序之前对其进行排序,尽管您可能想要做的可能不是排序。

sortdir 替换了 opendirreaddirreaddir64closedir,并且只有 197 行代码,你可以好好看看它。

【讨论】:

    【解决方案2】:

    我不相信这是可能的,或者至少在任何便携式方式中都不可能。正如您所说,DIR* 类型是一个不透明的指针。 DIR 文件以特定于实现的方式在您无权访问的文件中定义。

    为了操作返回的DIR 值,您必须创建一个包含操作值的类似结构的struct。实现可以随意改变DIR 的定义或在没有警告的情况下更改它(毕竟它是不透明的)。因此,您添加的任何实现充其量都是脆弱的。

    【讨论】:

    • 确实,这在任何便携方式中都是不可能的,即任何解决方案都将与特定的 opendir/readdir 实现固有地绑定。
    【解决方案3】:

    如果我猜对了,您想操作目录条目,例如更改文件名或添加虚拟条目。你可以这样做。

    重载opendir(),在其中真正打开带有“real”opendir()的目录,立即读取所有目录条目,带有“real”readdir(),修改必要的内容,将修改后的版本存储在全局变量中并返回未修改DIR *。然后在重载的readdir() 中,您将传递的DIR * 视为您自己的不透明值(例如,地图中的键)并简单地按顺序返回先前准备好的条目。

    这是一个令人讨厌的概念证明(讨厌,因为我跳过了诸如错误检查、资源关闭、内存释放、线程安全等无聊的部分):

    opendir_wrap.cpp -> opendir_wrap.so:

    #include <sys/types.h>
    #include <dirent.h>
    #include <dlfcn.h>
    #include <stdio.h>
    #include <map>
    #include <list>
    
    extern "C" {
    
    static std::map<DIR *, std::list<struct dirent*> > MAP;
    
    typedef DIR *(*OPEN_T)(const char *name);
    typedef struct dirent *(*READ_T)(DIR *dirp);
    static OPEN_T real_opendir = NULL;
    static READ_T real_readdir = NULL;
    
    DIR *opendir(const char *name)
    {
        void *handle = dlopen("/lib/libc.so.6", RTLD_LAZY);
        if (!real_opendir) real_opendir = (OPEN_T) dlsym(handle, "opendir");
        if (!real_readdir) real_readdir = (READ_T) dlsym(handle, "readdir");
    
        DIR *dirp = real_opendir(name);
        struct dirent *entry = NULL;
        while (entry = real_readdir(dirp))
        {
            MAP[dirp].push_back(entry);
        }
        MAP[dirp].push_back(NULL);
    
        // your modifications here
        struct dirent *joke = new struct dirent;
        sprintf(joke->d_name, "JOKE!");
        MAP[dirp].push_front(joke);
    
        return dirp;
    }
    
    struct dirent *readdir(DIR *dirp)
    {
        struct dirent *entry = MAP[dirp].front();
        MAP[dirp].pop_front();
        return entry;
    }
    
    } // extern "C"
    

    opedir_use.c -> opendir_use:

    #include <sys/types.h>
    #include <dirent.h>
    #include <dlfcn.h>
    #include <stdio.h>
    
    int main()
    {
        struct dirent *entry = NULL;
        DIR *dirp = opendir(".");
        printf("dirp = %p\n", dirp);
        while (entry = readdir(dirp))
        {
            printf("entry->d_name = %s\n", entry->d_name);
        }
    }
    

    现在编译:

    $ gcc -fpic -shared -ldl -lstdc++ -o ./opendir_wrap.so ./opendir_wrap.cpp
    $ gcc opendir_use.c -o opendir_use
    

    正常运行:

    $ ./opendir_use 
    dirp = 0x9fd3008
    entry->d_name = opendir_wrap.so
    entry->d_name = opendir_use
    entry->d_name = opendir_use.c
    entry->d_name = opendir_wrap.cpp
    entry->d_name = ..
    entry->d_name = .
    

    使用包装器运行:

    $ LD_PRELOAD=`pwd`/opendir_wrap.so ./opendir_use
    dirp = 0x95374b8
    entry->d_name = JOKE!
    entry->d_name = opendir_wrap.so
    entry->d_name = opendir_use
    entry->d_name = opendir_use.c
    entry->d_name = opendir_wrap.cpp
    entry->d_name = ..
    entry->d_name = .
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-20
      • 2014-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-29
      相关资源
      最近更新 更多