Fs.FsLayer
Definitions
def accessTime(f: String): Result[IoError, Int64] \ IO
Sourcedef allowGlob(patterns: Nel[String], path: String): Result[IoError, String]
SourceResolves path to an absolute, normalized form and checks that it matches
at least one of the given glob patterns. Returns Ok(resolvedPath) if allowed,
or Err(PermissionDenied) if the path does not match any pattern.
def allowList(allowedDirs: Nel[String], path: String): Result[IoError, String]
SourceResolves path to an absolute, normalized form and checks that it falls within
at least one of the allowedDirs. Returns Ok(resolvedPath) if allowed,
or Err(PermissionDenied) if the path is outside every allowed directory.
def append(data: { str = String }, f: String): Result[IoError, Unit] \ IO
Sourcedef appendBytes(data: Vector[Int8], f: String): Result[IoError, Unit] \ IO
Sourcedef appendLines(data: { lines = List[String] }, f: String): Result[IoError, Unit] \ IO
Sourcedef atomicWrite(file: String, doWrite: String -> Result[IoError, Unit] \ ef, doMoveAtomic: String -> (String -> Result[IoError, Unit] \ ef), doDelete: String -> Result[IoError, Unit] \ ef): Result[IoError, Unit] \ ef
SourcePerforms an atomic write to file by writing to a temporary sibling path
first, then atomically moving it into place.
doWrite(tmp)writes data to the temporary path.doMoveAtomic(tmp, file)atomically moves the temp file to the target.doDelete(tmp)cleans up the temp file on failure.
The caller supplies these as effect operations so that this helper works
with any effect (FileWrite, FileSystem, etc.).
def backup(file: String, suffix: String, doCopy: String -> (String -> Result[IoError, Unit] \ ef), doAction: Unit -> Result[IoError, a] \ ef): Result[IoError, a] \ ef
SourcePerforms a backup of file to file + suffix before executing doAction.
doCopy(file, bak)copies the file to the backup path.- If the copy succeeds,
doAction()is executed. - If the copy fails with
NotFound, the file doesn't exist yet, sodoAction()proceeds without backup. - If the copy fails with any other error, the operation is aborted.
def bytesToHex(v: Vector[Int8]): String
SourceConverts a vector of bytes to a lowercase hex string.
def checkTransferLimit(maxSize: Size, actualSize: Size): Result[IoError, Unit]
SourceChecks that actualSize does not exceed maxSize.
Returns Ok(()) if within the limit, or Err(TransferLimitExceeded) otherwise.
def checksumAfterDelete(file: String, sidecar: String, deleteResult: Result[IoError, Unit], doDeleteSidecar: String -> Result[IoError, Unit] \ ef): Result[IoError, Unit] \ ef
SourceDeletes the checksum sidecar after a successful delete.
If the sidecar does not exist, the delete result is returned unchanged. Sidecar delete errors are discarded.
def checksumAfterMove(src: String, dst: String, sidecar: String, moveResult: Result[IoError, Unit], doMoveSidecar: String -> (String -> Result[IoError, Unit] \ ef)): Result[IoError, Unit] \ ef
SourceMoves the checksum sidecar after a successful moveWith.
If the source sidecar does not exist, the move result is returned unchanged. Sidecar move errors are discarded.
def checksumAfterWrite(file: String, doWrite: Unit -> Result[IoError, Unit] \ ef1, doUpdateSidecar: String -> Result[IoError, Unit] \ ef2): Result[IoError, Unit] \ ef1 + ef2
SourcePerforms doWrite, then computes and writes a checksum sidecar for file.
doUpdateSidecar(file) should read the file bytes, hash them, and
write the hex digest to the sidecar path.
def checksumOnRead(file: String, sidecar: String, computeHex: Vector[Int8] -> String, readResult: Result[IoError, a], doReadBytes: String -> Result[IoError, Vector[Int8]] \ ef, doReadSidecar: String -> Result[IoError, String] \ ef): Result[IoError, a] \ ef
SourceVerifies a read or readLines result against a checksum sidecar.
Since the result type (String or List[String]) does not preserve
raw bytes, doReadBytes is called to obtain the on-disk bytes for
hashing. If no sidecar exists, the result passes through.
def checksumOnReadBytes(file: String, sidecar: String, computeHex: Vector[Int8] -> String, readResult: Result[IoError, Vector[Int8]], doReadSidecar: String -> Result[IoError, String] \ ef): Result[IoError, Vector[Int8]] \ ef
SourceVerifies a readBytes result against a checksum sidecar.
The returned bytes are hashed via computeHex and compared against
the sidecar. If no sidecar exists, the result passes through.
def chroot(chrootDir: String, path: String): Result[IoError, String]
SourceResolves path against chrootDir and validates that the resolved result
stays within the chroot directory. Symlinks are resolved to their real
filesystem targets before the boundary check.
Returns Ok(resolvedPath) if the path is within bounds,
or Err(PermissionDenied) if the path escapes the chroot.
def conflictCheck(file: String, snapshots: MutMap[String, Int64, r], getModTime: String -> Result[IoError, Int64] \ ef): Result[IoError, Unit] \ ef + r
SourceChecks whether file was modified externally since last snapshot.
- No snapshot →
Ok()(file was never read, nothing to conflict with). - Mod time matches snapshot →
Ok(). - Mod time differs →
Err(Conflict(...)). - File deleted (
NotFound) →Ok()(file gone, proceed). - Other
getModTimeerror → propagated.
def copy(src: { src = String }, dst: String): Result[IoError, Unit] \ IO
Sourcedef copyWith(src: { src = String }, dst: String, opts: Set[CopyOption]): Result[IoError, Unit] \ IO
Sourcedef creationTime(f: String): Result[IoError, Int64] \ IO
Sourcedef delete(f: String): Result[IoError, Unit] \ IO
Sourcedef denyGlob(patterns: Nel[String], path: String): Result[IoError, String]
SourceResolves path to an absolute, normalized form and checks that it does not match
any of the given glob patterns. Returns Ok(resolvedPath) if permitted,
or Err(PermissionDenied) if the path matches a denied pattern.
def denyList(deniedDirs: Nel[String], path: String): Result[IoError, String]
SourceResolves path to an absolute, normalized form and checks that it does not fall
within any of the deniedDirs. Returns Ok(resolvedPath) if permitted,
or Err(PermissionDenied) if the path is within a denied directory.
def ensureParentDirs(file: String, doMkDirs: String -> Result[IoError, Unit] \ ef, doAction: Unit -> Result[IoError, a] \ ef): Result[IoError, a] \ ef
SourceEnsures the parent directory of file exists before executing doAction.
- If
filehas no parent (bare filename),doAction()proceeds directly. - If
doMkDirs(parent)succeeds,doAction()proceeds. - If
doMkDirs(parent)fails, the error is returned anddoActionis not performed.
def estimateStringBytes(s: String): Size
SourceEstimates the UTF-8 byte size of a string by multiplying the character count by 4 (the maximum bytes per character in UTF-8).
def estimateStringListBytes(l: List[String]): Size
SourceEstimates the UTF-8 byte size of a list of strings by multiplying the total character count by 4 (the maximum bytes per character in UTF-8).
def exists(f: String): Result[IoError, Bool] \ IO
Sourcedef glob(base: String, pattern: String): Result[IoError, List[String]] \ IO
Sourcedef isDirectory(f: String): Result[IoError, Bool] \ IO
Sourcedef isExecutable(f: String): Result[IoError, Bool] \ IO
Sourcedef isReadable(f: String): Result[IoError, Bool] \ IO
Sourcedef isRegularFile(f: String): Result[IoError, Bool] \ IO
Sourcedef isSymbolicLink(f: String): Result[IoError, Bool] \ IO
Sourcedef isWritable(f: String): Result[IoError, Bool] \ IO
Sourcedef list(f: String): Result[IoError, List[String]] \ IO
Sourcedef logPost(op: String, path: String, describe: a -> String, result: Result[IoError, a]): Unit \ Logger
SourceLogs a post-operation message: Debug on success, Warn on error.
def logPost2(op: String, src: String, dst: String, result: Result[IoError, Unit]): Unit \ Logger
SourceLogs a post-operation message for two-path operations (copy/move).
def logPre(op: String, path: String): Unit \ Logger
SourceLogs a pre-operation message at Debug level.
def logPre2(op: String, src: String, dst: String): Unit \ Logger
SourceLogs a pre-operation message for two-path operations (copy/move) at Debug level.
def mkDir(d: String): Result[IoError, Unit] \ IO
Sourcedef mkDirs(d: String): Result[IoError, Unit] \ IO
Sourcedef mkTempDir(prefix: String): Result[IoError, String] \ IO
Sourcedef modificationTime(f: String): Result[IoError, Int64] \ IO
Sourcedef move(src: { src = String }, dst: String): Result[IoError, Unit] \ IO
Sourcedef moveWith(src: { src = String }, dst: String, opts: Set[MoveOption]): Result[IoError, Unit] \ IO
Sourcedef parentDir(path: String): Option[String]
SourceReturns the parent directory of path, or None if the path has no parent
(e.g., a bare filename like "test.txt").
def read(f: String): Result[IoError, String] \ IO
Sourcedef readBytes(f: String): Result[IoError, Vector[Int8]] \ IO
Sourcedef readLines(f: String): Result[IoError, List[String]] \ IO
Sourcedef resolve(baseDir: String, path: String): String
SourceResolves path against baseDir using Java's Path.resolve semantics:
- If
pathis absolute, it is returned as-is. - If
pathis relative, it is joined tobaseDir.
def resolveRealPath(path: String): Result[IoError, String]
SourceResolves path to its real filesystem target by following all symlinks.
Returns Ok(realPath) if the path exists, or an appropriate IoError if the
path is invalid, does not exist, or cannot be resolved.
def resolveRealPathOrSelf(path: String): String
SourceResolves path to its real filesystem target by following all symlinks.
Falls back to the original path if resolution fails (e.g., the file does not
exist yet). Useful for write/create operations where the target may not exist.
def rotateIfNeeded(file: String, maxSize: Size, maxFiles: Int32, doSize: String -> Result[IoError, Size] \ ef1, doMove: String -> (String -> Result[IoError, Unit] \ ef2), doDelete: String -> Result[IoError, Unit] \ ef2, doAction: Unit -> Result[IoError, a] \ ef2): Result[IoError, a] \ ef1 + ef2
SourceRotates file if its size meets or exceeds maxSize, then executes doAction.
Rotation shifts existing numbered files (file.1 … file.{maxFiles})
upward by one, deletes the oldest (file.{maxFiles}), and moves file
to file.1. The doAction then writes to the now-absent original path.
If the file does not exist (NotFound), rotation is skipped and
doAction proceeds directly (append will create it).
def size(f: String): Result[IoError, Size] \ IO
Sourcedef snapshotModTime(file: String, snapshots: MutMap[String, Int64, r], getModTime: String -> Result[IoError, Int64] \ ef): Unit \ ef + r
SourceSnapshots the modification time of file into snapshots.
If getModTime fails (file deleted, etc.), silently skips.
def truncate(f: String): Result[IoError, Unit] \ IO
Sourcedef updateSidecar(file: String, sidecar: String, computeHex: Vector[Int8] -> String, doReadBytes: String -> Result[IoError, Vector[Int8]] \ ef1, doWriteSidecar: String -> (String -> Result[IoError, Unit] \ ef2)): Result[IoError, Unit] \ ef1 + ef2
SourceReads the bytes of file, hashes them with computeHex, and writes
the hex digest to the sidecar path file + sidecar.
def verifyChecksum(file: String, sidecar: String, actual: String, doReadSidecar: String -> Result[IoError, String] \ ef): Result[IoError, Unit] \ ef
SourceVerifies actual (a hex digest string) against the checksum stored in
the sidecar file file + sidecar.
- If the sidecar does not exist (
NotFound), returnsOk(()). - If the sidecar exists and matches, returns
Ok(()). - If the sidecar exists and does not match, returns
Err(IoError(ChecksumMismatch, ...)).
def write(data: { str = String }, f: String): Result[IoError, Unit] \ IO
Sourcedef writeBytes(data: Vector[Int8], f: String): Result[IoError, Unit] \ IO
Sourcedef writeLines(data: { lines = List[String] }, f: String): Result[IoError, Unit] \ IO
Source