diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt
index b455862..c2a1551 100644
--- a/src/main/kotlin/html4tree/main.kt
+++ b/src/main/kotlin/html4tree/main.kt
@@ -199,15 +199,38 @@ fun process_ignore_file(curr_dir: File, dirFilesNames: Array? = null): S
}
// ⚡ Bolt Performance Optimization: 디렉토리 목록을 Set에 추가하기 위해 필터링만 할 때는 정렬이 불필요하므로 .sorted()를 제거하여 O(N log N) 오버헤드를 방지합니다.
- val list = dirFilesNames ?: curr_dir.list()
- list?.forEach {
- val current = it
- val pathCurrent = java.nio.file.Paths.get(current)
- for (matcher in ignored_matchers) {
- if (matcher.matches(pathCurrent)) {
- files_to_exclude.add(current)
- break
- }
+ if (dirFilesNames != null) {
+ dirFilesNames.forEach {
+ val current = it
+ val pathCurrent = java.nio.file.Paths.get(current)
+ for (matcher in ignored_matchers) {
+ if (matcher.matches(pathCurrent)) {
+ files_to_exclude.add(current)
+ break
+ }
+ }
+ }
+ } else {
+ try {
+ val stream = java.nio.file.Files.newDirectoryStream(curr_dir.toPath())
+ try {
+ val iterator = stream.iterator()
+ while (iterator.hasNext()) {
+ val path = iterator.next()
+ val current = path.fileName.toString()
+ val pathCurrent = java.nio.file.Paths.get(current)
+ for (matcher in ignored_matchers) {
+ if (matcher.matches(pathCurrent)) {
+ files_to_exclude.add(current)
+ break
+ }
+ }
+ }
+ } finally {
+ stream.close()
+ }
+ } catch (e: Exception) {
+ // Ignore access denied exceptions
}
}
}
@@ -220,9 +243,29 @@ fun process_ignore_file(curr_dir: File, dirFilesNames: Array? = null): S
files_to_exclude.addAll(defaultSensitiveFiles)
// 보안 향상: .env, .git 등 민감한 정보가 포함될 수 있는 숨김 파일(.으로 시작하는 모든 항목)을 기본적으로 노출하지 않도록 제외 (정보 노출 방지)
- (dirFilesNames ?: curr_dir.list())?.forEach {
- if (it.startsWith(".")) {
- files_to_exclude.add(it)
+ if (dirFilesNames != null) {
+ dirFilesNames.forEach {
+ if (it.startsWith(".")) {
+ files_to_exclude.add(it)
+ }
+ }
+ } else {
+ try {
+ val stream = java.nio.file.Files.newDirectoryStream(curr_dir.toPath())
+ try {
+ val iterator = stream.iterator()
+ while (iterator.hasNext()) {
+ val path = iterator.next()
+ val current = path.fileName.toString()
+ if (current.startsWith(".")) {
+ files_to_exclude.add(current)
+ }
+ }
+ } finally {
+ stream.close()
+ }
+ } catch (e: Exception) {
+ // Ignore access denied exceptions
}
}
diff --git a/src/test/kotlin/html4tree/MainTest.kt b/src/test/kotlin/html4tree/MainTest.kt
index 1349471..1138a6f 100644
--- a/src/test/kotlin/html4tree/MainTest.kt
+++ b/src/test/kotlin/html4tree/MainTest.kt
@@ -705,4 +705,33 @@ class MainTest {
assertFalse(processed, "fileKey mismatch should skip directory processing")
assertFalse(listed, "fileKey mismatch should skip child listing")
}
+
+
+ @Test
+ fun testProcessIgnoreFileThrowsExceptionOnNewDirectoryStream() {
+ val dir = File(tempDir, "errorDir")
+ dir.mkdir()
+ File(dir, ".html4ignore").writeText("*.txt")
+ try {
+ Assume.assumeTrue(dir.setReadable(false, false))
+ val excluded = process_ignore_file(dir, null)
+ assertTrue(excluded.contains("index.html"))
+ } finally {
+ dir.setReadable(true, false)
+ }
+ }
+
+ @Test
+ fun testProcessIgnoreFileUnreadableDirectory() {
+ val unreadableDir = File(tempDir, "unreadable")
+ unreadableDir.mkdir()
+ try {
+ Assume.assumeTrue(unreadableDir.setReadable(false, false))
+ val excluded = process_ignore_file(unreadableDir, null)
+ assertTrue(excluded.contains("index.html"))
+ } finally {
+ unreadableDir.setReadable(true, false)
+ }
+ }
+
}