private FSInputStream(SVNDeltaCombiner combiner, FSRepresentation representation, FSFS owner) throws SVNException { myCombiner = combiner; myChunkIndex = 0; isChecksumFinalized = false; myHexChecksum = representation.getMD5HexDigest(); myOffset = 0; myLength = representation.getExpandedSize(); try { myDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException nsae) { SVNErrorMessage err = SVNErrorMessage.create( SVNErrorCode.IO_ERROR, "MD5 implementation not found: {0}", nsae.getLocalizedMessage()); SVNErrorManager.error(err, nsae, SVNLogType.FSFS); } try { buildRepresentationList(representation, myRepStateList, owner); } catch (SVNException svne) { /* * Something terrible has happened while building rep list, need to * close any files still opened */ close(); throw svne; } }
private static boolean areRepresentationsEqual( FSRevisionNode revNode1, FSRevisionNode revNode2, boolean forProperties) { if (revNode1 == revNode2) { return true; } else if (revNode1 == null || revNode2 == null) { return false; } return FSRepresentation.compareRepresentations( forProperties ? revNode1.getPropsRepresentation() : revNode1.getTextRepresentation(), forProperties ? revNode2.getPropsRepresentation() : revNode2.getTextRepresentation()); }
private FSRepresentationState buildRepresentationList( FSRepresentation firstRep, LinkedList result, FSFS owner) throws SVNException { FSFile file = null; FSRepresentation rep = new FSRepresentation(firstRep); ByteBuffer buffer = ByteBuffer.allocate(4); try { while (true) { file = owner.openAndSeekRepresentation(rep); FSRepresentationState repState = readRepresentationLine(file); repState.myFile = file; repState.myStart = file.position(); repState.myOffset = repState.myStart; repState.myEnd = repState.myStart + rep.getSize(); if (!repState.myIsDelta) { return repState; } buffer.clear(); int r = file.read(buffer); byte[] header = buffer.array(); if (!(header[0] == 'S' && header[1] == 'V' && header[2] == 'N' && r == 4)) { SVNErrorMessage err = SVNErrorMessage.create( SVNErrorCode.FS_CORRUPT, "Malformed svndiff data in representation"); SVNErrorManager.error(err, SVNLogType.FSFS); } repState.myVersion = header[3]; repState.myChunkIndex = 0; repState.myOffset += 4; /* * Push this rep onto the list. If it's self-compressed, we're * done. */ result.addLast(repState); if (repState.myIsDeltaVsEmpty) { return null; } rep.setRevision(repState.myBaseRevision); rep.setOffset(repState.myBaseOffset); rep.setSize(repState.myBaseLength); rep.setTxnId(null); } } catch (IOException ioe) { file.close(); SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage()); SVNErrorManager.error(err, ioe, SVNLogType.FSFS); } catch (SVNException svne) { file.close(); throw svne; } return null; }
private static long merge( FSFS owner, String targetPath, FSRevisionNode target, FSRevisionNode source, FSRevisionNode ancestor, FSTransactionRoot txnRoot, StringBuffer conflictPath) throws SVNException { FSID sourceId = source.getId(); FSID targetId = target.getId(); FSID ancestorId = ancestor.getId(); long mergeInfoIncrement = 0; if (ancestorId.equals(targetId)) { SVNErrorMessage err = SVNErrorMessage.create( SVNErrorCode.FS_GENERAL, "Bad merge; target ''{0}'' has id ''{1}'', same as ancestor", new Object[] {targetPath, targetId}); SVNErrorManager.error(err, SVNLogType.FSFS); } if (ancestorId.equals(sourceId) || sourceId.equals(targetId)) { return mergeInfoIncrement; } if (source.getType() != SVNNodeKind.DIR || target.getType() != SVNNodeKind.DIR || ancestor.getType() != SVNNodeKind.DIR) { SVNErrorManager.error(FSErrors.errorConflict(targetPath, conflictPath), SVNLogType.FSFS); } if (!FSRepresentation.compareRepresentations( target.getPropsRepresentation(), ancestor.getPropsRepresentation())) { SVNErrorManager.error(FSErrors.errorConflict(targetPath, conflictPath), SVNLogType.FSFS); } Map sourceEntries = source.getDirEntries(owner); Map targetEntries = target.getDirEntries(owner); Map ancestorEntries = ancestor.getDirEntries(owner); Set removedEntries = new SVNHashSet(); for (Iterator ancestorEntryNames = ancestorEntries.keySet().iterator(); ancestorEntryNames.hasNext(); ) { String ancestorEntryName = (String) ancestorEntryNames.next(); FSEntry ancestorEntry = (FSEntry) ancestorEntries.get(ancestorEntryName); FSEntry sourceEntry = removedEntries.contains(ancestorEntryName) ? null : (FSEntry) sourceEntries.get(ancestorEntryName); FSEntry targetEntry = (FSEntry) targetEntries.get(ancestorEntryName); if (sourceEntry != null && ancestorEntry.getId().equals(sourceEntry.getId())) { /* * No changes were made to this entry while the transaction was * in progress, so do nothing to the target. */ } else if (targetEntry != null && ancestorEntry.getId().equals(targetEntry.getId())) { if (owner.supportsMergeInfo()) { FSRevisionNode targetEntryNode = owner.getRevisionNode(targetEntry.getId()); long mergeInfoStart = targetEntryNode.getMergeInfoCount(); mergeInfoIncrement -= mergeInfoStart; } if (sourceEntry != null) { if (owner.supportsMergeInfo()) { FSRevisionNode sourceEntryNode = owner.getRevisionNode(sourceEntry.getId()); long mergeInfoEnd = sourceEntryNode.getMergeInfoCount(); mergeInfoIncrement += mergeInfoEnd; } txnRoot.setEntry(target, ancestorEntryName, sourceEntry.getId(), sourceEntry.getType()); } else { txnRoot.deleteEntry(target, ancestorEntryName); } } else { if (sourceEntry == null || targetEntry == null) { SVNErrorManager.error( FSErrors.errorConflict( SVNPathUtil.getAbsolutePath(SVNPathUtil.append(targetPath, ancestorEntryName)), conflictPath), SVNLogType.FSFS); } if (sourceEntry.getType() == SVNNodeKind.FILE || targetEntry.getType() == SVNNodeKind.FILE || ancestorEntry.getType() == SVNNodeKind.FILE) { SVNErrorManager.error( FSErrors.errorConflict( SVNPathUtil.getAbsolutePath(SVNPathUtil.append(targetPath, ancestorEntryName)), conflictPath), SVNLogType.FSFS); } if (!sourceEntry.getId().getNodeID().equals(ancestorEntry.getId().getNodeID()) || !sourceEntry.getId().getCopyID().equals(ancestorEntry.getId().getCopyID()) || !targetEntry.getId().getNodeID().equals(ancestorEntry.getId().getNodeID()) || !targetEntry.getId().getCopyID().equals(ancestorEntry.getId().getCopyID())) { SVNErrorManager.error( FSErrors.errorConflict( SVNPathUtil.getAbsolutePath(SVNPathUtil.append(targetPath, ancestorEntryName)), conflictPath), SVNLogType.FSFS); } FSRevisionNode sourceEntryNode = owner.getRevisionNode(sourceEntry.getId()); FSRevisionNode targetEntryNode = owner.getRevisionNode(targetEntry.getId()); FSRevisionNode ancestorEntryNode = owner.getRevisionNode(ancestorEntry.getId()); String childTargetPath = SVNPathUtil.getAbsolutePath(SVNPathUtil.append(targetPath, targetEntry.getName())); long subMergeInfoIncrement = merge( owner, childTargetPath, targetEntryNode, sourceEntryNode, ancestorEntryNode, txnRoot, conflictPath); if (owner.supportsMergeInfo()) { mergeInfoIncrement += subMergeInfoIncrement; } } removedEntries.add(ancestorEntryName); } for (Iterator sourceEntryNames = sourceEntries.keySet().iterator(); sourceEntryNames.hasNext(); ) { String sourceEntryName = (String) sourceEntryNames.next(); if (removedEntries.contains(sourceEntryName)) { continue; } FSEntry sourceEntry = (FSEntry) sourceEntries.get(sourceEntryName); FSEntry targetEntry = (FSEntry) targetEntries.get(sourceEntryName); if (targetEntry != null) { SVNErrorManager.error( FSErrors.errorConflict( SVNPathUtil.getAbsolutePath(SVNPathUtil.append(targetPath, targetEntry.getName())), conflictPath), SVNLogType.FSFS); } if (owner.supportsMergeInfo()) { FSRevisionNode sourceEntryNode = owner.getRevisionNode(sourceEntry.getId()); long mergeInfoCount = sourceEntryNode.getMergeInfoCount(); mergeInfoIncrement += mergeInfoCount; } txnRoot.setEntry(target, sourceEntry.getName(), sourceEntry.getId(), sourceEntry.getType()); } long sourceCount = source.getCount(); updateAncestry(owner, sourceId, targetId, targetPath, sourceCount); if (owner.supportsMergeInfo()) { txnRoot.incrementMergeInfoCount(target, mergeInfoIncrement); } return mergeInfoIncrement; }
public void close() throws IOException { if (myIsClosed) { return; } myIsClosed = true; final long truncateToSize[] = new long[] {-1}; try { ByteArrayInputStream target = new ByteArrayInputStream(myTextBuffer.toByteArray()); myDeltaGenerator.sendDelta(null, mySourceStream, mySourceOffset, target, this, false); final FSRepresentation rep = new FSRepresentation(); rep.setOffset(myRepOffset); long offset = myTargetFileOS.getPosition(); rep.setSize(offset - myDeltaStart); rep.setExpandedSize(myRepSize); rep.setTxnId(myRevNode.getId().getTxnID()); String uniqueSuffix = myTxnRoot.getNewTxnNodeId(); String uniquifier = rep.getTxnId() + '/' + uniqueSuffix; rep.setUniquifier(uniquifier); rep.setRevision(SVNRepository.INVALID_REVISION); rep.setMD5HexDigest(SVNFileUtil.toHexDigest(myMD5Digest)); rep.setSHA1HexDigest(SVNFileUtil.toHexDigest(mySHA1Digest)); FSFS fsfs = myTxnRoot.getOwner(); final IFSRepresentationCacheManager reposCacheManager = fsfs.getRepositoryCacheManager(); if (reposCacheManager != null) { try { reposCacheManager.runReadTransaction( new IFSSqlJetTransaction() { public void run() throws SVNException { final FSRepresentation oldRep = reposCacheManager.getRepresentationByHash(rep.getSHA1HexDigest()); if (oldRep != null) { oldRep.setUniquifier(rep.getUniquifier()); oldRep.setMD5HexDigest(rep.getMD5HexDigest()); truncateToSize[0] = myRepOffset; myRevNode.setTextRepresentation(oldRep); } } }); } catch (SVNException e) { // explicitly ignore. SVNDebugLog.getDefaultLog().logError(SVNLogType.FSFS, e); } } if (truncateToSize[0] < 0) { myTargetFileOS.write("ENDREP\n".getBytes("UTF-8")); myRevNode.setTextRepresentation(rep); } myRevNode.setIsFreshTxnRoot(false); fsfs.putTxnRevisionNode(myRevNode.getId(), myRevNode); } catch (SVNException svne) { throw new IOException(svne.getMessage()); } finally { closeStreams(truncateToSize[0]); try { myTxnLock.unlock(); } catch (SVNException e) { // } FSWriteLock.release(myTxnLock); } }
public static OutputStream createStream( FSRevisionNode revNode, FSTransactionRoot txnRoot, OutputStream dstStream, boolean compress) throws SVNException { if (revNode.getType() != SVNNodeKind.FILE) { SVNErrorMessage err = SVNErrorMessage.create( SVNErrorCode.FS_NOT_FILE, "Attempted to set textual contents of a *non*-file node"); SVNErrorManager.error(err, SVNLogType.FSFS); } if (!revNode.getId().isTxn()) { SVNErrorMessage err = SVNErrorMessage.create( SVNErrorCode.FS_NOT_MUTABLE, "Attempted to set textual contents of an immutable node"); SVNErrorManager.error(err, SVNLogType.FSFS); } OutputStream targetOS = null; InputStream sourceStream = null; long offset = -1; long deltaStart = -1; FSWriteLock txnLock = null; try { txnLock = FSWriteLock.getWriteLockForTxn(txnRoot.getTxnID(), txnRoot.getOwner()); txnLock.lock(); File targetFile = txnRoot.getTransactionProtoRevFile(); offset = targetFile.length(); targetOS = SVNFileUtil.openFileForWriting(targetFile, true); CountingOutputStream revWriter = new CountingOutputStream(targetOS, offset); FSRepresentation baseRep = revNode.chooseDeltaBase(txnRoot.getOwner()); sourceStream = FSInputStream.createDeltaStream(new SVNDeltaCombiner(), baseRep, txnRoot.getOwner()); String header; if (baseRep != null) { header = FSRepresentation.REP_DELTA + " " + baseRep.getRevision() + " " + baseRep.getOffset() + " " + baseRep.getSize() + "\n"; } else { header = FSRepresentation.REP_DELTA + "\n"; } revWriter.write(header.getBytes("UTF-8")); deltaStart = revWriter.getPosition(); if (dstStream instanceof FSOutputStream) { FSOutputStream fsOS = (FSOutputStream) dstStream; fsOS.reset( revNode, revWriter, targetFile, sourceStream, deltaStart, 0, offset, txnRoot, txnLock); return dstStream; } return new FSOutputStream( revNode, revWriter, targetFile, sourceStream, deltaStart, 0, offset, txnRoot, compress, txnLock); } catch (IOException ioe) { SVNFileUtil.closeFile(targetOS); SVNFileUtil.closeFile(sourceStream); txnLock.unlock(); FSWriteLock.release(txnLock); SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.IO_ERROR, ioe.getLocalizedMessage()); SVNErrorManager.error(err, ioe, SVNLogType.FSFS); } catch (SVNException svne) { if (txnLock != null) { txnLock.unlock(); FSWriteLock.release(txnLock); } SVNFileUtil.closeFile(targetOS); SVNFileUtil.closeFile(sourceStream); throw svne; } return null; }