1

この関数opendir()はディレクトリ stream へのポインタを返しますがDIR *、これは明らかに不透明なデータ型です。実装は隠されています。

libcのマニュアルには、自分でオブジェクトを割り当てるべきではなくDIR、ディレクトリ関数に割り当てを処理させるべきであると記載されています。

ディレクトリストリームを取得した後opendir()、たとえばに渡す前にディレクトリストリームを操作する方法はありますreaddir()か?

私は基本的に 、 で使用される操作されたディレクトリ ストリームを返すために をオーバーロードopendir()したいと考えています。LD_PRELOADreaddir()

4

3 に答える 3

3

プログラムにディレクトリ エントリを渡す前に、 がディレクトリ エントリを並べ替えるときに何をするかを調べると役立つLD_PRELOAD sortdir 場合がありますが、やりたいことは並べ替え以外のことかもしれません。

sortdiropendirreaddirreaddir64、およびを置き換えるのclosedirはわずか 197 行のコードなので、これを見るだけでも十分役に立ちます。

于 2012-02-18T18:53:45.167 に答える
2

私はこれが可能であるとは思わない、あるいは少なくともどんな種類の携帯型の方法でも不可能だと思う。あなたが言ったように、DIR*タイプは不透明なポインタです。ファイルは、DIRアクセスできないファイルで実装固有の方法で定義されます。

戻り値を操作するには、操作された値を含む同様の構造をDIR作成する必要があります。struct実装は、定義を自由に変更しDIRたり、警告なしに変更したりできます(結局のところ不透明です)。したがって、追加した実装は、せいぜい壊れやすいものになります。

于 2012-02-18T18:46:12.860 に答える
1

正しければ、ディレクトリエントリを操作します。たとえば、ファイル名を変更したり、ダミーエントリを追加したりします。あなたはそのようにそれをすることができます。

オーバーロードopendir()、その中で実際に「real」でディレクトリを開き、「real」opendir()ですべてのディレクトリエントリをすぐに読み取り、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 = .
于 2012-02-19T01:00:35.823 に答える