该函数opendir()
返回一个指向目录流的指针DIR *
,它显然是一种不透明的数据类型。实现是隐藏的。
libc手册指出您不应该DIR
自己分配对象并让目录函数处理分配。
opendir()
在获取目录流之后以及将其传递给之前,有什么方法可以操纵目录流readdir()
?
我基本上想重载 opendir()
withLD_PRELOAD
以返回一个操纵的目录流,由readdir()
.
在将目录条目提供给程序之前查看它的作用可能会有所帮助,LD_PRELOAD
sortdir
尽管您可能想要做的可能不是排序。
sortdir
替换opendir
, readdir
, readdir64
, andclosedir
仅 197 行代码,你可以好好看看它。
我不相信这是可能的,或者至少以任何便携式方式都不可能。正如你所说,DIR*
类型是一个不透明的指针。该DIR
文件是在您无权访问的文件中以特定于实现的方式定义的。
为了操纵返回的DIR
值,您必须创建一个struct
包含操纵值的类似结构。实现可以在DIR
没有警告的情况下随意更改或更改定义(毕竟它是不透明的)。因此,您添加的任何实现充其量都是脆弱的。
如果我猜对了,您想要操作目录条目,例如更改文件名或添加虚拟条目。你可以这样做。
重载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 = .