Use typed path symlink checks in SSD storage

ober

24002587ecfb9594388abb5bee8adb472b6169ce

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index e7b4d5b..5c50b9b 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -1574,7 +1574,7 @@
                 TruthIndexEntry-page TruthIndexEntry-dpi TruthIndexEntry-groupCount
                 TruthIndexEntry-truthTime betterTruthIndex
                 fileExists fileIsDirectory fileIsRegular fileIsSymbolicLink
-                safeLocalRegularFile
+                pathIsSymbolicLink safeLocalRegularFile
                 destinationNewFileDelta
                 oldDestinationBytes urlEffectivePort
                 remoteBearerTokenPresent remoteBearerTokenValid
@@ -1597,7 +1597,7 @@
           (kotlin-member-call length))
         (extern (fileToPath (file : File)) : Path
           (kotlin-member-call toPath))
-        (extern (pathIsSymbolicLink (path : Path)) : Bool
+        (extern (pathIsSymbolicLinkRaw (path : Path)) : Bool
           (kotlin-call Files isSymbolicLink))
         (extern (bytesSize (bytes : Bytes)) : Int32
           (kotlin-member-get size))
@@ -1644,6 +1644,8 @@
           (and (fileExists file) (fileIsDirectoryRaw file)))
         (def (fileIsRegular (file : File)) : Bool
           (and (fileExists file) (fileIsFile file)))
+        (def (pathIsSymbolicLink (path : Path)) : Bool
+          (pathIsSymbolicLinkRaw path))
         (def (fileIsSymbolicLink (file : File)) : Bool
           (pathIsSymbolicLink (fileToPath file)))
         (def (safeLocalRegularFile (file : File)) : Bool
@@ -8070,7 +8072,7 @@
        "    private fun containedLeaf(base: File, leaf: String): File {"
        "        require(safeLeaf(leaf)) { \"Unsafe local leaf\" }"
        "        val basePath = base.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS)"
-       "        require(!Files.isSymbolicLink(basePath)) { \"Symlinked storage root rejected\" }"
+       "        require(!pathIsSymbolicLink(basePath)) { \"Symlinked storage root rejected\" }"
        "        val target = basePath.resolve(leaf).normalize()"
        "        require(target.parent == basePath) { \"Local path escaped storage root\" }"
        "        return target.toFile()"
@@ -8110,10 +8112,10 @@
        "        ensureStorageCapacity(destination, bytes.size.toLong())"
        "        val parent = destination.parentFile ?: throw IllegalArgumentException(\"Destination has no parent\")"
        "        val parentPath = parent.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS)"
-       "        require(!Files.isSymbolicLink(parentPath)) { \"Symlinked destination parent rejected\" }"
+       "        require(!pathIsSymbolicLink(parentPath)) { \"Symlinked destination parent rejected\" }"
        "        val target = parentPath.resolve(destination.name).normalize()"
        "        require(target.parent == parentPath) { \"Destination escaped parent\" }"
-       "        require(!Files.isSymbolicLink(target)) { \"Symlinked destination rejected\" }"
+       "        require(!pathIsSymbolicLink(target)) { \"Symlinked destination rejected\" }"
        "        val temporary = Files.createTempFile(parentPath, \".ssd-review-\", \".part\")"
        "        try {"
        "            Files.write(temporary, bytes, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)"