/* * ==================================================================== * 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.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; import java.util.Collections; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.internal.delta.SVNDeltaCombiner; 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.io.ISVNDeltaConsumer; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.core.io.diff.SVNDeltaProcessor; import org.tmatesoft.svn.core.io.diff.SVNDiffWindow; import org.tmatesoft.svn.util.SVNLogType; /** * @version 1.3 * @author TMate Software Ltd. */ public class FSDeltaConsumer implements ISVNDeltaConsumer { private String myBasePath; private FSTransactionRoot myTxnRoot; private FSFS myFSFS; private FSCommitter myCommitter; private SVNDeltaProcessor myDeltaProcessor; private FSOutputStream myTargetStream; private String myAuthor; private Collection myLockTokens; private SVNDeltaCombiner myDeltaCombiner; private boolean myIsComputeChecksum; private String myComputedChecksum; public FSDeltaConsumer(String basePath, FSTransactionRoot txnRoot, FSFS fsfs, FSCommitter committer, String author, Collection lockTokens) { myBasePath = basePath; myTxnRoot = txnRoot; myFSFS = fsfs; myCommitter = committer; myAuthor = author; myLockTokens = lockTokens != null ? lockTokens : Collections.EMPTY_LIST; } public void applyTextDelta(String path, String baseChecksum) throws SVNException { String fullPath = SVNPathUtil.getAbsolutePath(SVNPathUtil.append(myBasePath, path)); FSParentPath parentPath = myTxnRoot.openPath(fullPath, true, true); if ((myTxnRoot.getTxnFlags() & FSTransactionRoot.SVN_FS_TXN_CHECK_LOCKS) != 0) { myCommitter.allowLockedOperation(myFSFS, fullPath, myAuthor, myLockTokens, false, false); } myCommitter.makePathMutable(parentPath, fullPath); FSRevisionNode node = parentPath.getRevNode(); if (baseChecksum != null) { String md5HexChecksum = node.getFileMD5Checksum(); if (md5HexChecksum != null && !md5HexChecksum.equals(baseChecksum)) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.CHECKSUM_MISMATCH, "Base checksum mismatch on ''{0}'':\n expected: {1}\n actual: {2}\n", new Object[] { path, baseChecksum, md5HexChecksum }); SVNErrorManager.error(err, SVNLogType.FSFS); } } InputStream sourceStream = null; OutputStream targetStream = null; int dbFormat = myFSFS.getDBFormat(); try { sourceStream = FSInputStream.createDeltaStream(getCombiner(), node, myFSFS); targetStream = FSOutputStream.createStream(node, myTxnRoot, myTargetStream, dbFormat >= 2); if (myDeltaProcessor == null) { myDeltaProcessor = new SVNDeltaProcessor(); } myDeltaProcessor.applyTextDelta(sourceStream, targetStream, myIsComputeChecksum); } catch (SVNException svne) { SVNFileUtil.closeFile(sourceStream); throw svne; } finally { myTargetStream = (FSOutputStream) targetStream; } myCommitter.addChange(fullPath, node.getId(), FSPathChangeKind.FS_PATH_CHANGE_MODIFY, true, false, SVNRepository.INVALID_REVISION, null, SVNNodeKind.FILE); } public void applyText(String path) throws SVNException { String fullPath = SVNPathUtil.getAbsolutePath(SVNPathUtil.append(myBasePath, path)); FSParentPath parentPath = myTxnRoot.openPath(fullPath, true, true); if ((myTxnRoot.getTxnFlags() & FSTransactionRoot.SVN_FS_TXN_CHECK_LOCKS) != 0) { myCommitter.allowLockedOperation(myFSFS, fullPath, myAuthor, myLockTokens, false, false); } myCommitter.makePathMutable(parentPath, fullPath); FSRevisionNode node = parentPath.getRevNode(); InputStream sourceStream = null; OutputStream targetStream = null; int dbFormat = myFSFS.getDBFormat(); try { sourceStream = SVNFileUtil.DUMMY_IN; targetStream = FSOutputStream.createStream(node, myTxnRoot, myTargetStream, dbFormat >= 2); if (myDeltaProcessor == null) { myDeltaProcessor = new SVNDeltaProcessor(); } myDeltaProcessor.applyTextDelta(sourceStream, targetStream, false); } catch (SVNException svne) { throw svne; } finally { myTargetStream = (FSOutputStream) targetStream; } myCommitter.addChange(fullPath, node.getId(), FSPathChangeKind.FS_PATH_CHANGE_MODIFY, true, false, SVNRepository.INVALID_REVISION, null, SVNNodeKind.FILE); } public OutputStream textDeltaChunk(String path, SVNDiffWindow diffWindow) throws SVNException { return myDeltaProcessor.textDeltaChunk(diffWindow); } public void textDeltaEnd(String path) throws SVNException { myComputedChecksum = myDeltaProcessor.textDeltaEnd(); } public String getChecksum() { return myComputedChecksum; } public void close() throws SVNException { abort(); } public void abort() throws SVNException { if (myTargetStream != null) { try { myTargetStream.closeStreams(-1); } catch (IOException e) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e); SVNErrorManager.error(err, SVNLogType.FSFS); } } } public void setComputeChecksum(boolean computeChecksum) { myIsComputeChecksum = computeChecksum; } private SVNDeltaCombiner getCombiner() { if (myDeltaCombiner == null) { myDeltaCombiner = new SVNDeltaCombiner(); } else { myDeltaCombiner.reset(); } return myDeltaCombiner; } }