是什么决定了 getdents 返回目录条目的顺序?

发布于 2024-12-26 16:15:15 字数 147 浏览 2 评论 0原文

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

FS 是 ext4,如果这有什么区别的话。

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 displayed in the same order as a call to ls with no arguments. Is it possible to update the directory data in some way to achieve this?

FS is ext4, if that makes any difference.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

花间憩 2025-01-02 16:15:15

如果您真的决心更改此程序的行为(我假设您没有可用的源代码),您可以使用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 函数。

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

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.

要走干脆点 2025-01-02 16:15:15

不,您无法操作文件系统元数据,使 getdents(2) 按照与 ls(1) 应用的排序顺序相同的顺序返回整个目录目录完整。

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

No, there is no way you can manipulate the filesystem metadata to have getdents(2) return directory entires in the same order as the sort order that ls(1) applies to the directory entires.

You can always modify your program to sort entries using the same algorithms that ls(1) provides, though this requires at least O(N) memory and O(N Log N) time for sorting a directory with N entries. You'll have to decide if it is worth the implementation, memory, and time, to sort in the same manner as ls(1).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文