1

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

libc手册指出您不应该DIR自己分配对象并让目录函数处理分配。

opendir()在获取目录流之后以及将其传递给之前,有什么方法可以操纵目录流readdir()

我基本上想重载 opendir()withLD_PRELOAD以返回一个操纵的目录流,由readdir().

4

3 回答 3

3

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

sortdir替换opendir, readdir, readdir64, andclosedir仅 197 行代码,你可以好好看看它。

于 2012-02-18T18:53:45.167 回答
2

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

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

于 2012-02-18T18:46:12.860 回答
1

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

重载opendir(),用 "real" 真正打开目录opendir(),立即用 "real" 读取所有目录条目,readdir()修改必要的内容,将修改后的版本存储在全局变量中并返回 unmodified 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 = .
于 2012-02-19T01:00:35.823 回答