我可以操作使用opendir()获得的目录流吗?

时间:2012-02-18 18:38:39

标签: c linux opendir

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

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

在使用opendir()获取目录流并将其传递给例如readdir()之前是否有办法操纵目录流?

我基本上希望用opendir()重载LD_PRELOAD来返回由readdir()使用的受控目录流。

3 个答案:

答案 0 :(得分:3)

可能有助于查看LD_PRELOAD sortdir在将目录条目提供给程序之前对其进行排序的功能,尽管您可能想要做的事情可能不是排序。

sortdir取代opendirreaddirreaddir64closedir,只有197行代码,您可以很好地查看它

答案 1 :(得分:2)

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

为了操纵返回的DIR值,您必须创建一个包含操纵值的类似结构的struct。实现可以自由地改变DIR的定义或在没有警告的情况下进行更改(毕竟它是不透明的)。所以你添加的任何实现都是脆弱的。

答案 2 :(得分:1)

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

重载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 - &gt; 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 = .