basefs

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2025 License: MIT Imports: 9 Imported by: 1

README

basefs - Base File System

Go Reference Go Report Card CI License

The basefs package implements the absfs.FileSystem interface by constraining a absfs.FileSystem to a specific subdirectory. A basefs filesystem will essentially be re-rooted to the provided subdirectory and no path navigation will allow access to paths outside of the subdirectory. All paths the are passed to the underlying filesystem are absolute paths constructed by the basefs to avoid ambiguity. After constructing the correct path basefs calls the underlying Filesystem methods normally. basefs will also edit any errors returned to reflect the path as it would appear if the prefix was removed.

The basefs package also provides Prefix and Unwrap functions for debugging purposes.

Install

$ go get github.com/absfs/basefs

Example Usage

package main

import (
    "fmt"

    "github.com/absfs/basefs"
    "github.com/absfs/osfs"
)

func main() {
    ofs, _ := osfs.NewFS() // remember kids don't ignore errors
    bfs, _ := basefs.NewFS(ofs, "/tmp")
    f, _ := bfs.Create("/test.txt")
    defer bfs.Remove("/test.txt")
    bfsdata := []byte("base fs bound to `/tmp`\n")
    f.Write(bfsdata)
    f.Close()

    f, _ = ofs.Open("/tmp/test.txt")
    defer f.Close()
    ofsdata := make([]byte, 512)
    n, _ := f.Read(ofsdata)
    ofsdata = ofsdata[:n]

    if string(bfsdata) == string(ofsdata) {
        fmt.Println("it's the same file.")
    }
}

absfs

Check out the absfs repo for more information about the abstract filesystem interface and features like filesystem composition

LICENSE

This project is governed by the MIT License. See LICENSE

Documentation

Overview

Example (DirectoryTraversal)

Example_directoryTraversal demonstrates directory traversal using fstools.Walk.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/absfs/basefs"
	"github.com/absfs/fstools"
	"github.com/absfs/osfs"
)

func main() {
	ofs, err := osfs.NewFS()
	if err != nil {
		log.Fatal(err)
	}

	// Create an isolated temp directory for this test
	tmpdir, err := os.MkdirTemp("", "basefs-walk-example-")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpdir)

	bfs, err := basefs.NewFS(ofs, tmpdir)
	if err != nil {
		log.Fatal(err)
	}

	// Create some test files, ensuring they are properly closed
	f1, err := bfs.Create("/walk-test-1.txt")
	if err != nil {
		log.Fatal(err)
	}
	if err := f1.Sync(); err != nil {
		log.Fatal(err)
	}
	f1.Close()

	f2, err := bfs.Create("/walk-test-2.txt")
	if err != nil {
		log.Fatal(err)
	}
	if err := f2.Sync(); err != nil {
		log.Fatal(err)
	}
	f2.Close()

	// Walk the filesystem
	count := 0
	err = fstools.Walk(bfs, "/", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		// Count files that start with "walk-test" in their basename
		if !info.IsDir() {
			name := info.Name()
			if len(name) >= 9 && name[:9] == "walk-test" {
				count++
			}
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Found %d test files\n", count)
}
Output:

Found 2 test files
Example (PathSecurity)

ExampleSymlinkFileSystem_path_security demonstrates that basefs prevents directory traversal attacks.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/absfs/basefs"
	"github.com/absfs/osfs"
)

func main() {
	// Create an OS filesystem
	ofs, err := osfs.NewFS()
	if err != nil {
		log.Fatal(err)
	}

	// Get temp directory
	tmpdir := os.TempDir()

	// Create a basefs constrained to temp directory
	bfs, err := basefs.NewFS(ofs, tmpdir)
	if err != nil {
		log.Fatal(err)
	}

	// Try to access a file outside the base directory using ../
	// This will fail safely
	_, err = bfs.Open("/../etc/passwd")
	if err != nil {
		fmt.Println("Access denied: cannot escape base directory")
	}

}
Output:

Access denied: cannot escape base directory

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Prefix

func Prefix(fs absfs.FileSystem) string

Prefix checks if `fs` is a `*basefs.FileSystem` and if so returns the prefix. otherwise it returns an empty string

Example

ExamplePrefix demonstrates getting the prefix path from a basefs.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/absfs/basefs"
	"github.com/absfs/osfs"
)

func main() {
	ofs, err := osfs.NewFS()
	if err != nil {
		log.Fatal(err)
	}

	tmpdir := os.TempDir()
	bfs, err := basefs.NewFS(ofs, tmpdir)
	if err != nil {
		log.Fatal(err)
	}

	// Get the prefix (base directory)
	prefix := basefs.Prefix(bfs)

	// Verify the prefix matches what we set
	if prefix == tmpdir {
		fmt.Println("Prefix matches temp directory")
	}
}
Output:

Prefix matches temp directory

func Unwrap

func Unwrap(fs absfs.FileSystem) absfs.FileSystem

Unwrap checks if `fs` is a `*basefs.FileSystem` and if so returns the underlying `absfs.FileSystem`, otherwise it returns `fs`

Example

ExampleUnwrap demonstrates unwrapping a basefs to get the underlying filesystem.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/absfs/basefs"
	"github.com/absfs/osfs"
)

func main() {
	ofs, err := osfs.NewFS()
	if err != nil {
		log.Fatal(err)
	}

	tmpdir := os.TempDir()
	bfs, err := basefs.NewFS(ofs, tmpdir)
	if err != nil {
		log.Fatal(err)
	}

	// Unwrap to get the underlying filesystem
	underlying := basefs.Unwrap(bfs)

	fmt.Printf("Unwrapped: %T\n", underlying)
}
Output:

Unwrapped: *osfs.FileSystem

Types

type File

type File struct {
	// contains filtered or unexported fields
}

func (*File) Close

func (f *File) Close() error

func (*File) Name

func (f *File) Name() string

func (*File) Read

func (f *File) Read(p []byte) (n int, err error)

func (*File) ReadAt

func (f *File) ReadAt(b []byte, off int64) (n int, err error)

func (*File) ReadDir

func (f *File) ReadDir(n int) ([]fs.DirEntry, error)

func (*File) Readdir

func (f *File) Readdir(n int) (dirs []os.FileInfo, err error)

func (*File) Readdirnames

func (f *File) Readdirnames(n int) (names []string, err error)

func (*File) Seek

func (f *File) Seek(offset int64, whence int) (ret int64, err error)

func (*File) Stat

func (f *File) Stat() (os.FileInfo, error)

func (*File) Sync

func (f *File) Sync() error

func (*File) Truncate

func (f *File) Truncate(size int64) error

func (*File) Write

func (f *File) Write(p []byte) (n int, err error)

func (*File) WriteAt

func (f *File) WriteAt(b []byte, off int64) (n int, err error)

func (*File) WriteString

func (f *File) WriteString(s string) (n int, err error)

type FileSystem

type FileSystem struct {
	// contains filtered or unexported fields
}

func NewFileSystem

func NewFileSystem(fs absfs.FileSystem, dir string) (*FileSystem, error)

NewFileSystem creates a new FileSystem from a `absfs.FileSystem` compatible object and a path. The path must be an absolute path (Unix-style, starting with /) and must already exist in the fs provided otherwise an error is returned.

Example

ExampleNewFileSystem demonstrates the non-symlink filesystem interface.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/absfs/basefs"
	"github.com/absfs/osfs"
)

func main() {
	// Create an OS filesystem
	ofs, err := osfs.NewFS()
	if err != nil {
		log.Fatal(err)
	}

	// Get the system temp directory (works cross-platform)
	tmpdir := os.TempDir()

	// Create a basefs constrained to temp directory
	bfs, err := basefs.NewFileSystem(ofs, tmpdir)
	if err != nil {
		log.Fatal(err)
	}

	// Create and write to a file
	f, err := bfs.Create("/test.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer bfs.Remove("/test.txt")

	_, err = f.WriteString("Testing basefs\n")
	if err != nil {
		log.Fatal(err)
	}
	f.Close()

	// Read the file back
	f, err = bfs.Open("/test.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	data := make([]byte, 100)
	n, err := f.Read(data)
	if err != nil && err.Error() != "EOF" {
		log.Fatal(err)
	}

	fmt.Printf("Read %d bytes\n", n)
}
Output:

Read 15 bytes

func (*FileSystem) Chdir

func (b *FileSystem) Chdir(dir string) error

func (*FileSystem) Chmod

func (f *FileSystem) Chmod(name string, mode os.FileMode) error

Chmod changes the mode of the named file to mode.

func (*FileSystem) Chown

func (f *FileSystem) Chown(name string, uid, gid int) error

Chown changes the owner and group ids of the named file

func (*FileSystem) Chtimes

func (f *FileSystem) Chtimes(name string, atime time.Time, mtime time.Time) error

Chtimes changes the access and modification times of the named file

func (*FileSystem) Create

func (f *FileSystem) Create(name string) (absfs.File, error)

func (*FileSystem) Getwd

func (b *FileSystem) Getwd() (dir string, err error)

func (*FileSystem) Mkdir

func (f *FileSystem) Mkdir(name string, perm os.FileMode) error

Mkdir creates a directory in the filesystem, return an error if any happens.

func (*FileSystem) MkdirAll

func (f *FileSystem) MkdirAll(name string, perm os.FileMode) error

func (*FileSystem) Open

func (f *FileSystem) Open(name string) (absfs.File, error)

func (*FileSystem) OpenFile

func (f *FileSystem) OpenFile(name string, flags int, perm os.FileMode) (absfs.File, error)

OpenFile opens a file using the given flags and the given mode.

func (*FileSystem) ReadDir

func (f *FileSystem) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir reads the named directory and returns a list of directory entries sorted by filename.

func (*FileSystem) ReadFile

func (f *FileSystem) ReadFile(name string) ([]byte, error)

ReadFile reads the named file and returns its contents.

func (*FileSystem) Remove

func (f *FileSystem) Remove(name string) error

Remove removes a file identified by name, returning an error, if any happens.

func (*FileSystem) RemoveAll

func (f *FileSystem) RemoveAll(name string) error

func (*FileSystem) Rename

func (f *FileSystem) Rename(oldname, newname string) error

func (*FileSystem) Stat

func (f *FileSystem) Stat(name string) (os.FileInfo, error)

Stat returns the FileInfo structure describing file. If there is an error, it will be of type *PathError.

func (*FileSystem) Sub

func (f *FileSystem) Sub(dir string) (fs.FS, error)

Sub returns an fs.FS corresponding to the subtree rooted at dir.

func (*FileSystem) TempDir

func (f *FileSystem) TempDir() string

func (*FileSystem) Truncate

func (f *FileSystem) Truncate(name string, size int64) error

type SymlinkFileSystem

type SymlinkFileSystem struct {
	// contains filtered or unexported fields
}

func NewFS

NewFS creates a new SymlinkFileSystem from a `absfs.SymlinkFileSystem` compatible object and a path. The path must be an absolute path (Unix-style, starting with /) and must already exist in the fs provided otherwise an error is returned.

Example

ExampleNewFS demonstrates creating a basefs filesystem that constrains access to a specific subdirectory.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/absfs/basefs"
	"github.com/absfs/osfs"
)

func main() {
	// Create an OS filesystem
	ofs, err := osfs.NewFS()
	if err != nil {
		log.Fatal(err)
	}

	// Get the system temp directory (works cross-platform)
	tmpdir := os.TempDir()

	// Create a basefs constrained to temp directory
	bfs, err := basefs.NewFS(ofs, tmpdir)
	if err != nil {
		log.Fatal(err)
	}

	// All operations are now relative to the temp directory
	// This creates a file in the temp directory
	f, err := bfs.Create("/example.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer bfs.Remove("/example.txt")
	defer f.Close()

	// Write some data
	_, err = f.Write([]byte("Hello from basefs!\n"))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("File created successfully")
}
Output:

File created successfully

func (*SymlinkFileSystem) Chdir

func (b *SymlinkFileSystem) Chdir(dir string) error

func (*SymlinkFileSystem) Chmod

func (f *SymlinkFileSystem) Chmod(name string, mode os.FileMode) error

Chmod changes the mode of the named file to mode.

func (*SymlinkFileSystem) Chown

func (f *SymlinkFileSystem) Chown(name string, uid, gid int) error

Chown changes the owner and group ids of the named file

func (*SymlinkFileSystem) Chtimes

func (f *SymlinkFileSystem) Chtimes(name string, atime time.Time, mtime time.Time) error

Chtimes changes the access and modification times of the named file

func (*SymlinkFileSystem) Create

func (f *SymlinkFileSystem) Create(name string) (absfs.File, error)

func (*SymlinkFileSystem) Getwd

func (b *SymlinkFileSystem) Getwd() (dir string, err error)

func (*SymlinkFileSystem) Lchown

func (f *SymlinkFileSystem) Lchown(name string, uid, gid int) error

func (*SymlinkFileSystem) Lstat

func (f *SymlinkFileSystem) Lstat(name string) (os.FileInfo, error)

func (*SymlinkFileSystem) Mkdir

func (f *SymlinkFileSystem) Mkdir(name string, perm os.FileMode) error

Mkdir creates a directory in the filesystem, return an error if any happens.

func (*SymlinkFileSystem) MkdirAll

func (f *SymlinkFileSystem) MkdirAll(name string, perm os.FileMode) error

func (*SymlinkFileSystem) Open

func (f *SymlinkFileSystem) Open(name string) (absfs.File, error)

func (*SymlinkFileSystem) OpenFile

func (f *SymlinkFileSystem) OpenFile(name string, flags int, perm os.FileMode) (absfs.File, error)

OpenFile opens a file using the given flags and the given mode.

func (*SymlinkFileSystem) ReadDir

func (f *SymlinkFileSystem) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir reads the named directory and returns a list of directory entries sorted by filename.

func (*SymlinkFileSystem) ReadFile

func (f *SymlinkFileSystem) ReadFile(name string) ([]byte, error)

ReadFile reads the named file and returns its contents.

func (f *SymlinkFileSystem) Readlink(name string) (string, error)

func (*SymlinkFileSystem) Remove

func (f *SymlinkFileSystem) Remove(name string) error

Remove removes a file identified by name, returning an error, if any happens.

func (*SymlinkFileSystem) RemoveAll

func (f *SymlinkFileSystem) RemoveAll(name string) error

func (*SymlinkFileSystem) Rename

func (f *SymlinkFileSystem) Rename(oldname, newname string) error

func (*SymlinkFileSystem) Stat

func (f *SymlinkFileSystem) Stat(name string) (os.FileInfo, error)

Stat returns the FileInfo structure describing file. If there is an error, it will be of type *PathError.

func (*SymlinkFileSystem) Sub

func (f *SymlinkFileSystem) Sub(dir string) (fs.FS, error)

Sub returns an fs.FS corresponding to the subtree rooted at dir.

func (f *SymlinkFileSystem) Symlink(oldname, newname string) error

func (*SymlinkFileSystem) TempDir

func (f *SymlinkFileSystem) TempDir() string

func (*SymlinkFileSystem) Truncate

func (f *SymlinkFileSystem) Truncate(name string, size int64) error

Jump to

Keyboard shortcuts

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