Skip to content

Commit 34c930b

Browse files
author
Vladimir Kotal
authored
deal with symlinks when sorting directory entries (#3629)
1 parent 2ed3125 commit 34c930b

File tree

2 files changed

+71
-19
lines changed

2 files changed

+71
-19
lines changed

opengrok-web/src/main/java/org/opengrok/web/PageConfig.java

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import org.apache.lucene.document.DateTools;
6666
import org.apache.lucene.document.Document;
6767
import org.jetbrains.annotations.Nullable;
68+
import org.jetbrains.annotations.VisibleForTesting;
6869
import org.opengrok.indexer.Info;
6970
import org.opengrok.indexer.analysis.AbstractAnalyzer;
7071
import org.opengrok.indexer.analysis.AnalyzerGuru;
@@ -446,28 +447,11 @@ public List<String> getResourceFileList() {
446447
if (isDir() && getResourcePath().length() > 1) {
447448
files = getResourceFile().listFiles();
448449
}
450+
449451
if (files == null) {
450452
dirFileList = Collections.emptyList();
451453
} else {
452-
List<String> listOfFiles;
453-
if (env.getListDirsFirst()) {
454-
Arrays.sort(files, (f1, f2) -> {
455-
if (f1.isDirectory() && f2.isDirectory()) {
456-
return f1.getName().compareTo(f2.getName());
457-
} else if (f1.isFile() && f2.isFile()) {
458-
return f1.getName().compareTo(f2.getName());
459-
} else {
460-
if (f1.isFile() && f2.isDirectory()) {
461-
return 1;
462-
} else {
463-
return -1;
464-
}
465-
}
466-
});
467-
} else {
468-
Arrays.sort(files, Comparator.comparing(File::getName));
469-
}
470-
listOfFiles = Arrays.stream(files).map(File::getName).collect(Collectors.toList());
454+
List<String> listOfFiles = getSortedFiles(files);
471455

472456
if (env.hasProjects() && getPath().isEmpty()) {
473457
/**
@@ -494,6 +478,27 @@ public List<String> getResourceFileList() {
494478
return dirFileList;
495479
}
496480

481+
private Comparator<File> getFileComparator() {
482+
if (getEnv().getListDirsFirst()) {
483+
return (f1, f2) -> {
484+
if (f1.isDirectory() && !f2.isDirectory()) {
485+
return -1;
486+
} else if (!f1.isDirectory() && f2.isDirectory()) {
487+
return 1;
488+
} else {
489+
return f1.getName().compareTo(f2.getName());
490+
}
491+
};
492+
} else {
493+
return Comparator.comparing(File::getName);
494+
}
495+
}
496+
497+
@VisibleForTesting
498+
List<String> getSortedFiles(File[] files) {
499+
return Arrays.stream(files).sorted(getFileComparator()).map(File::getName).collect(Collectors.toList());
500+
}
501+
497502
/**
498503
* Get the time of last modification of the related file or directory.
499504
*

opengrok-web/src/test/java/org/opengrok/web/PageConfigTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727
import java.io.FileNotFoundException;
2828
import java.io.IOException;
2929
import java.nio.file.Files;
30+
import java.nio.file.Path;
31+
import java.nio.file.Paths;
3032
import java.util.ArrayList;
3133
import java.util.Arrays;
3234
import java.util.List;
3335
import java.util.Map;
36+
import java.util.stream.Collectors;
3437

3538
import jakarta.servlet.http.HttpServletRequest;
3639
import org.junit.jupiter.api.AfterAll;
@@ -219,6 +222,50 @@ public boolean isAllowed(HttpServletRequest request, Project project) {
219222
env.setProjects(oldProjects);
220223
}
221224

225+
@SuppressWarnings("ResultOfMethodCallIgnored")
226+
@EnabledOnOs({OS.LINUX, OS.MAC, OS.SOLARIS, OS.AIX, OS.OTHER})
227+
@Test
228+
void testGetSortedFilesDirsFirst() throws IOException {
229+
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
230+
env.setListDirsFirst(true);
231+
// Cannot spy/mock final class.
232+
HttpServletRequest req = createRequest("/source", "/xref", "");
233+
PageConfig pageConfig = PageConfig.get(req);
234+
235+
// Make sure the source root has just directories.
236+
File sourceRootFile = new File(repository.getSourceRoot());
237+
assertTrue(Arrays.stream(sourceRootFile.listFiles()).filter(File::isFile).
238+
collect(Collectors.toSet()).isEmpty());
239+
240+
// Create regular file under source root.
241+
File file = new File(sourceRootFile, "foo.txt");
242+
assertTrue(file.createNewFile());
243+
assertTrue(file.isFile());
244+
245+
// Make sure the regular file is last.
246+
List<String> entries = pageConfig.getSortedFiles(sourceRootFile.listFiles());
247+
assertNotNull(entries);
248+
assertFalse(entries.isEmpty());
249+
int numEntries = entries.size();
250+
assertEquals("foo.txt", entries.get(entries.size() - 1));
251+
252+
// Create symbolic link to non-existent target.
253+
Path link = Path.of(sourceRootFile.getCanonicalPath(), "link");
254+
Path target = Paths.get("/nonexistent");
255+
Files.createSymbolicLink(link, target);
256+
257+
// Check the symlink was sorted as file.
258+
entries = pageConfig.getSortedFiles(sourceRootFile.listFiles());
259+
assertNotNull(entries);
260+
assertFalse(entries.isEmpty());
261+
assertEquals(numEntries + 1, entries.size());
262+
assertEquals("link", entries.get(entries.size() - 1));
263+
264+
// Cleanup.
265+
file.delete();
266+
link.toFile().delete();
267+
}
268+
222269
@Test
223270
public void testGetIntParam() {
224271
String[] attrs = {"a", "b", "c", "d", "e", "f", "g", "h"};

0 commit comments

Comments
 (0)