函数opendir()
返回指向目录流DIR *
的指针,这显然是一种不透明的数据类型。实施是隐藏的。
libc manual表示您不应自己分配DIR
对象并让目录函数处理分配。
在使用opendir()
获取目录流并将其传递给例如readdir()
之前是否有办法操纵目录流?
我基本上希望用opendir()
重载LD_PRELOAD
来返回由readdir()
使用的受控目录流。
答案 0 :(得分:3)
可能有助于查看LD_PRELOAD
sortdir
在将目录条目提供给程序之前对其进行排序的功能,尽管您可能想要做的事情可能不是排序。
sortdir
取代opendir
,readdir
,readdir64
和closedir
,只有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 = .