2012-01-15 8 views
7

Lo sfondo è che ho un'applicazione esistente che elenca le voci della directory; strace rivela che chiama solo i getdent e li elenca nell'ordine restituito. Mi piacerebbe che fossero visualizzati nello stesso ordine di una chiamata a ls senza argomenti. È possibile aggiornare i dati della directory in qualche modo per raggiungere questo obiettivo?Cosa determina che le voci della directory degli ordini vengono restituite da getdents?

FS è ext4, se questo fa alcuna differenza.

Grazie

+0

Il fatto che sia ext4 sicuramente fa la differenza. Per vfat è sufficiente spostare la directory su un altro file system, quindi copiare i file nuovamente nell'ordine corretto. Lo faccio sempre per i lettori mp3 portatili. A proposito, shell glob ordina anche come 'ls'. Quindi - 'cp -r music/media/my_player' mi darà l'ordine sbagliato, ma' mkdir/media/my_player/music; cp -v music/*/media/my_player/music' - copia correttamente i file! Ma questo trucco non aiuta su ext4! (forse ha directory hashtable o qualcosa del genere ...) –

+0

Bene, ho trovato la stessa conclusione qui: http://superuser.com/a/373621/269542 - quindi puoi solo ordinare. Se si dispone di fonti di tale applicazione, è possibile aggiungere l'ordinamento lì, invece di hacking con LD_PRELOAD. –

risposta

6

Se davvero sono decisi a cambiare il comportamento di questo programma (di cui suppongo che non si ha il codice sorgente disponibile), è possibile utilizzare LD_PRELOAD per agganciare la chiamata a opendir e readdir e sostituirlo con la vostra proprio, ordinamento wrapper. Un esempio di come un tale gancio potrebbe apparire come è la seguente:

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

Esso sovrascrive opendir e readdir per restituire le voci in ordine inverso (si può adattare questo per l'ordinamento troppo). Questo è come lo si utilizza con un programma test che elenca semplicemente le voci di directory nell'ordine in cui vengono ricevuti:

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

Hah! Questo funziona. Abbiamo appena collegato una funzione di libc.

+0

Grazie per il suggerimento - Ho appena raggiunto la stessa cosa usando il codice da qui: [libreria LD_PRELOAD per accelerare l'attraversamento delle directory] (http://www.redhat.com/archives/ext3-users/2008-May/msg00006.html) . Sembra che per ora questa sarà una soluzione, anche se sono ancora curioso di sapere quale algoritmo usi i getdent originali. – Barney

1

No, non c'è modo è possibile manipolare i metadati del file system di avere getdents(2) entires directory ritorno nello stesso ordine come l'ordinamento che ls(1) vale per le entires directory.

È sempre possibile modificare il programma per ordinare le voci utilizzando gli stessi algoritmi forniti da ls(1), sebbene ciò richieda almeno la memoria O (N) e il tempo O (N Log N) per l'ordinamento di una directory con N voci. Dovrai decidere se vale l'implementazione, la memoria e l'ora, per ordinare allo stesso modo di ls(1).

Problemi correlati