Remove the incorrect check for visited inodes (#659)

Removes the incorrect check for visited inodes. Fixes the added failing
tests:

> ✘ Test sameAbsoluteSymlinkFollowedTwice() recorded an issue at
TestEXT4Reader+IO.swift:502:6: Caught error: symlink loop while
resolving: target/../symlink/file.txt
> ✘ Test sameAbsoluteSymlinkFollowedTwice() failed after 0.009 seconds
with 1 issue.

> ✘ Test sameRelativeSymlinkFollowedTwice() recorded an issue at
TestEXT4Reader+IO.swift:516:6: Caught error: symlink loop while
resolving: ../target/../symlink/file.txt
> ✘ Test sameRelativeSymlinkFollowedTwice() failed after 0.010 seconds
with 1 issue.
This commit is contained in:
Dmitry Kovba
2026-04-09 11:09:07 -07:00
committed by GitHub
parent d8ec470b39
commit b2be8dec67
2 changed files with 28 additions and 7 deletions
@@ -281,7 +281,6 @@ extension EXT4.EXT4Reader {
var parentStack: [EXT4.InodeNumber] = [] // Track parent chain for proper ".." handling
var symlinkHops = 0
var visitedInodes = Set<EXT4.InodeNumber>()
// Process components one at a time to handle symlinks in the middle of paths
var componentIndex = 0
@@ -330,12 +329,6 @@ extension EXT4.EXT4Reader {
// Check if child is a symlink
let childInode = try getInode(number: child.1)
if childInode.mode.isLink() && followSymlinks {
// Check for symlink loop
if visitedInodes.contains(child.1) {
throw EXT4.PathIOError.symlinkLoop(FilePath(components.joined(separator: "/")).description)
}
visitedInodes.insert(child.1)
// Enforce max symlink depth
symlinkHops += 1
if symlinkHops > maxSymlinks {
@@ -499,6 +499,34 @@ struct EXT4PathIOTests {
}
}
@Test
func sameAbsoluteSymlinkFollowedTwice() throws {
let url = try buildFS { fmt in
try self.createDir(fmt, "/target")
try self.createFile(fmt, "/target/file.txt", "OK")
try self.createSymlink(fmt, "/symlink", "/target")
}
defer { try? FileManager.default.removeItem(at: url) }
let r = try openReader(url)
let data = try r.readFile(at: FilePath("/symlink/../symlink/file.txt"))
#expect(String(decoding: data, as: UTF8.self) == "OK")
}
@Test
func sameRelativeSymlinkFollowedTwice() throws {
let url = try buildFS { fmt in
try self.createDir(fmt, "/target")
try self.createFile(fmt, "/target/file.txt", "OK")
try self.createSymlink(fmt, "/symlink", "../target")
}
defer { try? FileManager.default.removeItem(at: url) }
let r = try openReader(url)
let data = try r.readFile(at: FilePath("/symlink/../symlink/file.txt"))
#expect(String(decoding: data, as: UTF8.self) == "OK")
}
@Test
func boundsCheckingForInvalidExtents() throws {
// This test verifies that the reader properly validates extent addresses