use of org.opengrok.indexer.util.ForbiddenSymlinkException in project OpenGrok by OpenGrok.
the class IndexDatabase method acceptSymlink.
/**
* Check if I should accept the path containing a symlink.
*
* @param absolute the path with a symlink to check
* @param canonical the canonical file object
* @param ret defined instance whose {@code localRelPath} property will be
* non-null afterward if and only if {@code absolute} is a symlink that
* targets either a {@link Repository}-local filesystem object or the same
* object ({@code canonical}) as a previously-detected and allowed symlink.
* N.b. method will return {@code false} if {@code ret.localRelPath} is set
* non-null.
* @return a value indicating if {@code file} should be included in index
*/
private boolean acceptSymlink(Path absolute, File canonical, AcceptSymlinkRet ret) {
ret.localRelPath = null;
String absolute1 = absolute.toString();
String canonical1 = canonical.getPath();
boolean isCanonicalDir = canonical.isDirectory();
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
IndexedSymlink indexed1;
String absolute0;
if (isLocal(canonical1)) {
if (!isCanonicalDir) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Local {0} has symlink from {1}", new Object[] { canonical1, absolute1 });
}
/*
* Always index symlinks to local files, but do not add to
* indexedSymlinks for a non-directory.
*/
return true;
}
/*
* Do not index symlinks to local directories, because the
* canonical target will be indexed on its own -- but relativize()
* a path to be returned in ret so that a symlink can be replicated
* in xref/.
*/
ret.localRelPath = absolute.getParent().relativize(canonical.toPath()).toString();
// Try to put the prime absolute path into indexedSymlinks.
try {
String primeRelative = env.getPathRelativeToSourceRoot(canonical);
absolute0 = env.getSourceRootPath() + primeRelative;
} catch (ForbiddenSymlinkException | IOException e) {
/*
* This is not expected, as indexDown() would have operated on
* the file already -- but we are forced to handle.
*/
LOGGER.log(Level.WARNING, String.format("Unexpected error getting relative for %s", canonical), e);
absolute0 = absolute1;
}
indexed1 = new IndexedSymlink(absolute0, canonical1, true);
indexedSymlinks.put(canonical1, indexed1);
return false;
}
IndexedSymlink indexed0;
if ((indexed0 = indexedSymlinks.get(canonical1)) != null) {
if (absolute1.equals(indexed0.getAbsolute())) {
return true;
}
/*
* Do not index symlinks to external directories already indexed
* as linked elsewhere, because the canonical target will be
* indexed already -- but relativize() a path to be returned in ret
* so that this second symlink can be redone as a local
* (non-external) symlink in xref/.
*/
ret.localRelPath = absolute.getParent().relativize(Paths.get(indexed0.getAbsolute())).toString();
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "External dir {0} has symlink from {1} after first {2}", new Object[] { canonical1, absolute1, indexed0.getAbsolute() });
}
return false;
}
/*
* Iterate through indexedSymlinks, which is sorted so that shorter
* canonical entries come first, to see if the new link is a child
* canonically.
*/
for (IndexedSymlink a0 : indexedSymlinks.values()) {
indexed0 = a0;
if (!indexed0.isLocal() && canonical1.startsWith(indexed0.getCanonicalSeparated())) {
absolute0 = indexed0.getAbsolute();
if (!isCanonicalDir) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "External file {0} has symlink from {1} under previous {2}", new Object[] { canonical1, absolute1, absolute0 });
}
// Do not add to indexedSymlinks for a non-directory.
return true;
}
/*
* See above about redoing a sourceRoot symlink as a local
* (non-external) symlink in xref/.
*/
Path abs0 = Paths.get(absolute0, canonical1.substring(indexed0.getCanonicalSeparated().length()));
ret.localRelPath = absolute.getParent().relativize(abs0).toString();
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "External dir {0} has symlink from {1} under previous {2}", new Object[] { canonical1, absolute1, absolute0 });
}
return false;
}
}
Set<String> canonicalRoots = env.getCanonicalRoots();
for (String canonicalRoot : canonicalRoots) {
if (canonical1.startsWith(canonicalRoot)) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Allowed symlink {0} per canonical root {1}", new Object[] { absolute1, canonical1 });
}
if (isCanonicalDir) {
indexed1 = new IndexedSymlink(absolute1, canonical1, false);
indexedSymlinks.put(canonical1, indexed1);
}
return true;
}
}
Set<String> allowedSymlinks = env.getAllowedSymlinks();
for (String allowedSymlink : allowedSymlinks) {
String allowedTarget;
try {
allowedTarget = new File(allowedSymlink).getCanonicalPath();
} catch (IOException e) {
LOGGER.log(Level.FINE, "unresolvable symlink: {0}", allowedSymlink);
continue;
}
/*
* The following canonical check is sufficient because indexDown()
* traverses top-down, and any intermediate symlinks would have
* also been checked here for an allowed canonical match. This
* technically means that if there is a set of redundant symlinks
* with the same canonical target, then allowing one of the set
* will allow all others in the set.
*/
if (canonical1.equals(allowedTarget)) {
if (isCanonicalDir) {
indexed1 = new IndexedSymlink(absolute1, canonical1, false);
indexedSymlinks.put(canonical1, indexed1);
}
return true;
}
}
return false;
}
use of org.opengrok.indexer.util.ForbiddenSymlinkException in project OpenGrok by OpenGrok.
the class IndexDatabase method getDocument.
/**
* @param file File object of a file under source root
* @return Document object for the file or {@code null}
* @throws IOException on I/O error
* @throws ParseException on problem with building Query
*/
public static Document getDocument(File file) throws IOException, ParseException {
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
String path;
try {
path = env.getPathRelativeToSourceRoot(file);
} catch (ForbiddenSymlinkException e) {
LOGGER.log(Level.FINER, e.getMessage());
return null;
}
// Sanitize Windows path delimiters in order not to conflict with Lucene escape character.
path = path.replace("\\", "/");
try (IndexReader ireader = getIndexReader(path)) {
if (ireader == null) {
// No index, no document..
return null;
}
Document doc;
Query q = new QueryBuilder().setPath(path).build();
IndexSearcher searcher = new IndexSearcher(ireader);
Statistics stat = new Statistics();
TopDocs top = searcher.search(q, 1);
stat.report(LOGGER, Level.FINEST, "search via getDocument done", "search.latency", new String[] { "category", "getdocument", "outcome", top.totalHits.value == 0 ? "empty" : "success" });
if (top.totalHits.value == 0) {
// No hits, no document...
return null;
}
doc = searcher.doc(top.scoreDocs[0].doc);
String foundPath = doc.get(QueryBuilder.PATH);
// Only use the document if we found an exact match.
if (!path.equals(foundPath)) {
return null;
}
return doc;
}
}
use of org.opengrok.indexer.util.ForbiddenSymlinkException in project OpenGrok by OpenGrok.
the class HistoryGuru method getLastHistoryEntry.
/**
* @param file file to get the history entry for
* @param ui is the request coming from the UI
* @return last (newest) history entry for given file or null
* @throws HistoryException if history retrieval failed
*/
@Nullable
public HistoryEntry getLastHistoryEntry(File file, boolean ui) throws HistoryException {
final File dir = file.isDirectory() ? file : file.getParentFile();
final Repository repository = getRepository(dir);
if (!isRepoHistoryEligible(repository, file, ui)) {
return null;
}
History history;
try {
history = getHistoryFromCache(file, repository, false, false);
if (history != null) {
HistoryEntry lastHistoryEntry = history.getLastHistoryEntry();
if (lastHistoryEntry != null) {
LOGGER.log(Level.FINEST, "got latest history entry {0} for ''{1}'' from history cache", new Object[] { lastHistoryEntry, file });
return lastHistoryEntry;
}
}
} catch (ForbiddenSymlinkException e) {
LOGGER.log(Level.FINER, e.getMessage());
return null;
}
return repository.getLastHistoryEntry(file, ui);
}
use of org.opengrok.indexer.util.ForbiddenSymlinkException in project OpenGrok by OpenGrok.
the class HistoryGuru method addRepositories.
/**
* recursively search for repositories with a depth limit, add those found
* to the internally used map.
*
* @param files list of files to check if they contain a repository
* @param allowedNesting number of levels of nested repos to allow
* @param depth current depth - using global scanningDepth - one can limit
* this to improve scanning performance
* @param isNested a value indicating if a parent {@link Repository} was
* already found above the {@code files}
* @return collection of added repositories
*/
private Collection<RepositoryInfo> addRepositories(File[] files, int allowedNesting, int depth, boolean isNested) {
List<RepositoryInfo> repoList = new ArrayList<>();
PathAccepter pathAccepter = env.getPathAccepter();
for (File file : files) {
if (!file.isDirectory()) {
continue;
}
String path;
try {
path = file.getCanonicalPath();
Repository repository = null;
try {
repository = RepositoryFactory.getRepository(file, CommandTimeoutType.INDEXER, isNested);
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException e) {
LOGGER.log(Level.WARNING, "Could not create repository for '" + file + "', could not instantiate the repository.", e);
} catch (IllegalAccessException iae) {
LOGGER.log(Level.WARNING, "Could not create repository for '" + file + "', missing access rights.", iae);
continue;
} catch (ForbiddenSymlinkException e) {
LOGGER.log(Level.WARNING, "Could not create repository for ''{0}'': {1}", new Object[] { file, e.getMessage() });
continue;
}
if (repository == null) {
if (depth > env.getScanningDepth()) {
// we reached our search max depth, skip looking through the children
continue;
}
// Not a repository, search its sub-dirs.
if (pathAccepter.accept(file)) {
File[] subFiles = file.listFiles();
if (subFiles == null) {
LOGGER.log(Level.WARNING, "Failed to get sub directories for ''{0}'', " + "check access permissions.", file.getAbsolutePath());
} else {
// Recursive call to scan next depth
repoList.addAll(addRepositories(subFiles, allowedNesting, depth + 1, isNested));
}
}
} else {
LOGGER.log(Level.CONFIG, "Adding <{0}> repository: <{1}>", new Object[] { repository.getClass().getName(), path });
repoList.add(new RepositoryInfo(repository));
putRepository(repository);
if (allowedNesting > 0 && repository.supportsSubRepositories()) {
File[] subFiles = file.listFiles();
if (subFiles == null) {
LOGGER.log(Level.WARNING, "Failed to get sub directories for ''{0}'', check access permissions.", file.getAbsolutePath());
} else if (depth <= env.getScanningDepth()) {
// Search down to a limit -- if not: too much
// stat'ing for huge Mercurial repositories
repoList.addAll(addRepositories(subFiles, allowedNesting - 1, depth + 1, true));
}
}
}
} catch (IOException exp) {
LOGGER.log(Level.WARNING, "Failed to get canonical path for {0}: {1}", new Object[] { file.getAbsolutePath(), exp.getMessage() });
LOGGER.log(Level.WARNING, "Repository will be ignored...", exp);
}
}
return repoList;
}
use of org.opengrok.indexer.util.ForbiddenSymlinkException in project OpenGrok by OpenGrok.
the class RuntimeEnvironmentTest method testGetPathRelativeToSourceRoot.
/**
* Verify that getPathRelativeToSourceRoot() returns path relative to
* source root for both directories and symbolic links.
* @throws java.io.IOException I/O exception
* @throws ForbiddenSymlinkException forbidden symlink exception
*/
@Test
public void testGetPathRelativeToSourceRoot() throws IOException, ForbiddenSymlinkException {
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
// Create and set source root.
File sourceRoot = Files.createTempDirectory("src").toFile();
assertTrue(sourceRoot.exists());
assertTrue(sourceRoot.isDirectory());
env.setSourceRoot(sourceRoot.getPath());
// Create directory underneath source root and check.
String filename = "foo";
File file = new File(env.getSourceRootFile(), filename);
file.createNewFile();
assertTrue(file.exists());
assertEquals(File.separator + filename, env.getPathRelativeToSourceRoot(file));
// Create symlink underneath source root.
String symlinkName = "symlink";
Path realDir = Files.createTempDirectory("realdir");
File symlink = new File(sourceRoot, symlinkName);
Files.createSymbolicLink(symlink.toPath(), realDir);
assertTrue(symlink.exists());
env.setAllowedSymlinks(new HashSet<>());
ForbiddenSymlinkException expex = null;
try {
env.getPathRelativeToSourceRoot(symlink);
} catch (ForbiddenSymlinkException e) {
expex = e;
}
assertNotNull(expex, "getPathRelativeToSourceRoot() should have thrown " + "IOexception for symlink that is not allowed");
// Allow the symlink and retest.
env.setAllowedSymlinks(new HashSet<>(Arrays.asList(symlink.getPath())));
assertEquals(File.separator + symlinkName, env.getPathRelativeToSourceRoot(symlink));
// cleanup
IOUtils.removeRecursive(sourceRoot.toPath());
IOUtils.removeRecursive(realDir);
}
Aggregations