Go code to list files in a Linux directory using getdents()

huangapple go评论75阅读模式
英文:

Go code to list files in a Linux directory using getdents()

问题

作为练习,我想将一些使用了许多系统调用的 C 代码翻译成 Golang。我在 Unix & Linux StackExchange 上找到了这个很好的代码示例

/*
 * 使用 getdents() 列出目录,因为 ls、find 和 Python 库使用的是 readdir(),它更慢(但底层使用的是 getdents())。
 *
 * 编译命令:
 * ]$ gcc  getdents.c -o getdents
 */
#define _GNU_SOURCE
#include <dirent.h>     /* 定义了 DT_* 常量 */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>

#define handle_error(msg) \
       do { perror(msg); exit(EXIT_FAILURE); } while (0)

struct linux_dirent {
   long           d_ino;
   off_t          d_off;
   unsigned short d_reclen;
   char           d_name[];
};

#define BUF_SIZE 1024*1024*5

int
main(int argc, char *argv[])
{
   int fd, nread;
   char buf[BUF_SIZE];
   struct linux_dirent *d;
   int bpos;
   char d_type;

   fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
   if (fd == -1)
       handle_error("open");

   for ( ; ; ) {
       nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
       if (nread == -1)
           handle_error("getdents");

       if (nread == 0)
           break;

       for (bpos = 0; bpos < nread;) {
           d = (struct linux_dirent *) (buf + bpos);
           d_type = *(buf + bpos + d->d_reclen - 1);
           if( d->d_ino != 0 && d_type == DT_REG ) {
              printf("%s\n", (char *)d->d_name );
           }
           bpos += d->d_reclen;
       }
   }

   exit(EXIT_SUCCESS);
}

我只能使用 ioutil.ReadDir 来编写这段代码,这违背了初衷。有人知道如何翻译这段代码吗?

英文:

As an exercise, I wanted to translate some C code that used many syscalls into Golang. I found this nice code example on Unix & Linux StackExchange:

/*
 * List directories using getdents() because ls, find and Python libraries
 * use readdir() which is slower (but uses getdents() underneath.
 *
 * Compile with 
 * ]$ gcc  getdents.c -o getdents
 */
#define _GNU_SOURCE
#include &lt;dirent.h&gt;     /* Defines DT_* constants */
#include &lt;fcntl.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;sys/syscall.h&gt;

#define handle_error(msg) \
       do { perror(msg); exit(EXIT_FAILURE); } while (0)

struct linux_dirent {
   long           d_ino;
   off_t          d_off;
   unsigned short d_reclen;
   char           d_name[];
};

#define BUF_SIZE 1024*1024*5

int
main(int argc, char *argv[])
{
   int fd, nread;
   char buf[BUF_SIZE];
   struct linux_dirent *d;
   int bpos;
   char d_type;

   fd = open(argc &gt; 1 ? argv[1] : &quot;.&quot;, O_RDONLY | O_DIRECTORY);
   if (fd == -1)
       handle_error(&quot;open&quot;);

   for ( ; ; ) {
       nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
       if (nread == -1)
           handle_error(&quot;getdents&quot;);

       if (nread == 0)
           break;

       for (bpos = 0; bpos &lt; nread;) {
           d = (struct linux_dirent *) (buf + bpos);
           d_type = *(buf + bpos + d-&gt;d_reclen - 1);
           if( d-&gt;d_ino != 0 &amp;&amp; d_type == DT_REG ) {
              printf(&quot;%s\n&quot;, (char *)d-&gt;d_name );
           }
           bpos += d-&gt;d_reclen;
       }
   }

   exit(EXIT_SUCCESS);
}

I have only been able to code this using ioutil.ReadDir which defeats the purpose. Does anyone have an idea on how to translate this?

答案1

得分: 2

我会避免使用这段代码。按照现有的写法,它是错误的:在32位系统上,甚至可能在一些64位系统上,SYS_getdents是一个不提供d_type并且不支持64位inode号的旧系统调用,这意味着在现代文件系统上会出现不必要的错误。即使你修复了这个问题,它也不比内联readdir更好,因为它在内部基本上做的事情是一样的。

英文:

I would avoid using this code. As written, it's wrong: on 32-bit systems and maybe even some 64-bit ones, SYS_getdents is the legacy syscall that doesn't provide d_type and lacks support for 64-bit inode numbers, which means you get gratuitous errors on modern filesystems. Even if you fix it, it's no better than inlining readdir, which does basically exactly the same thing internally.

huangapple
  • 本文由 发表于 2014年7月30日 02:29:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/25022486.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定