/* * ==================================================================== * 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 org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.io.SVNLocationEntry; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.util.SVNLogType; /** * @version 1.3 * @author TMate Software Ltd. */ public class FSNodeHistory { private SVNLocationEntry myHistoryEntry; private SVNLocationEntry mySearchResumeEntry; private boolean myIsInteresting; private FSFS myFSFS; public FSNodeHistory(SVNLocationEntry newHistoryEntry, boolean interesting, SVNLocationEntry newSearchResumeEntry, FSFS owner) { myHistoryEntry = newHistoryEntry; mySearchResumeEntry = newSearchResumeEntry; myIsInteresting = interesting; myFSFS = owner; } public SVNLocationEntry getHistoryEntry() { return myHistoryEntry; } public static SVNLocationEntry findYoungestCopyroot(File reposRootDir, FSParentPath parPath) throws SVNException { SVNLocationEntry parentEntry = null; if (parPath.getParent() != null) { parentEntry = findYoungestCopyroot(reposRootDir, parPath.getParent()); } SVNLocationEntry myEntry = new SVNLocationEntry(parPath.getRevNode().getCopyRootRevision(), parPath.getRevNode().getCopyRootPath()); if (parentEntry != null) { if (myEntry.getRevision() >= parentEntry.getRevision()) { return myEntry; } return parentEntry; } return myEntry; } public static boolean checkAncestryOfPegPath(String fsPath, long pegRev, long futureRev, FSFS owner) throws SVNException { FSRevisionRoot root = owner.createRevisionRoot(futureRev); FSNodeHistory history = root.getNodeHistory(fsPath);//getNodeHistory(root, fsPath); fsPath = null; SVNLocationEntry currentHistory = null; while (true) { history = history.getPreviousHistory(true); if (history == null) { break; } currentHistory = new SVNLocationEntry(history.getHistoryEntry().getRevision(), history.getHistoryEntry().getPath()); if (fsPath == null) { fsPath = currentHistory.getPath(); } if (currentHistory.getRevision() <= pegRev) { break; } } if (fsPath == null) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "FATAL error occurred while checking ancestry of peg path"); SVNErrorManager.error(err, SVNLogType.FSFS); } return (history != null && (fsPath.equals(currentHistory.getPath()))); } private FSNodeHistory historyPrev(boolean crossCopies) throws SVNException { String path = myHistoryEntry.getPath(); long revision = myHistoryEntry.getRevision(); boolean reported = myIsInteresting; if (mySearchResumeEntry != null && mySearchResumeEntry.getPath() != null && FSRepository.isValidRevision(mySearchResumeEntry.getRevision())) { reported = false; if (!crossCopies) { return null; } path = mySearchResumeEntry.getPath(); revision = mySearchResumeEntry.getRevision(); } FSRevisionRoot root = myFSFS.createRevisionRoot(revision); FSParentPath parentPath = root.openPath(path, true, true); FSRevisionNode revNode = parentPath.getRevNode(); SVNLocationEntry commitEntry = new SVNLocationEntry(revNode.getCreatedRevision(), revNode.getCreatedPath()); FSNodeHistory prevHist = null; if (revision == commitEntry.getRevision()) { if (!reported) { prevHist = new FSNodeHistory(commitEntry, true, new SVNLocationEntry(SVNRepository.INVALID_REVISION, null), myFSFS); return prevHist; } FSID predId = revNode.getPredecessorId(); if (predId == null) { return prevHist; } revNode = myFSFS.getRevisionNode(predId); commitEntry = new SVNLocationEntry(revNode.getCreatedRevision(), revNode.getCreatedPath()); } SVNLocationEntry copyrootEntry = findYoungestCopyroot(myFSFS.getRepositoryRoot(), parentPath); SVNLocationEntry srcEntry = new SVNLocationEntry(SVNRepository.INVALID_REVISION, null); long dstRev = SVNRepository.INVALID_REVISION; if (copyrootEntry.getRevision() > commitEntry.getRevision()) { FSRevisionRoot copyrootRoot = myFSFS.createRevisionRoot(copyrootEntry.getRevision()); revNode = copyrootRoot.getRevisionNode(copyrootEntry.getPath()); String copyDst = revNode.getCreatedPath(); String reminder = null; if (path.equals(copyDst)) { reminder = ""; } else { reminder = SVNPathUtil.getPathAsChild(copyDst, path); } if (reminder != null) { String copySrc = revNode.getCopyFromPath(); srcEntry = new SVNLocationEntry(revNode.getCopyFromRevision(), SVNPathUtil.getAbsolutePath(SVNPathUtil.append(copySrc, reminder))); dstRev = copyrootEntry.getRevision(); } } if (srcEntry.getPath() != null && FSRepository.isValidRevision(srcEntry.getRevision())) { boolean retry = false; if ((dstRev == revision) && reported) { retry = true; } return new FSNodeHistory(new SVNLocationEntry(dstRev, path), retry ? false : true, new SVNLocationEntry(srcEntry.getRevision(), srcEntry.getPath()), myFSFS); } return new FSNodeHistory(commitEntry, true, new SVNLocationEntry(SVNRepository.INVALID_REVISION, null), myFSFS); } public FSNodeHistory getPreviousHistory(boolean crossCopies) throws SVNException { if ("/".equals(myHistoryEntry.getPath())) { if (!myIsInteresting) { return new FSNodeHistory(new SVNLocationEntry(myHistoryEntry.getRevision(), "/"), true, new SVNLocationEntry(SVNRepository.INVALID_REVISION, null), myFSFS); } else if (myHistoryEntry.getRevision() > 0) { return new FSNodeHistory(new SVNLocationEntry(myHistoryEntry.getRevision() - 1, "/"), true, new SVNLocationEntry(SVNRepository.INVALID_REVISION, null), myFSFS); } } else { FSNodeHistory prevHist = this; while (true) { prevHist = prevHist.historyPrev(crossCopies); if (prevHist == null) { return null; } if (prevHist.myIsInteresting) { return prevHist; } } } return null; } }