Paths and Locking

These helpers use the same absolute POSIX path rules as transport sessions. PathLock protects the path map.

import {
  basename,
  dirname,
  isNormalizedPath,
  isPathInside,
  joinPath,
  normalizePath,
  PathLock,
  resolvePath,
  splitPath,
} from "mountx";

These APIs help drivers use the same path rules as transports. A driver does not have to call them. Each path that a driver receives is already normalized.

#Path helpers

The helpers accept only absolute Portable Operating System Interface (POSIX) paths. .. stops at the root. Therefore, an input path cannot move above the mount root.

splitPath("/a/b"); // ["a", "b"]
normalizePath("/a//b/../c"); // "/a/c"
joinPath("/a", "b"); // "/a/b"
dirname("/a/b"); // "/a"
basename("/a/b"); // "b"
isPathInside("/a/b", "/a"); // true

#isNormalizedPath()

This function checks whether a path has the exact form that normalizePath() produces. A normalized path is absolute. It has no //, trailing /, ., or ...

isNormalizedPath("/a/b"); // true
isNormalizedPath("/a//b"); // false
isNormalizedPath("a/b"); // false — not absolute

The result is the same as normalizePath(p) === p, but isNormalizedPath() scans the string one time.

It does not split and join the value. normalizePath(), dirname(), and basename() call this function first.

They skip additional work for an already normalized path.

Sessions always give normalized paths to drivers, so this avoids an allocation for common calls.

#resolvePath()

Use this function to normalize and split a path in one call:

resolvePath("/a/./b"); // { path: "/a/b", segments: ["a", "b"] }
resolvePath("/"); // { path: "/", segments: [] }

Calling normalizePath(p) and then splitPath(p) scans the string two times and discards the first array. Drivers often resolve a path such as /a/b/c one component at a time. resolvePath() avoids that duplicate work. segments is a new array. You can change it.

#PathLock

PathLock is the writer lock for the path map. Sessions in all three mount transports use it. RENAME takes the lock. READ and WRITE do not take it, so large input/output operations do not wait for an unrelated rename.

9P uses one lock for each connection, not one lock for each mount. A rename is serialized with other requests on the same connection. It is not serialized with requests from a second client.

#Next

  • Driver interface describes the methods that receive these paths.
  • Tuning explains concurrency and the cost of the lock.

mountx  Write a filesystem in JavaScript, mount it as a real folder.