Documentation
¶
Overview ¶
Package pfs provides a symlink-following file-systemtraverser and other file-system functions.
Index ¶
- Constants
- func Abs(dir string) (out string)
- func AbsEval(path string, retainSymlinks ...bool) (absPath string, err error)
- func AddDirEntry(abs string) (dirEntry fs.DirEntry, err error)
- func AddStatDirEntry(abs string) (dirEntry fs.DirEntry, err error)
- func Exists(path string) (fileInfo fs.FileInfo)
- func Exists2(path string) (fileInfo fs.FileInfo, isNotExist bool, err error)
- func GetModeBitValues() (s string)
- func IsDirectory(path string, flags IsDirectoryArg) (isDirectory bool, err error)
- func NewDirEntryIterator(path string) (iterator iters.Iterator[DirEntry])
- func NewDirIterator(path string) (iterator iters.Iterator[ResultEntry])
- func NewIterator(path string) (iterator iters.Iterator[ResultEntry])
- func ReadDir(abs string, sort ...bool) (entries []fs.DirEntry, err error)
- func Stat(path string) (fileInfo fs.FileInfo, err error)
- type DeferringDirEntry
- type DirEntry
- type DirEntryIterator
- type DirIterator
- type FileMode
- type IsDirectoryArg
- type Iterator
- type Registry
- type ResultEntry
- type ResultReason
- type Root2
- type Traverser
Constants ¶
const ( // AllModeBits is all known github.com/fsnotify/fsevents.EventFlags AllModeBits fs.FileMode = fs.ModeDir | fs.ModeAppend | fs.ModeExclusive | fs.ModeTemporary | fs.ModeSymlink | fs.ModeDevice | fs.ModeNamedPipe | fs.ModeSocket | fs.ModeSetuid | fs.ModeSetgid | fs.ModeCharDevice | fs.ModeSticky | fs.ModeIrregular )
const ( // [DirectoryOrder] NoSorting = false )
const ( // do not evaluate symlinks argument to [AbsEval] RetainSymlinks = true )
Variables ¶
This section is empty.
Functions ¶
func Abs ¶ added in v0.4.23
Abs ensures a file system path is fully qualified. Abs is single-return-value and panics on troubles
func AbsEval ¶
AbsEval returns an absolute path with resolved symlinks
- if symlinks are evaluated, the path must exist
- non-existing path is checked using punix.IsENOENT(err)
- if path is relative, the process’ current directory is used to make path absolute. path empty returns the process’ current directory as absolute evaled path
- absPath is absolute and only empty on error
- absPath is clean:
- — no multiple Separators in sequence
- — no “.” path name elements
- — no infix or postfix “..” path name element or to path above root
- when evaluating symlinks, the path is verified to exist
- if retainSymlinks is RetainSymlinks, symlinks are returned
- errors originate from:
- — os.Lstat os.Readlink os.Getwd or
- — infix path-segment not directory or
- — encountering more than 255 symlinks
func AddDirEntry ¶ added in v0.4.138
AddDirEntry returns an fs.DirEntry with fs.FileInfo available
- error if os.Lstat fails
func AddStatDirEntry ¶ added in v0.4.138
AddDirEntry returns an fs.DirEntry for the target of a symbolic link
func Exists ¶
Exists determines if a path exists If the path exists, fileInfo is non-nil if the path does not exist, fileInfo is nil panic on troubles
func Exists2 ¶ added in v0.4.127
Exists2 determines if a path exists
- fileInfo non-nil: does exist
- isNotExists true, fileInfo nil, err non-nil: does not exist
- isNotExist false, fileInfo nil, err non-nil: some error
func GetModeBitValues ¶
func GetModeBitValues() (s string)
func IsDirectory ¶
func IsDirectory(path string, flags IsDirectoryArg) (isDirectory bool, err error)
IsDirectory determines if path exists, is directory or another type of file-system entry
- path may be relative, contain symlinks or be unclean
- isDirectory is true if path exists and is directory. Non-existing path is not an error.
- if IsDirectoryNonExistentIsError is present, non-existing path returns error
- if IsDirectoryNotDirIsError is present, a file-system entry that is not directory returns error
- flags is bitfield: IsDirectoryNonExistentIsError | IsDirectoryNotDirIsError
- symlinks are followed os.Stat
func NewDirEntryIterator ¶ added in v0.4.148
NewDirEntryIterator returns a one-level directory iterator
- path: directory whose entries should be traversed. Relative or absolute, cannot be empty. May be “.” to scan current working directory.
Usage:
var iterator = pfs.NewDirEntryIterator(someDir) defer iterator.Cancel(&err) for dirEntry, _ := iterator.Init(); iterator.Cond(&dirEntry); { parl.Log(dirEntry.Name()) // “file.txt” parl.Log(dirEntry.providedPath) // “someDir/file.txt” var abs string if abs, err = pfs.AbsEval(dirEntry.ProvidedPath); err != nil { return } parl.Log(abs) // “/file-system/someDir/file.txt” parl.Log("%t", dirEntry.IsDir()) // “false” parl.Log("%t", dirEntry.Type().IsRegular()) // “true” var fileInfo fs.FileInfo if fileInfo, err = dirEntry.Info(); err != nil {
func NewDirIterator ¶ added in v0.4.141
func NewDirIterator(path string) (iterator iters.Iterator[ResultEntry])
NewDirIterator returns an iterator for directories
- path is the initial path for the file-system walk. it may be relative or absolute, contain symlinks and point to a file, directory or special file
- only directories are returned. if directories are not skipped, they descended into.
- symlinks are followed. Broken symlinks are ignored.
- any errored file-system entry cancels the iterator with error.
func NewIterator ¶ added in v0.4.138
func NewIterator(path string) (iterator iters.Iterator[ResultEntry])
NewIterator returns a directory-tree iterator for all file-system entries following symbolic links
- path: initial path for file-system traversal. path may be relative or absolute, contain symlinks and point to a file, directory or special file
- entries that are error-free non-directory non-symbolic-link are returned as REntry
- symbolic links and directories that are not actively skipped are followed
- — returned as RSkippable
- “.” and “..” are not returned
- directories that cannot be opened or listed are returned again as RDirBad
- broken symbolic links are returned as RSymlinkBad
- entries that unexpectedly produce error are returned as RError
- —
- NewDirEntryIterator single-level directory iterator
- delegates to pfs.NewTraverser
func ReadDir ¶ added in v0.4.148
directoryOrder returns unsorted entries, most with deferred fs.FileInfo
Types ¶
type DeferringDirEntry ¶ added in v0.4.138
type DeferringDirEntry struct {
// contains filtered or unexported fields
}
func NewDeferringDirEntry ¶ added in v0.4.138
func NewDeferringDirEntry(abs string) (entry *DeferringDirEntry)
NewDeferringDirEntry returns fs.DirEntry with fs.FileInfo deferred
- abs is absolute path that maybe does not exist
func (*DeferringDirEntry) Info ¶ added in v0.4.138
func (e *DeferringDirEntry) Info() (fileInfo fs.FileInfo, err error)
Info returns the FileInfo for the file or subdirectory described by the entry
- thread-safe, does os.Lstat every time
func (*DeferringDirEntry) IsDir ¶ added in v0.4.138
func (e *DeferringDirEntry) IsDir() (isDir bool)
IsDir reports whether the entry is a directory, ie. ModeDir bit being set
- may panic unless Info has successfully completed
func (*DeferringDirEntry) Name ¶ added in v0.4.138
func (e *DeferringDirEntry) Name() (base string)
base name of the file
func (*DeferringDirEntry) Type ¶ added in v0.4.138
func (e *DeferringDirEntry) Type() (modeType fs.FileMode)
Type returns ModeType bits, 0 for regular file
- ModeDir ModeSymlink ModeNamedPipe ModeSocket ModeDevice ModeCharDevice ModeIrregular
type DirEntry ¶ added in v0.4.148
type DirEntry struct { // DirEntry is the directory entry as returned by // [os.File.ReadDir] fs.DirEntry // ProvidedPath is the initial path to the directory // as provided with [DirEntry.Name] appended ProvidedPath string }
DirEntry is the value-type the iterator returns
type DirEntryIterator ¶ added in v0.4.148
type DirEntryIterator struct { // base iterator provides Cancel() Cond() Next() iters.BaseIterator[DirEntry] // contains filtered or unexported fields }
DirEntryIterator is a one-level directory iterator
func (*DirEntryIterator) Init ¶ added in v0.4.148
func (i *DirEntryIterator) Init() (result DirEntry, iterator iters.Iterator[DirEntry])
Init implements the right-hand side of a short variable declaration in the init statement of a Go “for” clause
for i, iterator := iters.NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); { // i is pointer to slice element
type DirIterator ¶ added in v0.4.141
type DirIterator struct { // BaseIterator provides iterator methods: // [iters.Iterator.Cancel] [iters.Iterator.Cond] [iters.Iterator.Next] iters.BaseIterator[ResultEntry] // contains filtered or unexported fields }
DirIterator traverses file-system directories
func (*DirIterator) Init ¶ added in v0.4.141
func (i *DirIterator) Init() (result ResultEntry, iterator iters.Iterator[ResultEntry])
Init implements the right-hand side of a short variable declaration in the init statement of a Go “for” clause
for i, iterator := iters.NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); { // i is pointer to slice element
type FileMode ¶
type IsDirectoryArg ¶
type IsDirectoryArg uint8
bitfield argument to IsDirectory
- IsDirectoryNonExistentIsError IsDirectoryNotDirIsError
const ( // if path does not exist, return the error [IsDirectory] IsDirectoryNonExistentIsError IsDirectoryArg = 1 << iota // if existing path is not directory, return an error [IsDirectory] // - symlinks are followed, so a symlink pointing ot directory is ok IsDirectoryNotDirIsError )
type Iterator ¶ added in v0.4.138
type Iterator struct { // BaseIterator provides iterator methods: // [iters.Iterator.Cancel] [iters.Iterator.Cond] [iters.Iterator.Next] iters.BaseIterator[ResultEntry] // contains filtered or unexported fields }
Iterator traverses file-system entries and errors
func (*Iterator) Init ¶ added in v0.4.138
func (i *Iterator) Init() (result ResultEntry, iterator iters.Iterator[ResultEntry])
Init implements the right-hand side of a short variable declaration in the init statement of a Go “for” clause
for i, iterator := iters.NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); { // i is pointer to slice element
type Registry ¶ added in v0.4.138
type Registry[V any] struct { // contains filtered or unexported fields }
Registry stores values that are accessible by index or by absolute path
func NewRegistry ¶ added in v0.4.138
NewRegistry returns a registry of values by absolute path
func (*Registry[V]) GetValue ¶ added in v0.4.138
GetValue retrieves value by index
- if index is less than 0 or too large or for a removed value, nil is returned
func (*Registry[V]) HasAbs ¶ added in v0.4.138
HasAbs check whether an absolute path is stored in the registry as a key to a value
func (*Registry[V]) ListLength ¶ added in v0.4.138
ListLength returns the length of the value slice
- a value can still be nil for a discarded root
func (*Registry[V]) ObsoleteIndex ¶ added in v0.4.138
type ResultEntry ¶ added in v0.4.138
type ResultEntry struct { // Info() should be cached because it may be recreated on each invocation // - — deferred-info executing [os.Lstat] // - if Err is non-nil, [RError], Info may return error // - nil for [REnd] fs.DirEntry // path as provided that may be easier to read // - may be implicitly relative to current directory: “subdir/file.txt” // - may have no directory or extension part: “README.css” “z” // - may be relative: “../file.txt” // - may contain symlinks, unnecessary “.” and “..” or // multiple separators in sequence // - may be empty string for current working directory // - empty string for [REnd] ProvidedPath string // - equivalent of Path: absolute, symlink-free, clean // - if Err non-nil, [RError] may be empty // - if the entry is symbolic link: // - — ProvidedPath is the symbolic link location // - — Abs is what the symbolic link points to // - empty string for [REnd] Abs string // function to skip descending into directory or following symlink // - only non-nil for directories and good symbolic links SkipEntry func(no uint64) // skippable serial number, argument to SkipEntry // - only non-zero for directories and good symbolic links No uint64 // any error associated with this entry // - [os.Lstat] failed // - only non-nil for [RDirBad] [RSymlinkBad] [RError] Err error // why this entry was provided // - [REnd] [REntry] [RSkippable] [RDirBad] [RSymlinkBad] [RError] Reason ResultReason }
ResultEntry is an existing file-system entry, traversal-end marker or an error-entry during file-system traversal
- typically created by Traverser or an iterator delegating to Traverser
- — “.” “..” are not returned
- non-error non-end entries have been proven to exist
- ResultEntry.IsEnd or Reason == REnd indicates end
- Reason indicates why the ResultEntry was returned:
- — REnd (zero-value) marks iteration ended: all fields are nil
- — — for-statement iterators do not return this value
- — REntry a directory entry: non-symlink non-directory non-error
- — RSkippable a symlink or directory that may be skipped, default is to traverse it
- — RDirBad a directory whose listing failed os.Open os.File.ReadDir
- — — such erroring directory is returned twice: RSkippable and RDirBad
- — — Err is set
- — RSymlinkBad a broken symlink, Err is set
- — RError error other than bad directory or bad symbolic link
- ResultEntry.Type().IsRegular() determines regular file
- — not available for REnd
- —
- ResultEntry is a value-container that as a local variable, function argument or result is a tuple not causing allocation by using temporary stack storage
- taking the address of a &ResultEntry causes allocation
func (ResultEntry) IsEnd ¶ added in v0.4.138
func (e ResultEntry) IsEnd() (isEnd bool)
IsEnd indicates that this ResultEntry is an end of entries marker
func (ResultEntry) IsHidden ¶ added in v0.4.189
func (e ResultEntry) IsHidden() (isHidden bool)
IsHidden indicates a hidden file, directory or other entry
func (ResultEntry) Skip ¶ added in v0.4.138
func (e ResultEntry) Skip()
Skip marks the returned entry to be skipped
- the entry is directory or symbolic link
- can only be invoked when [ResultEntry.Reason] is RSkippable
func (ResultEntry) String ¶ added in v0.4.145
func (e ResultEntry) String() (s string)
resultEntry path: "…" abs"/…" err ‘OK’ reason ‘non-symlink non-directory non-error entry’
type ResultReason ¶ added in v0.4.138
type ResultReason uint8
Why a directory entry was provided by Traverser
- REnd REntry RSkippable RDirBad RSymlinkBad RError
const ( // the filesystem traversal completed all entries REnd ResultReason = iota // a non-symlink non-directory non-error entry REntry // a directory or symlink about to be traversed RSkippable // a directory whose listing failed [os.Open] [os.File.ReadDir] RDirBad // a broken symlink [os.Stat] RSymlinkBad // failure in [os.Lstat] [os.Readlink] [os.Getwd] RError )
func (ResultReason) String ¶ added in v0.4.138
func (r ResultReason) String() (s string)
type Root2 ¶ added in v0.4.138
type Root2 struct { // path as provided that may be easier to read // - may be implicitly relative to current directory: “subdir/file.txt” // - may have no directory or extension part: “README.css” “z” // - may be relative: “../file.txt” // - may contain symlinks, unnecessary “.” and “..” or // multiple separators in sequence // - may be empty string for current working directory ProvidedPath string // Abs is required for relating roots // - equivalent of Path: absolute, symlink-free, clean // - may not exist Abs string }
Root2 is a file system hierarchy
func NewAbsRoot2 ¶ added in v0.4.138
type Traverser ¶ added in v0.4.138
type Traverser struct {
// contains filtered or unexported fields
}
Traverser represents a file system that is scanned following symlinks
- each file system entry is returned exactly once except:
- — error reading a directory returns the directory a second time
- directories and symlinks are returned before they are read so that they can be more efficiently skipped by invoking ResultEntry.Skip
- directory entries are returned in 8-bit character order
- returned entries may not exist, such entries have [ResultEntry.Err] non-nil
- result.ProvidedPath is based on the initial path and may be relative, unclean and contain symlinks
- if [ResultEntry.Err] is nil, Abs is absolute, symlink-free clean path
- —
- ResultEntry.DirEntry.Info typically invokes os.Lstat every time, so this value should be cached
- because symlinks may point to parents or separate trees, the file system scan may involve multiple roots which may affect the order of return entries
- symlinks are followed and not returned. Therefore, a symlink pointing to a scanned location is effectively ignored
- the returned struct is by value. If its address is not taken, no allocation will occur
func NewTraverser ¶ added in v0.4.138
NewTraverser returns a file-system traverser
- typically used via pfs.Iterator or pfs.DirIterator
- path is the initial path. Path may be relative or absolute, contain symlinks and be unclean. Path may be of any modeType: file, directory or special file. Empty string means process’ current directory
- the Next method is used to obtain file-system entries and errors
- consider using pfs iterators:
- — Iterator for all entries and errors
- — DirIterator for error-free directories
Usage:
var traverser = pfs.NewTraverser(path) for { var result = traverser.Next() if result.IsEnd() || result.Err != nil { break } println(result.Abs) }
func (*Traverser) Next ¶ added in v0.4.138
func (t *Traverser) Next() (result ResultEntry)
Next returns the next file-system entry
- Next ends with [ResultEntry.DirEntry] nil, ie. ResultEntry.IsEnd returns true or ResultEntry.Reason == REnd
- symlinks and directories can be skipped by invoking ResultEntry.Skip. Those have ResultEntry.Reason == RSkippable
- symlinks have information based on the symlink source but [ResultEntry.Abs] is the fully resolved symlink target
- [ResultEntry.ProvidedPath] is a path to the entry based upon the initially provided path. May be empty string
- [ResultEntry.Abs] is an absolute symlink-free clean path but only available when [ResultEntry.Err] is nil
- [ResultEntry.Err] holds any error associated with the returned entry
- —
- result.Err is from:
- — process working directory cannot be read
- — directory read error or os.Readlink or os.Lstat failed