什么决定了getdents返回的订单目录条目?

时间:2012-01-15 00:24:41

标签: linux system-calls

背景是我有一个列出目录条目的现有应用程序; strace显示它只是调用getdents并按返回的顺序列出它们。我希望它们以与没有参数的ls调用相同的顺序显示。是否有可能以某种方式更新目录数据来实现这一目标?

FS是ext4,如果这有任何区别的话。

由于

2 个答案:

答案 0 :(得分:8)

如果确实决定更改此程序的行为(我假设您没有可用的源代码),则可以使用LD_PRELOAD挂钩调用opendirreaddir并将其替换为您自己的排序包装器。这样一个钩子的样子如下:

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

它会覆盖opendirreaddir以相反的顺序返回条目(您也可以将其调整为排序)。这就是你如何使用程序test,它只是按照收到的顺序列出目录条目:

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

哈!这有效。我们只是挂了一个libc函数。

答案 1 :(得分:1)

不,您无法操纵文件系统元数据以使getdents(2)返回目录,其顺序与ls(1)应用于目录的排序顺序相同。

您始终可以使用ls(1)提供的相同算法修改程序以对条目进行排序,但这需要至少O(N)内存和O(N Log N)时间来排序具有N个条目的目录。您必须决定是否值得实现,内存和时间,以与ls(1)相同的方式进行排序。