Если я правильно понял, вы хотите манипулировать записями каталога, например, изменять имена файлов или добавлять фиктивные записи.Вы можете сделать это следующим образом.
Перегрузить 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 -> 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 = .