Help us shape the future of Go! Take the 2026 Go Developer Survey

ls

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

linux-ls

A lightweight wrapper around the getdents syscall on linux.

The main reason for me to write this was that [os.ReadDir] did not return the inode number together with the file name. The only way I could find was with an extra lstat syscall.

Installation

go get -u github.com/tfoertsch123/linux-ls

Documentation

Overview

Package ls provides a lightweight directory listing utility built on top of the getdents(2) system call. It returns directory entries as an iterator sequence, avoiding the overhead of allocating a full slice of results and enabling early termination by the caller.

Entries can be filtered by name (via a regular expression) and by type (e.g. unix.DT_REG, unix.DT_DIR). Each entry includes the inode number and the d_type field, so callers can avoid an additional unix.Stat call when the filesystem supports d_type (most do, including ext4, xfs, btrfs, and ZFS).

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func LsFd

func LsFd(
	fd int,
	re *regexp.Regexp,
	types ...uint8,
) iter.Seq2[*DirItem, error]

LsFd behaves the same as LsPath with the exception that it expects an open file descriptor instead of a directory path.

Example (No_filter)
dir, err := setupExampleDir("ExampleLsPath_no_filter")
if err != nil {
	fmt.Fprintf(os.Stderr, "Cannot create temp dir %v\n", err)
	return
}
defer os.RemoveAll(dir)

fh, err := os.Open(dir)
if err != nil {
	fmt.Fprintf(os.Stderr, "Cannot open temp dir %v\n", err)
	return
}

for item, err := range ls.LsFd(int(fh.Fd()), nil) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while reading dir: %v\n", err)
		break
	}
	fmt.Printf("> %-10s %s\n", dtNames[item.Type], item.Name)
}
Output:
> DT_DIR     .
> DT_DIR     ..
> DT_DIR     dir1
> DT_DIR     dir2
> DT_DIR     other_dir
> DT_REG     file1
> DT_REG     file2
> DT_REG     other_file
> DT_LNK     symlink1
> DT_LNK     symlink2
> DT_LNK     other_symlink

func LsPath

func LsPath(
	dir string,
	re *regexp.Regexp,
	types ...uint8,
) iter.Seq2[*DirItem, error]

LsPath returns an iter.Seq2 iterator over the entries in the directory dir. Each iteration yields a *DirItem and an error; when an error occurs the entry is nil and iteration stops.

If re is non-nil, only entries whose name matches the regular expression are yielded. If one or more types are given, only entries whose d_type matches one of the specified values (e.g. unix.DT_REG, unix.DT_DIR) are yielded. Both filters are AND-combined.

The iterator opens the directory with (unix.O_RDONLY | unix.O_DIRECTORY) and reads entries with unix.Getdents. The directory file descriptor is closed automatically when iteration completes or is abandoned (via [break] or early return from the yield function).

The "." and ".." entries are included in the output unless filtered out by re or types.

Example (Filter_both)
dir, err := setupExampleDir("ExampleLsPath_filter_both")
if err != nil {
	fmt.Fprintf(os.Stderr, "Cannot create temp dir %v\n", err)
	return
}
defer os.RemoveAll(dir)

re := regexp.MustCompile(`^other_`)
for item, err := range ls.LsPath(dir, re, unix.DT_LNK, unix.DT_REG) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while reading dir: %v\n", err)
		break
	}
	fmt.Printf("> %-10s %s\n", dtNames[item.Type], item.Name)
}
Output:
> DT_REG     other_file
> DT_LNK     other_symlink
Example (No_filter)
dir, err := setupExampleDir("ExampleLsPath_no_filter")
if err != nil {
	fmt.Fprintf(os.Stderr, "Cannot create temp dir %v\n", err)
	return
}
defer os.RemoveAll(dir)

for item, err := range ls.LsPath(dir, nil) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while reading dir: %v\n", err)
		break
	}
	fmt.Printf("> %-10s %s\n", dtNames[item.Type], item.Name)
}
Output:
> DT_DIR     .
> DT_DIR     ..
> DT_DIR     dir1
> DT_DIR     dir2
> DT_DIR     other_dir
> DT_REG     file1
> DT_REG     file2
> DT_REG     other_file
> DT_LNK     symlink1
> DT_LNK     symlink2
> DT_LNK     other_symlink
Example (Regexp_filter)
dir, err := setupExampleDir("ExampleLsPath_regexp_filter")
if err != nil {
	fmt.Fprintf(os.Stderr, "Cannot create temp dir %v\n", err)
	return
}
defer os.RemoveAll(dir)

re := regexp.MustCompile(`^other_`)
for item, err := range ls.LsPath(dir, re) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while reading dir: %v\n", err)
		break
	}
	fmt.Printf("> %-10s %s\n", dtNames[item.Type], item.Name)
}
Output:
> DT_DIR     other_dir
> DT_REG     other_file
> DT_LNK     other_symlink
Example (Type_filter)
dir, err := setupExampleDir("ExampleLsPath_type_filter")
if err != nil {
	fmt.Fprintf(os.Stderr, "Cannot create temp dir %v\n", err)
	return
}
defer os.RemoveAll(dir)

for item, err := range ls.LsPath(dir, nil, unix.DT_LNK, unix.DT_REG) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while reading dir: %v\n", err)
		break
	}
	fmt.Printf("> %-10s %s\n", dtNames[item.Type], item.Name)
}
Output:
> DT_REG     file1
> DT_REG     file2
> DT_REG     other_file
> DT_LNK     symlink1
> DT_LNK     symlink2
> DT_LNK     other_symlink

Types

type DirItem

type DirItem struct {
	// Name is the filename of the directory entry, without any path prefix.
	Name string
	// Ino is the inode number of the entry, as reported by the filesystem.
	Ino uint64
	// Type is the d_type field from the directory entry. It is one of the
	// unix.DT_* constants (e.g. [unix.DT_REG], [unix.DT_DIR], [unix.DT_LNK]).
	// Most filesystems populate this field; callers should still handle
	// [unix.DT_UNKNOWN] gracefully.
	Type uint8
}

DirItem represents a single directory entry returned by LsPath/LsFd.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL