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

发布于 2025-01-06 17:32:43 字数 390 浏览 1 评论 0原文

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

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

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

我基本上想使用 LD_PRELOAD 重载 opendir() 来返回受操作的目录流,该目录流由 readdir() 使用。

The function opendir() returns a pointer to a directory stream DIR *, which apparently is an opaque data type. The implementation is hidden.

The libc manual states that you should not allocate a DIR object yourself and let the directory functions handle the allocation.

Is there any way to manipulate a directory stream after obtaining it with opendir() and before passing it to, for example, readdir()?

I basically want to overload opendir() with LD_PRELOAD to return a manipulated directory stream, which is used by readdir().

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

在梵高的星空下 2025-01-13 17:32:43

查看 LD_PRELOAD sortdir 的作用是在将目录条目提供给程序之前对其进行排序,尽管您可能想做的可能不是排序。

sortdir 取代了 opendirreaddirreaddir64linedir 并且只有 197 行代码,看看它会对你很有帮助。

It might help to look at what the LD_PRELOAD sortdir does as it sorts the directory entries before giving them to the program although what you might want to do might be something other than sorting.

sortdir replaces opendir, readdir, readdir64, and closedir and being only 197 lines of code, it would serve you well to look at it.

短暂陪伴 2025-01-13 17:32:43

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

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

I don't believe this is possible, or at least not possible in any sort of portable fashion. As you said the DIR* type is an opaque pointer. The DIR file is defined in an implementation specific fashion in a file you don't have access to.

In order to manipulate the returned DIR value you'd have to create a struct of similar structure which contains the manipulated values. Implementations are free to vary the definition of DIR or change it without warning (it is opaque after all). So any implementation you added would be fragile at best.

剩余の解释 2025-01-13 17:32:43

如果我的理解正确,您想要操作目录条目,例如更改文件名或添加虚拟条目。你可以这样做。

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

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

op​​endir_wrap.cpp -> opendir_wrap.so:opedir_use.c

#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"

-> 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 = .

If I get you right you want to manipulate the directory entries, e.g. change file names or add dummy entries. You can do it like that.

Overload opendir(), within it really open the directory with "real" opendir(), immediately read all directory entries, with "real" readdir(), modify what's necessary, store the modified version in a global variable and return unmodified DIR *. Then in the overloaded readdir() you treat passed DIR * as your own opaque value (e.g. key in a map) and simply sequentially return previously prepared entries.

Here's a nasty proof of concept (nasty because I skipped the boring part like error checking, resource closing, memory freeing, thread safety, etc.):

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);
    }
}

Now compile:

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

Run normally:

$ ./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 = .

Run with the wrapper:

$ 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 = .
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文