What determines the order directory entries are returned by getdents?

前端 未结 2 2054
慢半拍i
慢半拍i 2021-02-15 13:31

Background is I have an existing application which lists directory entries; strace reveals it just calls getdents and lists them in the order returned. I would like them display

2条回答
  •  暗喜
    暗喜 (楼主)
    2021-02-15 14:21

    If you really are determined to change this program's behaviour (of which I assume that you don't have the source code available), you can use LD_PRELOAD to hook the call to opendir and readdir and replace it with your own, sorting wrapper. An example how such a hook could look like is the following:

    #define _GNU_SOURCE 1
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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;
    }
    

    It overrides opendir and readdir to return the entries in reverse order (you can adapt this for sorting too). This is how you use it with a program test that simply lists the directory entries in the order they are received:

    $ 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! This works. We just hooked a libc function.

提交回复
热议问题