2012-01-15 3 views
7

배경 디렉토리 항목을 나열하는 기존 응용 프로그램이 있습니다. strace는 단지 getdents를 호출하고 반환 된 순서대로 나열합니다. 인수없이 ls에 대한 호출과 동일한 순서로 표시하려고합니다. 이를 달성하기 위해 디렉토리 데이터를 업데이트 할 수 있습니까?getdents에 의해 주문 디렉토리 항목이 리턴되는 것을 결정하는 것은 무엇입니까?

FS가 ext4 일 경우 차이가 있습니다.

감사

+0

ext4라는 사실이 차이를 만듭니다. vfat의 경우 디렉토리를 다른 파일 시스템으로 옮긴 다음 올바른 순서로 파일을 다시 복사 할 수 있습니다. 나는 휴대용 mp3 선수를 위해 그것을 항상한다. BTW, 셸 glob 또한 'ls'와 같은 정렬합니다. 그래서 - cp -r music/media/my_player는 잘못된 순서를 줄 것이지만'mkdir/media/my_player/music; cp -v music/*/media/my_player/music' - 파일을 올바르게 복사합니다! 하지만이 트릭은 ext4에서 도움이되지 않습니다! (어쩌면 해시 테이블 디렉토리 또는 뭔가가 있습니다 ...) –

+0

글쎄, 난 여기에 같은 결론을 발견 : http://superuser.com/a/373621/269542 - 그래서 당신만을 정렬 할 수 있습니다. 해당 응용 프로그램의 소스가있는 경우 LD_PRELOAD를 사용하여 해킹하는 대신 정렬을 추가 할 수 있습니다. –

답변

6

당신이 정말로가 (난 당신이 사용할 수있는 소스 코드가없는 가정있는)이 프로그램의 동작을 변경하기로 결정하는 경우 opendirreaddir에 전화를 끼어로 교체 LD_PRELOAD을 사용할 수 있습니다 자신의 정렬 래퍼.

#define _GNU_SOURCE 1 
#include <stdio.h> 
#include <dirent.h> 
#include <dlfcn.h> 
#include <stdlib.h> 
#include <string.h> 

struct __dirstream 
{ 
    int __fd; 
    char *__data; 
    size_t __allocation; 
    size_t __offset; 
    size_t __size; 
    struct dirent __entry; 
}; 

typedef struct _dirent_list { 
    struct dirent *value; 
    struct _dirent_list *next; 
} dirent_list; 

typedef struct _my_DIR { 
    struct __dirstream orig; 
    dirent_list *first_entry; 
    int first_readdir; 
} my_DIR; 

DIR *opendir(const char *name) { 
    DIR *(*orig_opendir)(const char*) = dlsym(RTLD_NEXT, "opendir"); 
    DIR *dir = orig_opendir(name); 

    // save additional information along with the 
    // original DIR structure 
    my_DIR *my_dir = calloc(1, sizeof(*my_dir)); 
    my_dir->first_readdir = 1; 
    memcpy(my_dir, dir, sizeof(*dir)); 
    return (DIR*)my_dir; 
} 

struct dirent *readdir(DIR *dir) { 
    struct dirent *(*orig_readdir)(DIR*) = dlsym(RTLD_NEXT, "readdir"); 
    my_DIR *my_dir = (my_DIR*)dir; 
    dirent_list *item; 

    if (my_dir->first_readdir) { 
    struct dirent *entry; 
    while ((entry = orig_readdir(dir))) { 
     // exercise for the reader: 
     // implement insertion sort here 
     item = calloc(1, sizeof(*item)); 
     item->value = entry; 
     item->next = my_dir->first_entry; 
     my_dir->first_entry = item; 
    } 
    my_dir->first_readdir = 0; 
    } 

    if (!my_dir->first_entry) 
    return NULL; 

    item = my_dir->first_entry; 
    struct dirent *result = item->value; 
    my_dir->first_entry = item->next; 
    free(item); 

    return result; 
} 

그것은 opendir 무시하고 readdir는 역순으로 항목을 반환하는 (너무 정렬이 적응할 수) : 같은 후크 모양을 수있는 방법을 예는이 다음이다.

$ gcc -Wall -shared -fPIC -o libhookdir.so hookdir.c -ldl 
$ ./test 
.. 
test 
. 
hookdir.c 
libhookdir.so 
test.c 
$ LD_PRELOAD=./libhookdir.so ./test 
test.c 
libhookdir.so 
hookdir.c 
. 
test 
.. 

하 석 : 이것은 당신이 그들이받은 단순히 순서대로 디렉토리 항목을 나열하는 프로그램 test와 함께 사용하는 방법입니다! 이 작동합니다. 방금 libc 함수를 연결했습니다.

+0

제안 해 주셔서 감사합니다. 방금 여기에서 코드를 사용하여 동일한 작업을 수행했습니다. [LD_PRELOAD 라이브러리를 사용하여 디렉터리 통과 속도를 높입니다.] (http://www.redhat.com/archives/ext3-users/2008-May/msg00006.html) . 지금 당장은 해결책이 될 것 같습니다만, 원래 getdents가 사용하는 알고리즘이 무엇인지 궁금합니다. – Barney

1

아니, 당신은 파일 시스템의 메타 데이터 ls(1) 디렉터리 entires에 적용되는 정렬 순서와 같은 순서로 getdents(2) 반환 디렉토리 entires을 가지고 조작 할 수있는 방법이 없습니다.

ls(1)과 동일한 알고리즘을 사용하여 항목을 정렬하도록 프로그램을 수정할 수 있습니다. N 항목이있는 디렉토리를 정렬하려면 적어도 O (N) 메모리와 O (NLog N) 시간이 필요합니다. ls(1)과 같은 방식으로 정렬하려면 구현, 메모리 및 시간의 가치가 있는지 결정해야합니다.

관련 문제