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

osfs

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: BSD-3-Clause Imports: 15 Imported by: 0

README

osfs

A host directory as a go-filesystems/interface Filesystem, confined with os.Root.

Every other driver of the org decodes a format out of an image. This one hands each call to the host kernel, relative to one directory, so that a server written against the interface — go-fileshare/fileshare serves SMB, NFS, WebDAV, SFTP and S3 that way — can export a directory tree (a container volume, a home directory) exactly as it exports an image.

fsys, err := osfs.Open("/data/photos")                // read-write
fsys, err := osfs.Open("/data/photos", osfs.ReadOnly()) // every write refused
fsys, err := osfs.OpenRoot(root)                      // through an *os.Root you hold; Close closes it
total, free, err := fsys.Usage()                       // statfs of the tree

ReadFile refuses a file above 1 GiB (ErrTooLarge; change it with osfs.MaxReadFile(n)), since a client that may write can truncate a sparse file to any size; use OpenFile for large files.

Confinement

A client cannot leave the tree. .. that climbs out, and a symbolic link whose target is outside, are refused by the kernel-backed os.Root — not by a string check. A client may create a link to /etc with Symlink (the interface stores targets as given), but no call will follow it. A FIFO planted in the tree is refused rather than left to hang an open.

Capabilities

Filesystem, Opener (positional ReadAt/WriteAt straight on the *os.File, WritableFile when writable), Truncater, MetadataSetter, Symlinker, HardLinker. Pure Go, CGO_ENABLED=0. Tested on Linux, macOS and Windows, and under QEMU on riscv64, loong64, ppc64le and s390x; built for the BSDs, plan9, js and wasip1.

License

BSD-3-Clause.

Documentation

Overview

Package osfs serves a directory of the host as a github.com/go-filesystems/interface Filesystem.

Every other driver in the go-filesystems org decodes an on-disk format out of an image. This one has no format: it hands each call to the host kernel, relative to a directory opened once with os.OpenRoot. It exists so that a server written against the interface (go-fileshare/fileshare serves SMB, NFS, WebDAV, SFTP and S3 that way) can export a directory tree — a container volume, a home directory — exactly as it exports an image.

Confinement

The point of the package is that a client cannot leave the tree. Every path operation goes through the os.Root, never through a path joined by hand, so the confinement is the kernel-backed one os.Root implements (openat and friends, resolved one component at a time), not a string check that a clever path could get past:

  • ".." that climbs above the tree is refused;
  • a symbolic link whose target lies outside the tree is refused when it is followed — whether a client created it through FS.Symlink or it was already on the host;
  • a symbolic link inside the tree that stays inside the tree works.

Symlink stores its target as given (the interface requires it, and so does os.Root), so a client CAN create a link that points at /etc. What it cannot do is make the server follow it: ReadFile, OpenFile, WriteFile, ListDir, Truncate, Chmod, Chown, Chtimes, Link and the rest all refuse a path that leaves the tree through such a link. Stat and ReadLink describe the link itself, which is what a network client needs to resolve it on its own side.

Opening

Open takes a path. OpenRoot takes an os.Root the caller already holds and serves the tree through it, taking ownership of it: a server that checks a share's path and then opens it keeps the directory it checked, even if the path is swapped for a symbolic link afterwards, because the kernel resolves every call against the Root's descriptor.

Paths

Paths are slash-separated and relative to the root of the tree; a leading "/" is accepted and means the same thing, so "/a/b", "a/b" and "//a/b" name one file and "", "/" and "." name the root. That matches the other drivers of the org. It follows that there is no way to name a host absolute path on Unix: "/etc/passwd" is the file etc/passwd INSIDE the tree.

What each call means here

  • Stat does not follow a final symbolic link (it is lstat), so servers see S_IFLNK and can answer READLINK. Mode carries the POSIX type and permission bits. Inode is the host's inode number on Unix; on other systems it is 0, which consumers already treat as "unknown".
  • ListDir returns the entries sorted by name, without "." and "..". FileType is the dirent d_type value (DT_REG 8, DT_DIR 4, DT_LNK 10, DT_FIFO 1, DT_CHR 2, DT_BLK 6, DT_SOCK 12, DT_UNKNOWN 0).
  • DeleteFile removes any non-directory, including a symbolic link (never its target). DeleteDir removes an EMPTY directory, as rmdir(2) does: it is not recursive, because every protocol server that calls it expects rmdir semantics and a recursive delete of a host tree is not a thing to get by accident. Neither is idempotent: a missing path is an error wrapping io/fs.ErrNotExist.
  • ReadFile holds a whole file in memory, so it refuses one larger than DefaultMaxReadFile (1 GiB; see MaxReadFile) with an error wrapping ErrTooLarge, before allocating anything: a client that may write can Truncate a sparse file to any size. It never preallocates more than 1 MiB from the size a file claims; the buffer grows with what is read.
  • ReadFile, OpenFile, WriteFile and Truncate only ever touch regular files. They open with O_NONBLOCK on Unix and check the type of what they opened, so a FIFO in the tree is refused instead of hanging the server.
  • OpenFile returns a filesystem.WritableFile when the FS is writable and the host lets the file be opened read-write; otherwise a plain filesystem.File. Reads and writes are positional (pread/pwrite on the *os.File); nothing is buffered. Sync is fsync(2) (F_FULLFSYNC on Darwin, FlushFileBuffers on Windows), so "the backing store" is the host filesystem the directory lives on.

Read-only

With ReadOnly, every mutating method returns an error wrapping ErrReadOnly before it touches anything, and files are opened O_RDONLY.

Index

Constants

View Source
const DefaultMaxReadFile = 1 << 30

DefaultMaxReadFile is the largest file, in bytes, that FS.ReadFile reads unless MaxReadFile says otherwise: 1 GiB.

ReadFile holds the whole file in memory, and a client that may write can make a sparse file of any size with Truncate (NFS SETATTR, SMB SET_INFO): without a limit, one request makes the server read terabytes of zeros into memory. Anything larger belongs to FS.OpenFile, which reads it piece by piece.

Variables

View Source
var ErrReadOnly = errors.New("osfs: read-only filesystem")

ErrReadOnly is wrapped by the error every mutating method returns when the FS was opened with ReadOnly.

View Source
var ErrTooLarge = errors.New("osfs: file too large to read whole")

ErrTooLarge is wrapped by the error ReadFile returns for a file larger than the limit set with MaxReadFile (DefaultMaxReadFile unless changed).

Functions

This section is empty.

Types

type FS

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

FS is a host directory tree, confined with os.Root. It is safe for concurrent use.

func Open

func Open(dir string, opts ...Option) (*FS, error)

Open opens the directory dir, which must exist and be a directory, as a filesystem. Nothing outside dir is reachable through the result.

func OpenRoot added in v0.2.0

func OpenRoot(r *os.Root, opts ...Option) (*FS, error)

OpenRoot serves the directory r was opened on, through r itself. Every call goes through r, so the tree is the one r holds: a caller that checked a path and then opened it with os.OpenRoot keeps what it checked, even if a component of that path is swapped for a symbolic link afterwards.

On success the FS owns r: FS.Close closes it, and the caller must not. On error r is left open and still belongs to the caller.

An FS opened this way knows no path for its tree. Where FS.Usage needs one it derives it from r's descriptor instead (see Usage).

func (*FS) Chmod

func (fsys *FS) Chmod(p string, perm os.FileMode) error

Chmod sets the permission bits of p (following a final in-tree link).

On Windows a final symbolic link is changed itself rather than followed, as os.Root does there (go.dev/issue/71492); either way nothing outside the tree is touched.

func (*FS) Chown

func (fsys *FS) Chown(p string, uid, gid uint32) error

Chown sets the owner and group of p (following a final in-tree link). The host decides whether the caller may; on Windows it always fails.

func (*FS) Chtimes

func (fsys *FS) Chtimes(p string, atime, mtime time.Time) error

Chtimes sets the access and modification times of p.

func (*FS) Close

func (fsys *FS) Close() error

Close closes the tree and every File obtained from it with OpenFile.

func (*FS) DeleteDir

func (fsys *FS) DeleteDir(p string) error

DeleteDir removes the EMPTY directory at p, as rmdir(2) does. It is not recursive: a non-empty directory is an error.

func (*FS) DeleteFile

func (fsys *FS) DeleteFile(p string) error

DeleteFile removes the non-directory at p. A symbolic link is removed itself; its target is not touched.

func (fsys *FS) Link(oldPath, newPath string) error

Link creates newPath as a hard link to oldPath, which must not be a directory. If oldPath is a symbolic link, the link itself is linked.

func (*FS) ListDir

func (fsys *FS) ListDir(p string) ([]filesystem.DirEntry, error)

ListDir returns the entries of the directory at p, sorted by name, without "." and "..". See the package documentation for the FileType values.

func (*FS) MkDir

func (fsys *FS) MkDir(p string, perm os.FileMode) error

MkDir creates the directory p. Its parent must exist and p must not.

func (*FS) OpenFile

func (fsys *FS) OpenFile(p string) (filesystem.File, error)

OpenFile opens the regular file at p for positional access. The result is a filesystem.WritableFile unless the FS is read-only or the host refuses to open the file for writing (its permissions, a read-only mount), in which case it is a plain, read-only filesystem.File.

func (*FS) ReadFile

func (fsys *FS) ReadFile(p string) ([]byte, error)

ReadFile returns the whole content of the regular file at p. A file larger than the limit (DefaultMaxReadFile, or as set with MaxReadFile) is an error wrapping ErrTooLarge; so is one that grows past it while being read.

func (fsys *FS) ReadLink(p string) (string, error)

ReadLink returns the target of the symbolic link at p, slash-separated.

func (*FS) Rename

func (fsys *FS) Rename(oldPath, newPath string) error

Rename moves oldPath to newPath, replacing newPath if the host allows it.

func (*FS) Stat

func (fsys *FS) Stat(p string) (filesystem.Stat, error)

Stat describes the file at p. A final symbolic link is not followed.

func (fsys *FS) Symlink(target, linkPath string) error

Symlink creates the symbolic link linkPath with the literal target. The target is not checked — it may point anywhere — but it is never followed out of the tree: see the package documentation.

func (*FS) Truncate

func (fsys *FS) Truncate(p string, size int64) error

Truncate resizes the regular file at p to size bytes.

func (*FS) Usage

func (fsys *FS) Usage() (total, free uint64, err error)

Usage returns the size of the host filesystem holding the tree and the bytes available on it to an unprivileged user, from fstatfs(2) on the tree's own directory descriptor.

func (*FS) WriteFile

func (fsys *FS) WriteFile(p string, data []byte, perm os.FileMode) error

WriteFile creates or truncates the regular file at p and writes data to it. perm is used only when the file is created. The parent must exist.

type Option

type Option func(*options)

Option configures Open and OpenRoot.

func MaxReadFile added in v0.2.0

func MaxReadFile(n int64) Option

MaxReadFile sets the largest file, in bytes, that FS.ReadFile reads; a larger one is an error wrapping ErrTooLarge, returned before anything is allocated for it. n <= 0 removes the limit — memory is then the only bound, so do that only where every writer is trusted. The default is DefaultMaxReadFile.

func ReadOnly

func ReadOnly() Option

ReadOnly makes every mutating method return an error wrapping ErrReadOnly, and opens every file O_RDONLY.

Jump to

Keyboard shortcuts

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