Use typed symlink checks in SSD storage walks

ober

86d0719c4df7409b4a1c2ef94eea9216bbdcf6aa

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 26033f3..e7b4d5b 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -1573,7 +1573,8 @@
                 TruthIndexEntry-sourceName TruthIndexEntry-canonicalSourceName
                 TruthIndexEntry-page TruthIndexEntry-dpi TruthIndexEntry-groupCount
                 TruthIndexEntry-truthTime betterTruthIndex
-                fileExists fileIsDirectory fileIsRegular safeLocalRegularFile
+                fileExists fileIsDirectory fileIsRegular fileIsSymbolicLink
+                safeLocalRegularFile
                 destinationNewFileDelta
                 oldDestinationBytes urlEffectivePort
                 remoteBearerTokenPresent remoteBearerTokenValid
@@ -1643,9 +1644,11 @@
           (and (fileExists file) (fileIsDirectoryRaw file)))
         (def (fileIsRegular (file : File)) : Bool
           (and (fileExists file) (fileIsFile file)))
+        (def (fileIsSymbolicLink (file : File)) : Bool
+          (pathIsSymbolicLink (fileToPath file)))
         (def (safeLocalRegularFile (file : File)) : Bool
           (and (fileIsRegular file)
-               (not (pathIsSymbolicLink (fileToPath file)))))
+               (not (fileIsSymbolicLink file))))
         (def (destinationNewFileDelta (destination : File)) : Int32
           (if (fileExists destination) (int32 0) (int32 1)))
         (def (oldDestinationBytes (destination : File)) : Int
@@ -8077,7 +8080,7 @@
        "        val stats = StorageStats(0, 0L)"
        "        fun walk(file: File, depth: Int) {"
        "            if (depth > 32) throw IllegalStateException(\"Storage tree too deep\")"
-       "            if (Files.isSymbolicLink(file.toPath())) throw IllegalStateException(\"Storage symlink rejected\")"
+       "            if (fileIsSymbolicLink(file)) throw IllegalStateException(\"Storage symlink rejected\")"
        "            if (fileIsDirectory(file)) {"
        "                file.listFiles()?.forEach { walk(it, depth + 1) }"
        "            } else if (fileIsRegular(file)) {"
@@ -8323,7 +8326,7 @@
        "        ZipOutputStream(BufferedOutputStream(limited)).use { zip ->"
        "            listOf(groundTruthDir, learnedDir, eventsDir, reviewsDir).forEach { dir ->"
        "                dir.walkTopDown().filter { fileIsRegular(it) }.forEach { file ->"
-       "                    if (Files.isSymbolicLink(file.toPath())) throw IllegalStateException(\"Storage symlink rejected\")"
+       "                    if (fileIsSymbolicLink(file)) throw IllegalStateException(\"Storage symlink rejected\")"
        "                    entries += 1"
        "                    sourceBytes += file.length()"
        "                    if (entries > MAX_ZIP_ENTRIES || file.length() > MAX_ZIP_ENTRY_BYTES || sourceBytes > MAX_ZIP_TOTAL_BYTES) {"