/* * ==================================================================== * Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.io.fs; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.Set; import org.tmatesoft.svn.core.ISVNDirEntryHandler; import org.tmatesoft.svn.core.ISVNLogEntryHandler; import org.tmatesoft.svn.core.SVNAuthenticationException; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNDirEntry; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNLock; import org.tmatesoft.svn.core.SVNMergeInfoInheritance; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.SVNProperties; import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.SVNRevisionProperty; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.BasicAuthenticationManager; import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; import org.tmatesoft.svn.core.auth.SVNAuthentication; import org.tmatesoft.svn.core.auth.SVNUserNameAuthentication; import org.tmatesoft.svn.core.internal.delta.SVNDeltaCombiner; import org.tmatesoft.svn.core.internal.util.SVNDate; import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc.SVNMergeInfoManager; import org.tmatesoft.svn.core.io.ISVNEditor; import org.tmatesoft.svn.core.io.ISVNFileRevisionHandler; import org.tmatesoft.svn.core.io.ISVNInheritedPropertiesHandler; import org.tmatesoft.svn.core.io.ISVNLocationEntryHandler; import org.tmatesoft.svn.core.io.ISVNLocationSegmentHandler; import org.tmatesoft.svn.core.io.ISVNLockHandler; import org.tmatesoft.svn.core.io.ISVNReplayHandler; import org.tmatesoft.svn.core.io.ISVNReporter; import org.tmatesoft.svn.core.io.ISVNReporterBaton; import org.tmatesoft.svn.core.io.ISVNSession; import org.tmatesoft.svn.core.io.ISVNWorkspaceMediator; import org.tmatesoft.svn.core.io.SVNCapability; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.util.SVNLogType; import org.tmatesoft.svn.util.Version; /** * @version 1.3 * @author TMate Software Ltd. */ public class FSRepository extends SVNRepository implements ISVNReporter { private File myReposRootDir; private FSUpdateContext myReporterContext; private FSLocationsFinder myLocationsFinder; private FSFS myFSFS; private SVNMergeInfoManager myMergeInfoManager; private FSLog myLogDriver; private boolean myIsHooksEnabled; protected FSRepository(SVNURL location, ISVNSession options) { super(location, options); setHooksEnabled(true); } public void setHooksEnabled(boolean enabled) { myIsHooksEnabled = enabled; if (getFSFS() != null) { getFSFS().setHooksEnabled(isHooksEnabled()); } } public boolean isHooksEnabled() { return myIsHooksEnabled; } public FSFS getFSFS() { return myFSFS; } public void testConnection() throws SVNException { // try to open and close a repository try { openRepository(); } finally { closeRepository(); } } public File getRepositoryRootDir() { return myReposRootDir; } public int getReposFormat() { return myFSFS.getReposFormat(); } public long getLatestRevision() throws SVNException { try { openRepository(); return myFSFS.getYoungestRevision(); } finally { closeRepository(); } } public long getDatedRevision(Date date) throws SVNException { if (date == null) { return getLatestRevision(); } try { openRepository(); return myFSFS.getDatedRevision(date); } finally { closeRepository(); } } public SVNProperties getRevisionProperties(long revision, SVNProperties properties) throws SVNException { assertValidRevision(revision); try { openRepository(); properties = properties == null ? new SVNProperties() : properties; properties.putAll(myFSFS.getRevisionProperties(revision)); } finally { closeRepository(); } return properties; } public void setRevisionPropertyValue(long revision, String propertyName, SVNPropertyValue propertyValue) throws SVNException { setRevisionPropertyValue(revision, propertyName, propertyValue, false); } public void setRevisionPropertyValue(long revision, String propertyName, SVNPropertyValue propertyValue, boolean bypassHooks) throws SVNException { setRevisionPropertyValue(revision, propertyName, propertyValue, bypassHooks, bypassHooks); } public void setRevisionPropertyValue(long revision, String propertyName, SVNPropertyValue propertyValue, boolean bypassPreRevpropHook, boolean bypassPostRevpropHook) throws SVNException { assertValidRevision(revision); try { openRepository(); FSRepositoryUtil.validateProperty(propertyName, propertyValue); String userName = getUserName(); SVNProperties revProps = myFSFS.getRevisionProperties(revision); SVNPropertyValue oldValue = revProps.getSVNPropertyValue(propertyName); String action = null; if (propertyValue == null) { action = FSHooks.REVPROP_DELETE; } else if (oldValue == null) { action = FSHooks.REVPROP_ADD; } else { action = FSHooks.REVPROP_MODIFY; } byte[] bytes = SVNPropertyValue.getPropertyAsBytes(propertyValue); if (isHooksEnabled() && FSHooks.isHooksEnabled() && !bypassPreRevpropHook) { FSHooks.runPreRevPropChangeHook(myReposRootDir, propertyName, bytes, userName, revision, action); } myFSFS.setRevisionProperty(revision, propertyName, propertyValue); if (isHooksEnabled() && FSHooks.isHooksEnabled() && !bypassPostRevpropHook) { FSHooks.runPostRevPropChangeHook(myReposRootDir, propertyName, bytes, userName, revision, action); } } finally { closeRepository(); } } public SVNPropertyValue getRevisionPropertyValue(long revision, String propertyName) throws SVNException { assertValidRevision(revision); if (propertyName == null) { return null; } try { openRepository(); return myFSFS.getRevisionProperties(revision).getSVNPropertyValue(propertyName); } finally { closeRepository(); } } public SVNNodeKind checkPath(String path, long revision) throws SVNException { try { openRepository(); if (!SVNRepository.isValidRevision(revision)) { revision = myFSFS.getYoungestRevision(); } String repositoryPath = getRepositoryPath(path); FSRevisionRoot root = myFSFS.createRevisionRoot(revision); return root.checkNodeKind(repositoryPath); } catch (SVNException e) { if (e.getErrorMessage().getErrorCode() == SVNErrorCode.FS_NOT_DIRECTORY) { return SVNNodeKind.NONE; } throw e; } finally { closeRepository(); } } public long getFile(String path, long revision, SVNProperties properties, OutputStream contents) throws SVNException { try { openRepository(); if (!SVNRepository.isValidRevision(revision)) { revision = myFSFS.getYoungestRevision(); } String repositoryPath = getRepositoryPath(path); FSRevisionRoot root = myFSFS.createRevisionRoot(revision); if (contents != null) { InputStream fileStream = null; try { fileStream = root.getFileStreamForPath(new SVNDeltaCombiner(), repositoryPath); FSRepositoryUtil.copy(fileStream, contents, getCanceller()); } finally { SVNFileUtil.closeFile(fileStream); } } if (properties != null) { FSRevisionNode revNode = root.getRevisionNode(repositoryPath); if (revNode.getFileMD5Checksum() != null) { properties.put(SVNProperty.CHECKSUM, revNode.getFileMD5Checksum()); } if (revision >= 0) { properties.put(SVNProperty.REVISION, Long.toString(revision)); } properties.putAll(collectProperties(revNode)); } return revision; } finally { closeRepository(); } } public long getDir(String path, long revision, SVNProperties properties, ISVNDirEntryHandler handler) throws SVNException { return getDir(path, revision, properties, SVNDirEntry.DIRENT_ALL, handler); } public SVNDirEntry getDir(String path, long revision, boolean includeCommitMessages, Collection entries) throws SVNException { try { openRepository(); if (!SVNRepository.isValidRevision(revision)) { revision = myFSFS.getYoungestRevision(); } String repositoryPath = getRepositoryPath(path); SVNURL parentURL = getLocation().appendPath(path, false); FSRevisionRoot root = myFSFS.createRevisionRoot(revision); FSRevisionNode parent = root.getRevisionNode(repositoryPath); if (entries != null) { entries.addAll(getDirEntries(parent, parentURL, SVNDirEntry.DIRENT_ALL)); } SVNDirEntry parentDirEntry = buildDirEntry(new FSEntry(parent.getId(), parent.getType(), ""), parentURL, parent, SVNDirEntry.DIRENT_ALL); return parentDirEntry; } finally { closeRepository(); } } public long getDir(String path, long revision, SVNProperties properties, int entryFields, ISVNDirEntryHandler handler) throws SVNException { try { openRepository(); if (!SVNRepository.isValidRevision(revision)) { revision = myFSFS.getYoungestRevision(); } String repositoryPath = getRepositoryPath(path); FSRevisionRoot root = myFSFS.createRevisionRoot(revision); FSRevisionNode parent = root.getRevisionNode(repositoryPath); if (handler != null) { SVNURL parentURL = getLocation().appendPath(path, false); Collection entriesCollection = getDirEntries(parent, parentURL, entryFields); Iterator entries = entriesCollection.iterator(); while (entries.hasNext()) { SVNDirEntry entry = (SVNDirEntry) entries.next(); handler.handleDirEntry(entry); } } if (properties != null) { properties.putAll(collectProperties(parent)); } return revision; } finally { closeRepository(); } } protected int getFileRevisionsImpl(String path, long startRevision, long endRevision, boolean includeMergedRevisions, ISVNFileRevisionHandler handler) throws SVNException { try { openRepository(); path = getRepositoryPath(path); long latestRevision = INVALID_REVISION; if (isInvalidRevision(startRevision)) { latestRevision = myFSFS.getYoungestRevision(); startRevision = latestRevision; } if (isInvalidRevision(endRevision)) { if (isInvalidRevision(latestRevision)) { latestRevision = myFSFS.getYoungestRevision(); } endRevision = latestRevision; } FSFileRevisionsFinder finder = new FSFileRevisionsFinder(myFSFS); int fileRevsNumber = finder.getFileRevisions(path, startRevision, endRevision, includeMergedRevisions, handler); return fileRevsNumber; } finally { closeRepository(); } } protected long logImpl(String[] targetPaths, long startRevision, long endRevision, boolean discoverChangedPaths, boolean strictNode, long limit, boolean includeMergedRevisions, String[] revPropNames, ISVNLogEntryHandler handler) throws SVNException { try { openRepository(); if (targetPaths == null || targetPaths.length == 0) { targetPaths = new String[] {""}; } String[] absPaths = new String[targetPaths.length]; for (int i = 0; i < targetPaths.length; i++) { absPaths[i] = getRepositoryPath(targetPaths[i]); } long youngestRev = myFSFS.getYoungestRevision(); if (isInvalidRevision(startRevision)) { startRevision = youngestRev; } if (isInvalidRevision(endRevision)) { endRevision = youngestRev; } long histStart = startRevision; long histEnd = endRevision; if (startRevision > youngestRev) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_NO_SUCH_REVISION, "No such revision {0}", String.valueOf(startRevision)); SVNErrorManager.error(err, SVNLogType.FSFS); } if (endRevision > youngestRev) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.FS_NO_SUCH_REVISION, "No such revision {0}", String.valueOf(endRevision)); SVNErrorManager.error(err, SVNLogType.FSFS); } boolean isDescendingOrder = startRevision >= endRevision; if (isDescendingOrder) { histStart = endRevision; histEnd = startRevision; } FSLog logDriver = getLogDriver(absPaths, limit, histStart, histEnd, isDescendingOrder, discoverChangedPaths, strictNode, includeMergedRevisions, revPropNames, handler); return logDriver.runLog(); } finally { closeRepository(); } } protected int getLocationsImpl(String path, long pegRevision, long[] revisions, ISVNLocationEntryHandler handler) throws SVNException { assertValidRevision(pegRevision); for (int i = 0; i < revisions.length; i++) { assertValidRevision(revisions[i]); } try { openRepository(); path = getRepositoryPath(path); FSLocationsFinder locationsFinder = getLocationsFinder(); return locationsFinder.traceNodeLocations(path, pegRevision, revisions, handler); } finally { closeRepository(); } } protected long getLocationSegmentsImpl(String path, long pegRevision, long startRevision, long endRevision, ISVNLocationSegmentHandler handler) throws SVNException { try { openRepository(); path = getRepositoryPath(path); FSLocationsFinder locationsFinder = getLocationsFinder(); return locationsFinder.getNodeLocationSegments(path, pegRevision, startRevision, endRevision, handler); } finally { closeRepository(); } } public void replay(long lowRevision, long highRevision, boolean sendDeltas, ISVNEditor editor) throws SVNException { try { openRepository(); FSRevisionRoot root = myFSFS.createRevisionRoot(highRevision); String basePath = getRepositoryPath(""); FSRepositoryUtil.replay(myFSFS, root, basePath, lowRevision, sendDeltas, editor); } finally { closeRepository(); } } public SVNDirEntry info(String path, long revision) throws SVNException { try { openRepository(); path = getRepositoryPath(path); if (FSRepository.isInvalidRevision(revision)) { revision = myFSFS.getYoungestRevision(); } FSRevisionRoot root = myFSFS.createRevisionRoot(revision); if (root.checkNodeKind(path) == SVNNodeKind.NONE) { return null; } FSRevisionNode revNode = root.getRevisionNode(path); String fullPath = getFullPath(path); String parentFullPath = "/".equals(path) ? fullPath : SVNPathUtil.removeTail(fullPath); SVNURL url = getLocation().setPath(parentFullPath, false); String name = "/".equals(path) ? "" : SVNPathUtil.tail(path); FSEntry fsEntry = new FSEntry(revNode.getId(), revNode.getType(), name); SVNDirEntry entry = buildDirEntry(fsEntry, url, revNode, SVNDirEntry.DIRENT_ALL); return entry; } finally { closeRepository(); } } public ISVNEditor getCommitEditor(String logMessage, Map locks, boolean keepLocks, ISVNWorkspaceMediator mediator) throws SVNException { try { openRepository(); } catch (SVNException svne) { closeRepository(); throw svne; } // fetch user name! String author = getUserName(); return new FSCommitEditor(getRepositoryPath(""), logMessage, author, locks, keepLocks, null, myFSFS, this); } public SVNLock getLock(String path) throws SVNException { try { openRepository(); path = getRepositoryPath(path); SVNLock lock = myFSFS.getLockHelper(path, false); return lock; } finally { closeRepository(); } } public SVNLock[] getLocks(String path) throws SVNException { try { openRepository(); path = getRepositoryPath(path); File digestFile = myFSFS.getDigestFileFromRepositoryPath(path); final ArrayList locks = new ArrayList(); ISVNLockHandler handler = new ISVNLockHandler() { public void handleLock(String path, SVNLock lock, SVNErrorMessage error) throws SVNException { locks.add(lock); } public void handleUnlock(String path, SVNLock lock, SVNErrorMessage error) throws SVNException { } }; myFSFS.walkDigestFiles(digestFile, handler, false); return (SVNLock[]) locks.toArray(new SVNLock[locks.size()]); } finally { closeRepository(); } } public void lock(Map pathsToRevisions, String comment, boolean force, ISVNLockHandler handler) throws SVNException { lock(pathsToRevisions, comment, force, false, handler); } public void lock(Map pathsToRevisions, String comment, boolean force, boolean isDAVComment, ISVNLockHandler handler) throws SVNException { try { openRepository(); for (Iterator paths = pathsToRevisions.keySet().iterator(); paths.hasNext();) { String path = (String) paths.next(); Long revision = (Long) pathsToRevisions.get(path); String reposPath = getRepositoryPath(path); long curRevision = (revision == null || isInvalidRevision(revision.longValue())) ? myFSFS.getYoungestRevision() : revision.longValue(); SVNLock lock = null; SVNErrorMessage error = null; try { lock = myFSFS.lockPath(reposPath, null, getUserName(), comment, null, curRevision, force, isDAVComment); } catch (SVNException svne) { error = svne.getErrorMessage(); if (!FSErrors.isLockError(error)) { throw svne; } } if (handler != null) { handler.handleLock(reposPath, lock, error); } } } finally { closeRepository(); } } public void unlock(Map pathToTokens, boolean force, ISVNLockHandler handler) throws SVNException { try { openRepository(); for (Iterator paths = pathToTokens.keySet().iterator(); paths.hasNext();) { String path = (String) paths.next(); String token = (String) pathToTokens.get(path); String reposPath = getRepositoryPath(path); SVNErrorMessage error = null; try { myFSFS.unlockPath(reposPath, token, getUserName(), force, true); } catch (SVNException svne) { error = svne.getErrorMessage(); if (!FSErrors.isUnlockError(error)) { throw svne; } } if (handler != null) { handler.handleUnlock(reposPath, new SVNLock(reposPath, token, null, null, null, null), error); } } } finally { closeRepository(); } } public void finishReport() throws SVNException { try { myReporterContext.drive(); } finally { myReporterContext.dispose(); } } public void abortReport() throws SVNException { if(myReporterContext != null){ myReporterContext.dispose(); } } public void closeSession() { } public static boolean isInvalidRevision(long revision) { return SVNRepository.isInvalidRevision(revision); } public static boolean isValidRevision(long revision) { return SVNRepository.isValidRevision(revision); } public void setPath(String path, String lockToken, long revision, boolean startEmpty) throws SVNException { setPath(path, lockToken, revision, SVNDepth.INFINITY, startEmpty); } public void deletePath(String path) throws SVNException { myReporterContext.writePathInfoToReportFile(path, null, null, SVNRepository.INVALID_REVISION, false, SVNDepth.INFINITY); } public void linkPath(SVNURL url, String path, String lockToken, long revision, boolean startEmpty) throws SVNException { linkPath(url, path, lockToken, revision, SVNDepth.INFINITY, startEmpty); } public void linkPath(SVNURL url, String path, String lockToken, long revision, SVNDepth depth, boolean startEmpty) throws SVNException { assertValidRevision(revision); if (depth == SVNDepth.EXCLUDE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.REPOS_BAD_ARGS, "Depth 'exclude' not supported for link"); SVNErrorManager.error(err, SVNLogType.FSFS); } SVNURL reposRootURL = getRepositoryRoot(false); if (url.toDecodedString().indexOf(reposRootURL.toDecodedString()) == -1) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "''{0}''\nis not the same repository as\n''{1}''", new Object[] { url, reposRootURL }); SVNErrorManager.error(err, SVNLogType.FSFS); } String reposLinkPath = url.toDecodedString().substring(reposRootURL.toDecodedString().length()); if ("".equals(reposLinkPath)) { reposLinkPath = "/"; } myReporterContext.writePathInfoToReportFile(path, reposLinkPath, lockToken, revision, startEmpty, depth); } public void setPath(String path, String lockToken, long revision, SVNDepth depth, boolean startEmpty) throws SVNException { assertValidRevision(revision); myReporterContext.writePathInfoToReportFile(path, null, lockToken, revision, startEmpty, depth); } public FSTranslateReporter beginReport(long revision, SVNURL url, String target, boolean ignoreAncestry, boolean sendTextDeltas, boolean sendCopyFromArgs, SVNDepth depth, ISVNEditor editor) throws SVNException { openRepository(); makeReporterContext(revision, target, url, depth, ignoreAncestry, sendTextDeltas, sendCopyFromArgs, editor); return new FSTranslateReporter(this); } public void update(long revision, String target, SVNDepth depth, boolean sendCopyFromArgs, ISVNReporterBaton reporter, ISVNEditor editor) throws SVNException { try { openRepository(); makeReporterContext(revision, target, null, depth, false, true, sendCopyFromArgs, editor); reporter.report(this); } finally { closeRepository(); } } public void update(SVNURL url, long revision, String target, SVNDepth depth, ISVNReporterBaton reporter, ISVNEditor editor) throws SVNException { try { openRepository(); makeReporterContext(revision, target, url, depth, true, true, false, editor); reporter.report(this); } finally { closeRepository(); } } public void diff(SVNURL url, long targetRevision, long revision, String target, boolean ignoreAncestry, SVNDepth depth, boolean getContents, ISVNReporterBaton reporter, ISVNEditor editor) throws SVNException { try { openRepository(); makeReporterContext(targetRevision, target, url, depth, ignoreAncestry, getContents, false, editor); reporter.report(this); } finally { closeRepository(); } } public void status(long revision, String target, SVNDepth depth, ISVNReporterBaton reporter, ISVNEditor editor) throws SVNException { try { openRepository(); makeReporterContext(revision, target, null, depth, false, false, false, editor); reporter.report(this); } finally { closeRepository(); } } public boolean hasCapability(SVNCapability capability) throws SVNException { if (capability == SVNCapability.DEPTH || capability == SVNCapability.LOG_REVPROPS || capability == SVNCapability.PARTIAL_REPLAY || capability == SVNCapability.COMMIT_REVPROPS) { return true; } else if (capability == SVNCapability.ATOMIC_REVPROPS) { return false; } else if (capability == SVNCapability.MERGE_INFO) { try { getMergeInfoImpl(new String[] { "" }, 0, SVNMergeInfoInheritance.EXPLICIT, false); } catch (SVNException svne) { SVNErrorCode code = svne.getErrorMessage().getErrorCode(); if (code == SVNErrorCode.UNSUPPORTED_FEATURE) { return false; } else if (code == SVNErrorCode.FS_NOT_FOUND) { return true; } throw svne; } return true; } else if (capability == SVNCapability.INHERITED_PROPS) { return true; } else if (capability == SVNCapability.EPHEMERAL_PROPS) { return true; } SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN_CAPABILITY, "Don''t know anything about capability ''{0}''", capability); SVNErrorManager.error(err, SVNLogType.FSFS); return false; } protected void getInheritedPropertiesImpl(String path, long revision, String propertyName, ISVNInheritedPropertiesHandler handler) throws SVNException { try { openRepository(); path = getRepositoryPath(path); String parentPath = path; final FSRevisionRoot root = myFSFS.createRevisionRoot(revision); while(!"/".equals(parentPath) && !"".equals(parentPath)) { parentPath = SVNPathUtil.removeTail(parentPath); if ("".equals(parentPath)) { parentPath = "/"; } final FSRevisionNode node = root.getRevisionNode(parentPath); final SVNProperties properties = myFSFS.getProperties(node); if (properties != null && handler != null && !properties.isEmpty()) { if (propertyName != null && properties.containsName(propertyName)) { final SVNProperties singleProperty = new SVNProperties(); singleProperty.put(propertyName, properties.getSVNPropertyValue(propertyName)); handler.handleInheritedProperites(parentPath, singleProperty); } else if (propertyName == null) { handler.handleInheritedProperites(parentPath, properties); } } } } finally { closeRepository(); } } void closeRepository() throws SVNException { if (myFSFS != null) { myFSFS.close(); } unlock(); } protected Map getMergeInfoImpl(String[] paths, long revision, SVNMergeInfoInheritance inherit, boolean includeDescendants) throws SVNException { try { openRepository(); if (!isValidRevision(revision)) { revision = myFSFS.getYoungestRevision(); } FSRevisionRoot root = myFSFS.createRevisionRoot(revision); String[] absPaths = new String[paths.length]; for (int i = 0; i < paths.length; i++) { absPaths[i] = getRepositoryPath(paths[i]); } SVNMergeInfoManager mergeInfoManager = getMergeInfoManager(); return mergeInfoManager.getMergeInfo(absPaths, root, inherit, includeDescendants); } finally { closeRepository(); } } protected ISVNEditor getCommitEditorInternal(Map locks, boolean keepLocks, SVNProperties revProps, ISVNWorkspaceMediator mediator) throws SVNException { try { openRepository(); } catch (SVNException svne) { closeRepository(); throw svne; } revProps = revProps == null ? new SVNProperties() : revProps; if (!revProps.containsName(SVNRevisionProperty.AUTHOR)) { revProps.put(SVNRevisionProperty.AUTHOR, getUserName()); } return new FSCommitEditor(getRepositoryPath(""), locks, keepLocks, null, myFSFS, this, revProps); } protected void replayRangeImpl(long startRevision, long endRevision, long lowRevision, boolean sendDeltas, ISVNReplayHandler handler) throws SVNException { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_NOT_IMPLEMENTED); SVNErrorManager.error(err, SVNLogType.FSFS); } protected long getDeletedRevisionImpl(String path, long pegRevision, long endRevision) throws SVNException { try { openRepository(); path = getRepositoryPath(path); return myFSFS.getDeletedRevision(path, pegRevision, endRevision); } finally { closeRepository(); } } private void openRepository() throws SVNException { try { openRepositoryRoot(); } catch (SVNException svne) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_LOCAL_REPOS_OPEN_FAILED, "Unable to open repository ''{0}''", getLocation().toString()); err.setChildErrorMessage(svne.getErrorMessage()); SVNErrorManager.error(err.wrap("Unable to open an ra_local session to URL"), SVNLogType.FSFS); } } private void openRepositoryRoot() throws SVNException { lock(); String hostName = getLocation().getHost(); boolean hasCustomHostName = !"".equals(hostName) && !"localhost".equalsIgnoreCase(hostName); if (!SVNFileUtil.isWindows && hasCustomHostName) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "Local URL ''{0}'' contains unsupported hostname", getLocation().toString()); SVNErrorManager.error(err, SVNLogType.FSFS); } String startPath = SVNEncodingUtil.uriDecode(getLocation().getURIEncodedPath()); String rootPath = FSFS.findRepositoryRoot(hasCustomHostName ? hostName : null, startPath); if (rootPath == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_LOCAL_REPOS_OPEN_FAILED, "Unable to open repository ''{0}''", getLocation().toString()); SVNErrorManager.error(err, SVNLogType.FSFS); } String dirPath = rootPath.replaceFirst("\\|", "\\:"); myReposRootDir = hasCustomHostName ? new File("\\\\" + hostName, dirPath).getAbsoluteFile() : new File(dirPath).getAbsoluteFile(); myFSFS = new FSFS(myReposRootDir); myFSFS.setHooksEnabled(isHooksEnabled()); myFSFS.open(); setRepositoryCredentials(myFSFS.getUUID(), getLocation().setPath(rootPath, false)); } private Collection getDirEntries(FSRevisionNode parent, SVNURL parentURL, int entryFields) throws SVNException { Map entries = parent.getDirEntries(myFSFS); Set keys = entries.keySet(); Iterator dirEntries = keys.iterator(); Collection dirEntriesList = new LinkedList(); while (dirEntries.hasNext()) { String name = (String) dirEntries.next(); FSEntry repEntry = (FSEntry) entries.get(name); if (repEntry != null) { dirEntriesList.add(buildDirEntry(repEntry, parentURL, null, entryFields)); } } return dirEntriesList; } private SVNProperties collectProperties(FSRevisionNode revNode) throws SVNException { SVNProperties properties = new SVNProperties(); SVNProperties versionedProps = revNode.getProperties(myFSFS); if (versionedProps != null && versionedProps.size() > 0) { properties.putAll(versionedProps); } SVNProperties metaprops = null; try { metaprops = myFSFS.compoundMetaProperties(revNode.getCreatedRevision()); } catch (SVNException svne) { // } if (metaprops != null && metaprops.size() > 0) { properties.putAll(metaprops); } return properties; } private SVNDirEntry buildDirEntry(FSEntry repEntry, SVNURL parentURL, FSRevisionNode entryNode, int entryFields) throws SVNException { entryNode = entryNode == null ? myFSFS.getRevisionNode(repEntry.getId()) : entryNode; SVNNodeKind kind = null; if ((entryFields & SVNDirEntry.DIRENT_KIND) != 0) { kind = repEntry.getType(); } long size = 0; if ((entryFields & SVNDirEntry.DIRENT_SIZE) != 0) { if (entryNode.getType() == SVNNodeKind.FILE) { size = entryNode.getFileLength(); } } boolean hasProps = false; if ((entryFields & SVNDirEntry.DIRENT_HAS_PROPERTIES) != 0) { SVNProperties props = entryNode.getProperties(myFSFS); hasProps = props != null && props.size() > 0; } String lastAuthor = null; String log = null; Date lastCommitDate = null; long revision = SVNRepository.INVALID_REVISION; if ((entryFields & SVNDirEntry.DIRENT_TIME) != 0 || (entryFields & SVNDirEntry.DIRENT_LAST_AUTHOR) != 0 || (entryFields & SVNDirEntry.DIRENT_CREATED_REVISION) != 0 || (entryFields & SVNDirEntry.DIRENT_COMMIT_MESSAGE) != 0) { revision = repEntry.getId().getRevision(); SVNProperties revProps = myFSFS.getRevisionProperties(repEntry.getId().getRevision()); if (revProps != null && revProps.size() > 0) { lastAuthor = revProps.getStringValue(SVNRevisionProperty.AUTHOR); log = revProps.getStringValue(SVNRevisionProperty.LOG); String timeString = revProps.getStringValue(SVNRevisionProperty.DATE); lastCommitDate = timeString != null ? SVNDate.parseDateString(timeString) : null; } } SVNURL entryURL = parentURL.appendPath(repEntry.getName(), false); SVNDirEntry dirEntry = new SVNDirEntry(entryURL, getRepositoryRoot(false), repEntry.getName(), kind, size, hasProps, revision, lastCommitDate, lastAuthor, log); dirEntry.setRelativePath(repEntry.getName()); return dirEntry; } private void makeReporterContext(long targetRevision, String target, SVNURL switchURL, SVNDepth depth, boolean ignoreAncestry, boolean textDeltas, boolean sendCopyFromArgs, ISVNEditor editor) throws SVNException { if (depth == SVNDepth.EXCLUDE) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.REPOS_BAD_ARGS, "Request depth 'exclude' not supported"); SVNErrorManager.error(err, SVNLogType.FSFS); } target = target == null ? "" : target; if (!isValidRevision(targetRevision)) { targetRevision = myFSFS.getYoungestRevision(); } String switchPath = null; if (switchURL != null) { SVNURL reposRootURL = getRepositoryRoot(false); if (switchURL.toDecodedString().indexOf(reposRootURL.toDecodedString()) == -1) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.RA_ILLEGAL_URL, "''{0}''\nis not the same repository as\n''{1}''", new Object[] { switchURL, getRepositoryRoot(false) }); SVNErrorManager.error(err, SVNLogType.FSFS); } switchPath = switchURL.toDecodedString().substring(reposRootURL.toDecodedString().length()); if ("".equals(switchPath)) { switchPath = "/"; } } String anchor = getRepositoryPath(""); String fullTargetPath = switchPath != null ? switchPath : SVNPathUtil.getAbsolutePath(SVNPathUtil.append(anchor, target)); if (myReporterContext == null) { myReporterContext = new FSUpdateContext(this, myFSFS, targetRevision, SVNFileUtil.createTempFile("report", ".tmp"), target, fullTargetPath, switchURL == null ? false : true, depth, ignoreAncestry, textDeltas, sendCopyFromArgs, editor); } else { myReporterContext.reset(this, myFSFS, targetRevision, SVNFileUtil.createTempFile("report", ".tmp"), target, fullTargetPath, switchURL == null ? false : true, depth, ignoreAncestry, textDeltas, sendCopyFromArgs, editor); } } private String getUserName() throws SVNException { if (getLocation().getUserInfo() != null && getLocation().getUserInfo().trim().length() > 0) { return getLocation().getUserInfo(); } if (getAuthenticationManager() != null) { try { String realm = getRepositoryUUID(true); ISVNAuthenticationManager authManager = getAuthenticationManager(); SVNAuthentication auth = authManager.getFirstAuthentication(ISVNAuthenticationManager.USERNAME, realm, getLocation()); while (auth != null) { String userName = auth.getUserName(); if (userName == null) { // anonymous. return null; } if ("".equals(userName.trim())) { userName = System.getProperty("user.name"); } auth = new SVNUserNameAuthentication(userName, auth.isStorageAllowed(), getLocation(), false); if (userName != null && !"".equals(userName.trim())) { BasicAuthenticationManager.acknowledgeAuthentication(true, ISVNAuthenticationManager.USERNAME, realm, null, auth, myLocation, authManager); return auth.getUserName(); } SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.AUTHN_CREDS_UNAVAILABLE, "Empty user name is not allowed"); BasicAuthenticationManager.acknowledgeAuthentication(false, ISVNAuthenticationManager.USERNAME, realm, err, auth, myLocation, authManager); auth = authManager.getNextAuthentication(ISVNAuthenticationManager.USERNAME, realm, getLocation()); } // auth manager returned null - that is cancellation. SVNErrorManager.cancel("Authentication cancelled", SVNLogType.FSFS); } catch (SVNCancelException e) { throw e; } catch (SVNAuthenticationException e) { // no more credentials, use system user name. } catch (SVNException e) { // generic error. throw e; } } // anonymous return null; } private FSLocationsFinder getLocationsFinder() { if (myLocationsFinder == null) { myLocationsFinder = new FSLocationsFinder(getFSFS()); } else { myLocationsFinder.reset(getFSFS()); } return myLocationsFinder; } private SVNMergeInfoManager getMergeInfoManager() { if (myMergeInfoManager == null) { myMergeInfoManager = new SVNMergeInfoManager(); } return myMergeInfoManager; } private FSLog getLogDriver(String[] absPaths, long limit, long histStart, long histEnd, boolean isDescendingOrder, boolean discoverChangedPaths, boolean strictNode, boolean includeMergedRevisions, String[] revPropNames, ISVNLogEntryHandler handler) { if (myLogDriver == null) { myLogDriver = new FSLog(myFSFS, absPaths, limit, histStart, histEnd, isDescendingOrder, discoverChangedPaths, strictNode, includeMergedRevisions, revPropNames, handler); } else { myLogDriver.reset(myFSFS, absPaths, limit, histStart, histEnd, isDescendingOrder, discoverChangedPaths, strictNode, includeMergedRevisions, revPropNames, handler); } return myLogDriver; } }