// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fs defines basic interfaces to a file system. // A file system can be provided by the host operating system // but also by other packages. // // See the [testing/fstest] package for support with testing // implementations of file systems.
package fs import ( ) // An FS provides access to a hierarchical file system. // // The FS interface is the minimum implementation required of the file system. // A file system may implement additional interfaces, // such as [ReadFileFS], to provide additional or optimized functionality. // // [testing/fstest.TestFS] may be used to test implementations of an FS for // correctness. type FS interface { // Open opens the named file. // // When Open returns an error, it should be of type *PathError // with the Op field set to "open", the Path field set to name, // and the Err field describing the problem. // // Open should reject attempts to open names that do not satisfy // ValidPath(name), returning a *PathError with Err set to // ErrInvalid or ErrNotExist. Open(name string) (File, error) } // ValidPath reports whether the given path name // is valid for use in a call to Open. // // Path names passed to open are UTF-8-encoded, // unrooted, slash-separated sequences of path elements, like “x/y/z”. // Path names must not contain an element that is “.” or “..” or the empty string, // except for the special case that the root directory is named “.”. // Paths must not start or end with a slash: “/x” and “x/” are invalid. // // Note that paths are slash-separated on all systems, even Windows. // Paths containing other characters such as backslash and colon // are accepted as valid, but those characters must never be // interpreted by an [FS] implementation as path element separators. func ( string) bool { if !utf8.ValidString() { return false } if == "." { // special case return true } // Iterate over elements in name, checking each. for { := 0 for < len() && [] != '/' { ++ } := [:] if == "" || == "." || == ".." { return false } if == len() { return true // reached clean ending } = [+1:] } } // A File provides access to a single file. // The File interface is the minimum implementation required of the file. // Directory files should also implement [ReadDirFile]. // A file may implement [io.ReaderAt] or [io.Seeker] as optimizations. type File interface { Stat() (FileInfo, error) Read([]byte) (int, error) Close() error } // A DirEntry is an entry read from a directory // (using the [ReadDir] function or a [ReadDirFile]'s ReadDir method). type DirEntry interface { // Name returns the name of the file (or subdirectory) described by the entry. // This name is only the final element of the path (the base name), not the entire path. // For example, Name would return "hello.go" not "home/gopher/hello.go". Name() string // IsDir reports whether the entry describes a directory. IsDir() bool // Type returns the type bits for the entry. // The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. Type() FileMode // Info returns the FileInfo for the file or subdirectory described by the entry. // The returned FileInfo may be from the time of the original directory read // or from the time of the call to Info. If the file has been removed or renamed // since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). // If the entry denotes a symbolic link, Info reports the information about the link itself, // not the link's target. Info() (FileInfo, error) } // A ReadDirFile is a directory file whose entries can be read with the ReadDir method. // Every directory file should implement this interface. // (It is permissible for any file to implement this interface, // but if so ReadDir should return an error for non-directories.) type ReadDirFile interface { File // ReadDir reads the contents of the directory and returns // a slice of up to n DirEntry values in directory order. // Subsequent calls on the same file will yield further DirEntry values. // // If n > 0, ReadDir returns at most n DirEntry structures. // In this case, if ReadDir returns an empty slice, it will return // a non-nil error explaining why. // At the end of a directory, the error is io.EOF. // (ReadDir must return io.EOF itself, not an error wrapping io.EOF.) // // If n <= 0, ReadDir returns all the DirEntry values from the directory // in a single slice. In this case, if ReadDir succeeds (reads all the way // to the end of the directory), it returns the slice and a nil error. // If it encounters an error before the end of the directory, // ReadDir returns the DirEntry list read until that point and a non-nil error. ReadDir(n int) ([]DirEntry, error) } // Generic file system errors. // Errors returned by file systems can be tested against these errors // using [errors.Is]. var ( ErrInvalid = errInvalid() // "invalid argument" ErrPermission = errPermission() // "permission denied" ErrExist = errExist() // "file already exists" ErrNotExist = errNotExist() // "file does not exist" ErrClosed = errClosed() // "file already closed" ) func errInvalid() error { return oserror.ErrInvalid } func errPermission() error { return oserror.ErrPermission } func errExist() error { return oserror.ErrExist } func errNotExist() error { return oserror.ErrNotExist } func errClosed() error { return oserror.ErrClosed } // A FileInfo describes a file and is returned by [Stat]. type FileInfo interface { Name() string // base name of the file Size() int64 // length in bytes for regular files; system-dependent for others Mode() FileMode // file mode bits ModTime() time.Time // modification time IsDir() bool // abbreviation for Mode().IsDir() Sys() any // underlying data source (can return nil) } // A FileMode represents a file's mode and permission bits. // The bits have the same definition on all systems, so that // information about files can be moved from one system // to another portably. Not all bits apply to all systems. // The only required bit is [ModeDir] for directories. type FileMode uint32 // The defined file mode bits are the most significant bits of the [FileMode]. // The nine least-significant bits are the standard Unix rwxrwxrwx permissions. // The values of these bits should be considered part of the public API and // may be used in wire protocols or disk representations: they must not be // changed, although new bits might be added. const ( // The single letters are the abbreviations // used by the String method's formatting. ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory ModeAppend // a: append-only ModeExclusive // l: exclusive use ModeTemporary // T: temporary file; Plan 9 only ModeSymlink // L: symbolic link ModeDevice // D: device file ModeNamedPipe // p: named pipe (FIFO) ModeSocket // S: Unix domain socket ModeSetuid // u: setuid ModeSetgid // g: setgid ModeCharDevice // c: Unix character device, when ModeDevice is set ModeSticky // t: sticky ModeIrregular // ?: non-regular file; nothing else is known about this file // Mask for the type bits. For regular files, none will be set. ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular ModePerm FileMode = 0777 // Unix permission bits ) func ( FileMode) () string { const = "dalTLDpSugct?" var [32]byte // Mode is uint32. := 0 for , := range { if &(1<<uint(32-1-)) != 0 { [] = byte() ++ } } if == 0 { [] = '-' ++ } const = "rwxrwxrwx" for , := range { if &(1<<uint(9-1-)) != 0 { [] = byte() } else { [] = '-' } ++ } return string([:]) } // IsDir reports whether m describes a directory. // That is, it tests for the [ModeDir] bit being set in m. func ( FileMode) () bool { return &ModeDir != 0 } // IsRegular reports whether m describes a regular file. // That is, it tests that no mode type bits are set. func ( FileMode) () bool { return &ModeType == 0 } // Perm returns the Unix permission bits in m (m & [ModePerm]). func ( FileMode) () FileMode { return & ModePerm } // Type returns type bits in m (m & [ModeType]). func ( FileMode) () FileMode { return & ModeType } // PathError records an error and the operation and file path that caused it. type PathError struct { Op string Path string Err error } func ( *PathError) () string { return .Op + " " + .Path + ": " + .Err.Error() } func ( *PathError) () error { return .Err } // Timeout reports whether this error represents a timeout. func ( *PathError) () bool { , := .Err.(interface{ () bool }) return && .() }