2012-01-15 9 views
7

Antecedentes es Tengo una aplicación existente que enumera entradas de directorio; strace revela que solo llama a getdents y los enumera en el orden en que se devuelve. Me gustaría que se muestren en el mismo orden que una llamada a ls sin argumentos. ¿Es posible actualizar los datos del directorio de alguna manera para lograr esto?¿Qué determina las entradas de directorio de pedidos devueltas por getdents?

FS es ext4, si eso hace alguna diferencia.

Gracias

+0

El hecho de que es ext4 seguro hace la diferencia. Para vfat, puede mover el directorio a otro sistema de archivos y luego copiar los archivos nuevamente en el orden correcto. Lo hago todo el tiempo para reproductores de mp3 portátiles. Por cierto, Shell Glob también tipo 'ls'. Entonces, 'cp -r music/media/my_player' me dará el orden incorrecto, pero' mkdir/media/my_player/music; cp -v music/*/media/my_player/music' - ¡copia los archivos correctamente! ¡Pero este truco no ayuda en ext4! (Tal vez tiene directorios hashtable o algo así ...) –

+0

Bueno, he encontrado la misma conclusión aquí: http://superuser.com/a/373621/269542 - por lo que solo puede ordenar. Si tiene las fuentes de dicha aplicación, puede agregar la ordenación allí, en lugar de piratear con LD_PRELOAD. –

Respuesta

6

Si realmente está decidido a cambiar el comportamiento de este programa (de la que supongo que usted no tiene el código fuente disponible), puede utilizar LD_PRELOAD para conectar la llamada a opendir y readdir y reemplazarlo con su propio, sorter de clasificación. Un ejemplo de cómo un gancho de este tipo podría ser similar es el siguiente:

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

Se anula opendir y readdir para regresar las entradas en orden inverso (se puede adaptar esta para clasificar también). Esta es la forma en que lo utilice con un programa test que se limita a enumerar las entradas de directorio en el orden en que se reciben:

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

Ja! Esto funciona. Acabamos de enganchar una función de libc.

+0

Gracias por la sugerencia. Acabo de lograr lo mismo usando el código de aquí: [Biblioteca LD_PRELOAD para acelerar el recorrido del directorio] (http://www.redhat.com/archives/ext3-users/2008-May/msg00006.html) . Parece que esta será una solución por ahora, aunque todavía tengo curiosidad sobre qué algoritmo usan los getdents originales. – Barney

1

No, no hay ninguna manera se puede manipular los metadatos del sistema de archivos para tener getdents(2) entires directorio de retorno en el mismo orden que el orden de clasificación que se aplica a los ls(1) entires de directorio.

Siempre puede modificar su programa para ordenar entradas utilizando los mismos algoritmos que proporciona ls(1), aunque esto requiere al menos O (N) memoria y O (N Log N) tiempo para ordenar un directorio con N entradas. Deberá decidir si vale la implementación, la memoria y el tiempo para ordenar de la misma manera que ls(1).

Cuestiones relacionadas