Add dfs fsck implementation
JGit already had some fsck-like classes like ObjectChecker which can check for an individual object. The read-only FsckPackParser which will parse all objects within a pack file and check it with ObjectChecker. It will also check the pack index file against the object information from the pack parser. Change-Id: Ifd8e0d28eb68ff0b8edd2b51b2fa3a50a544c855 Signed-off-by: Zhen Chen <czhen@google.com>
This commit is contained in:
parent
82f68500c0
commit
2c2999643f
|
@ -258,4 +258,27 @@ public static Path writeLink(Repository db, String link,
|
|||
target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate byte arrays.
|
||||
*
|
||||
* @param b
|
||||
* byte arrays to combine together.
|
||||
* @return a single byte array that contains all bytes copied from input
|
||||
* byte arrays.
|
||||
* @since 4.9
|
||||
*/
|
||||
public static byte[] concat(byte[]... b) {
|
||||
int n = 0;
|
||||
for (byte[] a : b) {
|
||||
n += a.length;
|
||||
}
|
||||
|
||||
byte[] data = new byte[n];
|
||||
n = 0;
|
||||
for (byte[] a : b) {
|
||||
System.arraycopy(a, 0, data, n, a.length);
|
||||
n += a.length;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
|
|||
org.eclipse.jgit.ignore;version="[4.9.0,4.10.0)",
|
||||
org.eclipse.jgit.ignore.internal;version="[4.9.0,4.10.0)",
|
||||
org.eclipse.jgit.internal;version="[4.9.0,4.10.0)",
|
||||
org.eclipse.jgit.internal.fsck;version="[4.9.0,4.10.0)",
|
||||
org.eclipse.jgit.internal.storage.dfs;version="[4.9.0,4.10.0)",
|
||||
org.eclipse.jgit.internal.storage.file;version="[4.9.0,4.10.0)",
|
||||
org.eclipse.jgit.internal.storage.pack;version="[4.9.0,4.10.0)",
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2017, Google Inc.
|
||||
* and other copyright owners as documented in the project's IP log.
|
||||
*
|
||||
* This program and the accompanying materials are made available
|
||||
* under the terms of the Eclipse Distribution License v1.0 which
|
||||
* accompanies this distribution, is reproduced below, and is
|
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.eclipse.jgit.internal.storage.dfs;
|
||||
|
||||
import static org.eclipse.jgit.junit.JGitTestUtil.concat;
|
||||
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
|
||||
import static org.eclipse.jgit.lib.Constants.encodeASCII;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jgit.internal.fsck.FsckError;
|
||||
import org.eclipse.jgit.internal.fsck.FsckError.CorruptObject;
|
||||
import org.eclipse.jgit.junit.TestRepository;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectChecker.ErrorType;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DfsFsckTest {
|
||||
private TestRepository<InMemoryRepository> git;
|
||||
|
||||
private InMemoryRepository repo;
|
||||
|
||||
private ObjectInserter ins;
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
DfsRepositoryDescription desc = new DfsRepositoryDescription("test");
|
||||
git = new TestRepository<>(new InMemoryRepository(desc));
|
||||
repo = git.getRepository();
|
||||
ins = repo.newObjectInserter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHealthyRepo() throws Exception {
|
||||
RevCommit commit0 = git.commit().message("0").create();
|
||||
RevCommit commit1 = git.commit().message("1").parent(commit0).create();
|
||||
git.update("master", commit1);
|
||||
|
||||
DfsFsck fsck = new DfsFsck(repo);
|
||||
FsckError errors = fsck.check(null);
|
||||
|
||||
assertEquals(errors.getCorruptObjects().size(), 0);
|
||||
assertEquals(errors.getMissingObjects().size(), 0);
|
||||
assertEquals(errors.getCorruptIndices().size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitWithCorruptAuthor() throws Exception {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
|
||||
b.append("author b <b@c> <b@c> 0 +0000\n");
|
||||
b.append("committer <> 0 +0000\n");
|
||||
byte[] data = encodeASCII(b.toString());
|
||||
ObjectId id = ins.insert(Constants.OBJ_COMMIT, data);
|
||||
ins.flush();
|
||||
|
||||
DfsFsck fsck = new DfsFsck(repo);
|
||||
FsckError errors = fsck.check(null);
|
||||
|
||||
assertEquals(errors.getCorruptObjects().size(), 1);
|
||||
CorruptObject o = errors.getCorruptObjects().iterator().next();
|
||||
assertTrue(o.getId().equals(id));
|
||||
assertEquals(o.getErrorType(), ErrorType.BAD_DATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCommitWithoutTree() throws Exception {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("parent ");
|
||||
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
|
||||
b.append('\n');
|
||||
byte[] data = encodeASCII(b.toString());
|
||||
ObjectId id = ins.insert(Constants.OBJ_COMMIT, data);
|
||||
ins.flush();
|
||||
|
||||
DfsFsck fsck = new DfsFsck(repo);
|
||||
FsckError errors = fsck.check(null);
|
||||
|
||||
assertEquals(errors.getCorruptObjects().size(), 1);
|
||||
CorruptObject o = errors.getCorruptObjects().iterator().next();
|
||||
assertTrue(o.getId().equals(id));
|
||||
assertEquals(o.getErrorType(), ErrorType.MISSING_TREE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTagWithoutObject() throws Exception {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("type commit\n");
|
||||
b.append("tag test-tag\n");
|
||||
b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
|
||||
byte[] data = encodeASCII(b.toString());
|
||||
ObjectId id = ins.insert(Constants.OBJ_TAG, data);
|
||||
ins.flush();
|
||||
|
||||
DfsFsck fsck = new DfsFsck(repo);
|
||||
FsckError errors = fsck.check(null);
|
||||
|
||||
assertEquals(errors.getCorruptObjects().size(), 1);
|
||||
CorruptObject o = errors.getCorruptObjects().iterator().next();
|
||||
assertTrue(o.getId().equals(id));
|
||||
assertEquals(o.getErrorType(), ErrorType.MISSING_OBJECT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTreeWithNullSha() throws Exception {
|
||||
byte[] data = concat(encodeASCII("100644 A"), new byte[] { '\0' },
|
||||
new byte[OBJECT_ID_LENGTH]);
|
||||
ObjectId id = ins.insert(Constants.OBJ_TREE, data);
|
||||
ins.flush();
|
||||
|
||||
DfsFsck fsck = new DfsFsck(repo);
|
||||
FsckError errors = fsck.check(null);
|
||||
|
||||
assertEquals(errors.getCorruptObjects().size(), 1);
|
||||
CorruptObject o = errors.getCorruptObjects().iterator().next();
|
||||
assertTrue(o.getId().equals(id));
|
||||
assertEquals(o.getErrorType(), ErrorType.NULL_SHA1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleInvalidObjects() throws Exception {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("tree ");
|
||||
b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
|
||||
b.append('\n');
|
||||
b.append("parent ");
|
||||
b.append("\n");
|
||||
byte[] data = encodeASCII(b.toString());
|
||||
ObjectId id1 = ins.insert(Constants.OBJ_COMMIT, data);
|
||||
|
||||
b = new StringBuilder();
|
||||
b.append("100644");
|
||||
data = encodeASCII(b.toString());
|
||||
ObjectId id2 = ins.insert(Constants.OBJ_TREE, data);
|
||||
|
||||
ins.flush();
|
||||
|
||||
DfsFsck fsck = new DfsFsck(repo);
|
||||
FsckError errors = fsck.check(null);
|
||||
|
||||
assertEquals(errors.getCorruptObjects().size(), 2);
|
||||
for (CorruptObject o : errors.getCorruptObjects()) {
|
||||
if (o.getId().equals(id1)) {
|
||||
assertEquals(o.getErrorType(), ErrorType.BAD_PARENT_SHA1);
|
||||
} else if (o.getId().equals(id2)) {
|
||||
assertNull(o.getErrorType());
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@
|
|||
package org.eclipse.jgit.lib;
|
||||
|
||||
import static java.lang.Integer.valueOf;
|
||||
import static org.eclipse.jgit.junit.JGitTestUtil.concat;
|
||||
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
|
||||
import static org.eclipse.jgit.lib.Constants.OBJ_BAD;
|
||||
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
|
||||
|
@ -1054,20 +1055,7 @@ public void testInvalidTreeNameIsMacHFSGit3()
|
|||
checker.checkTree(data);
|
||||
}
|
||||
|
||||
private static byte[] concat(byte[]... b) {
|
||||
int n = 0;
|
||||
for (byte[] a : b) {
|
||||
n += a.length;
|
||||
}
|
||||
|
||||
byte[] data = new byte[n];
|
||||
n = 0;
|
||||
for (byte[] a : b) {
|
||||
System.arraycopy(a, 0, data, n, a.length);
|
||||
n += a.length;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd()
|
||||
|
|
|
@ -59,6 +59,7 @@ Export-Package: org.eclipse.jgit.annotations;version="4.9.0",
|
|||
org.eclipse.jgit.ignore;version="4.9.0",
|
||||
org.eclipse.jgit.ignore.internal;version="4.9.0";x-friends:="org.eclipse.jgit.test",
|
||||
org.eclipse.jgit.internal;version="4.9.0";x-friends:="org.eclipse.jgit.test,org.eclipse.jgit.http.test",
|
||||
org.eclipse.jgit.internal.fsck;version="4.9.0";x-friends:="org.eclipse.jgit.test",
|
||||
org.eclipse.jgit.internal.ketch;version="4.9.0";x-friends:="org.eclipse.jgit.junit,org.eclipse.jgit.test,org.eclipse.jgit.pgm",
|
||||
org.eclipse.jgit.internal.storage.dfs;version="4.9.0";
|
||||
x-friends:="org.eclipse.jgit.test,
|
||||
|
|
|
@ -409,8 +409,11 @@ mergeRecursiveReturnedNoCommit=Merge returned no commit:\n Depth {0}\n Head one
|
|||
mergeRecursiveTooManyMergeBasesFor = "More than {0} merge bases for:\n a {1}\n b {2} found:\n count {3}"
|
||||
messageAndTaggerNotAllowedInUnannotatedTags = Unannotated tags cannot have a message or tagger
|
||||
minutesAgo={0} minutes ago
|
||||
mismatchOffset=mismatch offset for object {0}
|
||||
mismatchCRC=mismatch CRC for object {0}
|
||||
missingAccesskey=Missing accesskey.
|
||||
missingConfigurationForKey=No value for key {0} found in configuration
|
||||
missingCRC=missing CRC for object {0}
|
||||
missingDeltaBase=delta base
|
||||
missingForwardImageInGITBinaryPatch=Missing forward-image in GIT binary patch
|
||||
missingObject=Missing {0} {1}
|
||||
|
@ -667,6 +670,7 @@ unknownDIRCVersion=Unknown DIRC version {0}
|
|||
unknownHost=unknown host
|
||||
unknownIndexVersionOrCorruptIndex=Unknown index version (or corrupt index): {0}
|
||||
unknownObject=unknown object
|
||||
unknownObjectInIndex=unknown object {0} found in index but not in pack file
|
||||
unknownObjectType=Unknown object type {0}.
|
||||
unknownObjectType2=unknown
|
||||
unknownRepositoryFormat=Unknown repository format
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (C) 2017, Google Inc.
|
||||
* and other copyright owners as documented in the project's IP log.
|
||||
*
|
||||
* This program and the accompanying materials are made available
|
||||
* under the terms of the Eclipse Distribution License v1.0 which
|
||||
* accompanies this distribution, is reproduced below, and is
|
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.eclipse.jgit.errors;
|
||||
|
||||
import org.eclipse.jgit.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Exception thrown when encounters a corrupt pack index file.
|
||||
*
|
||||
* @since 4.9
|
||||
*/
|
||||
public class CorruptPackIndexException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** The error type of a corrupt index file. */
|
||||
public enum ErrorType {
|
||||
/** Offset does not match index in pack file. */
|
||||
MISMATCH_OFFSET,
|
||||
/** CRC does not match CRC of the object data in pack file. */
|
||||
MISMATCH_CRC,
|
||||
/** CRC is not present in index file. */
|
||||
MISSING_CRC,
|
||||
/** Object in pack is not present in index file. */
|
||||
MISSING_OBJ,
|
||||
/** Object in index file is not present in pack file. */
|
||||
UNKNOWN_OBJ,
|
||||
}
|
||||
|
||||
private ErrorType errorType;
|
||||
|
||||
/**
|
||||
* Report a specific error condition discovered in an index file.
|
||||
*
|
||||
* @param message
|
||||
* the error message.
|
||||
* @param errorType
|
||||
* the error type of corruption.
|
||||
*/
|
||||
public CorruptPackIndexException(String message, ErrorType errorType) {
|
||||
super(message);
|
||||
this.errorType = errorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific the reason of the corrupt index file.
|
||||
*
|
||||
* @return error condition or null.
|
||||
*/
|
||||
@Nullable
|
||||
public ErrorType getErrorType() {
|
||||
return errorType;
|
||||
}
|
||||
}
|
|
@ -468,8 +468,11 @@ public static JGitText get() {
|
|||
/***/ public String mergeRecursiveTooManyMergeBasesFor;
|
||||
/***/ public String messageAndTaggerNotAllowedInUnannotatedTags;
|
||||
/***/ public String minutesAgo;
|
||||
/***/ public String mismatchOffset;
|
||||
/***/ public String mismatchCRC;
|
||||
/***/ public String missingAccesskey;
|
||||
/***/ public String missingConfigurationForKey;
|
||||
/***/ public String missingCRC;
|
||||
/***/ public String missingDeltaBase;
|
||||
/***/ public String missingForwardImageInGITBinaryPatch;
|
||||
/***/ public String missingObject;
|
||||
|
@ -726,6 +729,7 @@ public static JGitText get() {
|
|||
/***/ public String unknownHost;
|
||||
/***/ public String unknownIndexVersionOrCorruptIndex;
|
||||
/***/ public String unknownObject;
|
||||
/***/ public String unknownObjectInIndex;
|
||||
/***/ public String unknownObjectType;
|
||||
/***/ public String unknownObjectType2;
|
||||
/***/ public String unknownRepositoryFormat;
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2017, Google Inc.
|
||||
* and other copyright owners as documented in the project's IP log.
|
||||
*
|
||||
* This program and the accompanying materials are made available
|
||||
* under the terms of the Eclipse Distribution License v1.0 which
|
||||
* accompanies this distribution, is reproduced below, and is
|
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.eclipse.jgit.internal.fsck;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jgit.annotations.Nullable;
|
||||
import org.eclipse.jgit.errors.CorruptPackIndexException;
|
||||
import org.eclipse.jgit.errors.CorruptPackIndexException.ErrorType;
|
||||
import org.eclipse.jgit.lib.ObjectChecker;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
|
||||
/** Holds all fsck errors of a git repository. */
|
||||
public class FsckError {
|
||||
/** Represents a corrupt object. */
|
||||
public static class CorruptObject {
|
||||
final ObjectId id;
|
||||
|
||||
final int type;
|
||||
|
||||
ObjectChecker.ErrorType errorType;
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* the object identifier.
|
||||
* @param type
|
||||
* type of the object.
|
||||
*/
|
||||
public CorruptObject(ObjectId id, int type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
void setErrorType(ObjectChecker.ErrorType errorType) {
|
||||
this.errorType = errorType;
|
||||
}
|
||||
|
||||
/** @return identifier of the object. */
|
||||
public ObjectId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/** @return type of the object. */
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/** @return error type of the corruption. */
|
||||
@Nullable
|
||||
public ObjectChecker.ErrorType getErrorType() {
|
||||
return errorType;
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents a corrupt pack index file. */
|
||||
public static class CorruptIndex {
|
||||
String fileName;
|
||||
|
||||
CorruptPackIndexException.ErrorType errorType;
|
||||
|
||||
/**
|
||||
* @param fileName
|
||||
* the file name of the pack index.
|
||||
* @param errorType
|
||||
* the type of error as reported in
|
||||
* {@link CorruptPackIndexException}.
|
||||
*/
|
||||
public CorruptIndex(String fileName, ErrorType errorType) {
|
||||
this.fileName = fileName;
|
||||
this.errorType = errorType;
|
||||
}
|
||||
|
||||
/** @return the file name of the index file. */
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/** @return the error type of the corruption. */
|
||||
public ErrorType getErrorType() {
|
||||
return errorType;
|
||||
}
|
||||
}
|
||||
|
||||
private final Set<CorruptObject> corruptObjects = new HashSet<>();
|
||||
|
||||
private final Set<ObjectId> missingObjects = new HashSet<>();
|
||||
|
||||
private final Set<CorruptIndex> corruptIndices = new HashSet<>();
|
||||
|
||||
/** @return corrupt objects from all pack files. */
|
||||
public Set<CorruptObject> getCorruptObjects() {
|
||||
return corruptObjects;
|
||||
}
|
||||
|
||||
/** @return missing objects that should present in pack files. */
|
||||
public Set<ObjectId> getMissingObjects() {
|
||||
return missingObjects;
|
||||
}
|
||||
|
||||
/** @return corrupt index files associated with the packs. */
|
||||
public Set<CorruptIndex> getCorruptIndices() {
|
||||
return corruptIndices;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright (C) 2017, Google Inc.
|
||||
* and other copyright owners as documented in the project's IP log.
|
||||
*
|
||||
* This program and the accompanying materials are made available
|
||||
* under the terms of the Eclipse Distribution License v1.0 which
|
||||
* accompanies this distribution, is reproduced below, and is
|
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.eclipse.jgit.internal.fsck;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import org.eclipse.jgit.errors.CorruptObjectException;
|
||||
import org.eclipse.jgit.errors.CorruptPackIndexException;
|
||||
import org.eclipse.jgit.errors.CorruptPackIndexException.ErrorType;
|
||||
import org.eclipse.jgit.errors.MissingObjectException;
|
||||
import org.eclipse.jgit.internal.JGitText;
|
||||
import org.eclipse.jgit.internal.fsck.FsckError.CorruptObject;
|
||||
import org.eclipse.jgit.internal.storage.dfs.ReadableChannel;
|
||||
import org.eclipse.jgit.internal.storage.file.PackIndex;
|
||||
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
|
||||
import org.eclipse.jgit.lib.AnyObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectChecker;
|
||||
import org.eclipse.jgit.lib.ObjectDatabase;
|
||||
import org.eclipse.jgit.transport.PackParser;
|
||||
import org.eclipse.jgit.transport.PackedObjectInfo;
|
||||
|
||||
/** A read-only pack parser for object validity checking. */
|
||||
public class FsckPackParser extends PackParser {
|
||||
private final CRC32 crc;
|
||||
|
||||
private final ReadableChannel channel;
|
||||
|
||||
private final Set<CorruptObject> corruptObjects = new HashSet<>();
|
||||
|
||||
private long expectedObjectCount = -1L;
|
||||
|
||||
private long offset;
|
||||
|
||||
private int blockSize;
|
||||
|
||||
/**
|
||||
* @param db
|
||||
* the object database which stores repository's data.
|
||||
* @param channel
|
||||
* readable channel of the pack file.
|
||||
*/
|
||||
public FsckPackParser(ObjectDatabase db, ReadableChannel channel) {
|
||||
super(db, Channels.newInputStream(channel));
|
||||
this.channel = channel;
|
||||
setCheckObjectCollisions(false);
|
||||
this.crc = new CRC32();
|
||||
this.blockSize = channel.blockSize() > 0 ? channel.blockSize() : 65536;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPackHeader(long objCnt) throws IOException {
|
||||
if (expectedObjectCount >= 0) {
|
||||
// Some DFS pack files don't contain the correct object count, e.g.
|
||||
// INSERT/RECEIVE packs don't always contain the correct object
|
||||
// count in their headers. Overwrite the expected object count
|
||||
// after parsing the pack header.
|
||||
setExpectedObjectCount(expectedObjectCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBeginWholeObject(long streamPosition, int type,
|
||||
long inflatedSize) throws IOException {
|
||||
crc.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onObjectHeader(Source src, byte[] raw, int pos, int len)
|
||||
throws IOException {
|
||||
crc.update(raw, pos, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onObjectData(Source src, byte[] raw, int pos, int len)
|
||||
throws IOException {
|
||||
crc.update(raw, pos, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEndWholeObject(PackedObjectInfo info) throws IOException {
|
||||
info.setCRC((int) crc.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBeginOfsDelta(long deltaStreamPosition,
|
||||
long baseStreamPosition, long inflatedSize) throws IOException {
|
||||
crc.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBeginRefDelta(long deltaStreamPosition, AnyObjectId baseId,
|
||||
long inflatedSize) throws IOException {
|
||||
crc.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UnresolvedDelta onEndDelta() throws IOException {
|
||||
UnresolvedDelta delta = new UnresolvedDelta();
|
||||
delta.setCRC((int) crc.getValue());
|
||||
return delta;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInflatedObjectData(PackedObjectInfo obj, int typeCode,
|
||||
byte[] data) throws IOException {
|
||||
// FsckPackParser ignores this event.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verifySafeObject(final AnyObjectId id, final int type,
|
||||
final byte[] data) {
|
||||
try {
|
||||
super.verifySafeObject(id, type, data);
|
||||
} catch (CorruptObjectException e) {
|
||||
// catch the exception and continue parse the pack file
|
||||
CorruptObject o = new CorruptObject(id.toObjectId(), type);
|
||||
if (e.getErrorType() != null) {
|
||||
o.setErrorType(e.getErrorType());
|
||||
}
|
||||
corruptObjects.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPackFooter(byte[] hash) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onAppendBase(int typeCode, byte[] data,
|
||||
PackedObjectInfo info) throws IOException {
|
||||
// Do nothing.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEndThinPack() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectTypeAndSize seekDatabase(PackedObjectInfo obj,
|
||||
ObjectTypeAndSize info) throws IOException {
|
||||
crc.reset();
|
||||
offset = obj.getOffset();
|
||||
return readObjectHeader(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectTypeAndSize seekDatabase(UnresolvedDelta delta,
|
||||
ObjectTypeAndSize info) throws IOException {
|
||||
crc.reset();
|
||||
offset = delta.getOffset();
|
||||
return readObjectHeader(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int readDatabase(byte[] dst, int pos, int cnt)
|
||||
throws IOException {
|
||||
// read from input instead of database.
|
||||
int n = read(offset, dst, pos, cnt);
|
||||
if (n > 0) {
|
||||
offset += n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int read(long channelPosition, byte[] dst, int pos, int cnt)
|
||||
throws IOException {
|
||||
long block = channelPosition / blockSize;
|
||||
byte[] bytes = readFromChannel(block);
|
||||
if (bytes == null) {
|
||||
return -1;
|
||||
}
|
||||
int offset = (int) (channelPosition - block * blockSize);
|
||||
int bytesToCopy = Math.min(cnt, bytes.length - offset);
|
||||
if (bytesToCopy < 1) {
|
||||
return -1;
|
||||
}
|
||||
System.arraycopy(bytes, offset, dst, pos, bytesToCopy);
|
||||
return bytesToCopy;
|
||||
}
|
||||
|
||||
private byte[] readFromChannel(long block) throws IOException {
|
||||
channel.position(block * blockSize);
|
||||
ByteBuffer buf = ByteBuffer.allocate(blockSize);
|
||||
int totalBytesRead = 0;
|
||||
while (totalBytesRead < blockSize) {
|
||||
int bytesRead = channel.read(buf);
|
||||
if (bytesRead == -1) {
|
||||
if (totalBytesRead == 0) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.copyOf(buf.array(), totalBytesRead);
|
||||
}
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkCRC(int oldCRC) {
|
||||
return oldCRC == (int) crc.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStoreStream(byte[] raw, int pos, int len)
|
||||
throws IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return corrupt objects that reported by {@link ObjectChecker}.
|
||||
*/
|
||||
public Set<CorruptObject> getCorruptObjects() {
|
||||
return corruptObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the existing index file with all objects from the pack.
|
||||
*
|
||||
* @param entries
|
||||
* all the entries that are expected in the index file
|
||||
* @param idx
|
||||
* index file associate with the pack
|
||||
* @throws CorruptPackIndexException
|
||||
* when the index file is corrupt.
|
||||
*/
|
||||
public void verifyIndex(List<PackedObjectInfo> entries, PackIndex idx)
|
||||
throws CorruptPackIndexException {
|
||||
Set<String> all = new HashSet<>();
|
||||
for (PackedObjectInfo entry : entries) {
|
||||
all.add(entry.getName());
|
||||
long offset = idx.findOffset(entry);
|
||||
if (offset == -1) {
|
||||
throw new CorruptPackIndexException(
|
||||
MessageFormat.format(JGitText.get().missingObject,
|
||||
entry.getType(), entry.getName()),
|
||||
ErrorType.MISSING_OBJ);
|
||||
} else if (offset != entry.getOffset()) {
|
||||
throw new CorruptPackIndexException(MessageFormat
|
||||
.format(JGitText.get().mismatchOffset, entry.getName()),
|
||||
ErrorType.MISMATCH_OFFSET);
|
||||
}
|
||||
|
||||
try {
|
||||
if (idx.hasCRC32Support()
|
||||
&& (int) idx.findCRC32(entry) != entry.getCRC()) {
|
||||
throw new CorruptPackIndexException(
|
||||
MessageFormat.format(JGitText.get().mismatchCRC,
|
||||
entry.getName()),
|
||||
ErrorType.MISMATCH_CRC);
|
||||
}
|
||||
} catch (MissingObjectException e) {
|
||||
throw new CorruptPackIndexException(MessageFormat
|
||||
.format(JGitText.get().missingCRC, entry.getName()),
|
||||
ErrorType.MISSING_CRC);
|
||||
}
|
||||
}
|
||||
|
||||
for (MutableEntry entry : idx) {
|
||||
if (!all.contains(entry.name())) {
|
||||
throw new CorruptPackIndexException(MessageFormat.format(
|
||||
JGitText.get().unknownObjectInIndex, entry.name()),
|
||||
ErrorType.UNKNOWN_OBJ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object count for overwriting the expected object count from pack
|
||||
* header.
|
||||
*
|
||||
* @param expectedObjectCount
|
||||
* the actual expected object count.
|
||||
*/
|
||||
public void overwriteObjectCount(long expectedObjectCount) {
|
||||
this.expectedObjectCount = expectedObjectCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/**
|
||||
* Git fsck support.
|
||||
*/
|
||||
package org.eclipse.jgit.internal.fsck;
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (C) 2017, Google Inc.
|
||||
* and other copyright owners as documented in the project's IP log.
|
||||
*
|
||||
* This program and the accompanying materials are made available
|
||||
* under the terms of the Eclipse Distribution License v1.0 which
|
||||
* accompanies this distribution, is reproduced below, and is
|
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||
* names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.eclipse.jgit.internal.storage.dfs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jgit.errors.CorruptPackIndexException;
|
||||
import org.eclipse.jgit.errors.MissingObjectException;
|
||||
import org.eclipse.jgit.internal.fsck.FsckError;
|
||||
import org.eclipse.jgit.internal.fsck.FsckError.CorruptIndex;
|
||||
import org.eclipse.jgit.internal.fsck.FsckPackParser;
|
||||
import org.eclipse.jgit.internal.storage.pack.PackExt;
|
||||
import org.eclipse.jgit.lib.ObjectChecker;
|
||||
import org.eclipse.jgit.lib.ProgressMonitor;
|
||||
import org.eclipse.jgit.transport.PackedObjectInfo;
|
||||
|
||||
/** Verify the validity and connectivity of a DFS repository. */
|
||||
public class DfsFsck {
|
||||
private final DfsRepository repo;
|
||||
|
||||
private final DfsObjDatabase objdb;
|
||||
|
||||
private final DfsReader ctx;
|
||||
|
||||
private ObjectChecker objChecker = new ObjectChecker();
|
||||
|
||||
/**
|
||||
* Initialize DFS fsck.
|
||||
*
|
||||
* @param repository
|
||||
* the dfs repository to check.
|
||||
*/
|
||||
public DfsFsck(DfsRepository repository) {
|
||||
repo = repository;
|
||||
objdb = repo.getObjectDatabase();
|
||||
ctx = objdb.newReader();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify the integrity and connectivity of all objects in the object
|
||||
* database.
|
||||
*
|
||||
* @param pm
|
||||
* callback to provide progress feedback during the check.
|
||||
* @return all errors about the repository.
|
||||
* @throws IOException
|
||||
* if encounters IO errors during the process.
|
||||
*/
|
||||
public FsckError check(ProgressMonitor pm) throws IOException {
|
||||
FsckError errors = new FsckError();
|
||||
try {
|
||||
for (DfsPackFile pack : objdb.getPacks()) {
|
||||
DfsPackDescription packDesc = pack.getPackDescription();
|
||||
try (ReadableChannel channel = repo.getObjectDatabase()
|
||||
.openFile(packDesc, PackExt.PACK)) {
|
||||
List<PackedObjectInfo> objectsInPack;
|
||||
FsckPackParser parser = new FsckPackParser(
|
||||
repo.getObjectDatabase(), channel);
|
||||
parser.setObjectChecker(objChecker);
|
||||
parser.overwriteObjectCount(packDesc.getObjectCount());
|
||||
parser.parse(pm);
|
||||
errors.getCorruptObjects()
|
||||
.addAll(parser.getCorruptObjects());
|
||||
objectsInPack = parser.getSortedObjectList(null);
|
||||
parser.verifyIndex(objectsInPack, pack.getPackIndex(ctx));
|
||||
} catch (MissingObjectException e) {
|
||||
errors.getMissingObjects().add(e.getObjectId());
|
||||
} catch (CorruptPackIndexException e) {
|
||||
errors.getCorruptIndices().add(new CorruptIndex(
|
||||
pack.getPackDescription()
|
||||
.getFileName(PackExt.INDEX),
|
||||
e.getErrorType()));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ctx.close();
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a customized object checker instead of the default one. Caller can
|
||||
* specify a skip list to ignore some errors.
|
||||
*
|
||||
* @param objChecker
|
||||
* A customized object checker.
|
||||
*/
|
||||
public void setObjectChecker(ObjectChecker objChecker) {
|
||||
this.objChecker = objChecker;
|
||||
}
|
||||
}
|
|
@ -550,29 +550,7 @@ public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
|
|||
}
|
||||
|
||||
if (deltaCount > 0) {
|
||||
if (resolving instanceof BatchingProgressMonitor) {
|
||||
((BatchingProgressMonitor) resolving).setDelayStart(
|
||||
1000,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
resolving.beginTask(JGitText.get().resolvingDeltas, deltaCount);
|
||||
resolveDeltas(resolving);
|
||||
if (entryCount < expectedObjectCount) {
|
||||
if (!isAllowThin()) {
|
||||
throw new IOException(MessageFormat.format(
|
||||
JGitText.get().packHasUnresolvedDeltas,
|
||||
Long.valueOf(expectedObjectCount - entryCount)));
|
||||
}
|
||||
|
||||
resolveDeltasWithExternalBases(resolving);
|
||||
|
||||
if (entryCount < expectedObjectCount) {
|
||||
throw new IOException(MessageFormat.format(
|
||||
JGitText.get().packHasUnresolvedDeltas,
|
||||
Long.valueOf(expectedObjectCount - entryCount)));
|
||||
}
|
||||
}
|
||||
resolving.endTask();
|
||||
processDeltas(resolving);
|
||||
}
|
||||
|
||||
packDigest = null;
|
||||
|
@ -595,6 +573,31 @@ public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving)
|
|||
return null; // By default there is no locking.
|
||||
}
|
||||
|
||||
private void processDeltas(ProgressMonitor resolving) throws IOException {
|
||||
if (resolving instanceof BatchingProgressMonitor) {
|
||||
((BatchingProgressMonitor) resolving).setDelayStart(1000,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
resolving.beginTask(JGitText.get().resolvingDeltas, deltaCount);
|
||||
resolveDeltas(resolving);
|
||||
if (entryCount < expectedObjectCount) {
|
||||
if (!isAllowThin()) {
|
||||
throw new IOException(MessageFormat.format(
|
||||
JGitText.get().packHasUnresolvedDeltas,
|
||||
Long.valueOf(expectedObjectCount - entryCount)));
|
||||
}
|
||||
|
||||
resolveDeltasWithExternalBases(resolving);
|
||||
|
||||
if (entryCount < expectedObjectCount) {
|
||||
throw new IOException(MessageFormat.format(
|
||||
JGitText.get().packHasUnresolvedDeltas,
|
||||
Long.valueOf(expectedObjectCount - entryCount)));
|
||||
}
|
||||
}
|
||||
resolving.endTask();
|
||||
}
|
||||
|
||||
private void resolveDeltas(final ProgressMonitor progress)
|
||||
throws IOException {
|
||||
final int last = entryCount;
|
||||
|
@ -684,6 +687,7 @@ private void resolveDeltas(DeltaVisit visit, final int type,
|
|||
PackedObjectInfo oe;
|
||||
oe = newInfo(tempObjectId, visit.delta, visit.parent.id);
|
||||
oe.setOffset(visit.delta.position);
|
||||
oe.setType(type);
|
||||
onInflatedObjectData(oe, type, visit.data);
|
||||
addObjectAndTrack(oe);
|
||||
visit.id = oe;
|
||||
|
@ -854,10 +858,9 @@ private void resolveDeltasWithExternalBases(final ProgressMonitor progress)
|
|||
visit.id = baseId;
|
||||
final int typeCode = ldr.getType();
|
||||
final PackedObjectInfo oe = newInfo(baseId, null, null);
|
||||
|
||||
oe.setType(typeCode);
|
||||
if (onAppendBase(typeCode, visit.data, oe))
|
||||
entries[entryCount++] = oe;
|
||||
|
||||
visit.nextChild = firstChildOf(oe);
|
||||
resolveDeltas(visit.next(), typeCode,
|
||||
new ObjectTypeAndSize(), progress);
|
||||
|
@ -1059,6 +1062,7 @@ private void whole(final long pos, final int type, final long sz)
|
|||
|
||||
PackedObjectInfo obj = newInfo(tempObjectId, null, null);
|
||||
obj.setOffset(pos);
|
||||
obj.setType(type);
|
||||
onEndWholeObject(obj);
|
||||
if (data != null)
|
||||
onInflatedObjectData(obj, type, data);
|
||||
|
@ -1069,8 +1073,21 @@ private void whole(final long pos, final int type, final long sz)
|
|||
}
|
||||
}
|
||||
|
||||
private void verifySafeObject(final AnyObjectId id, final int type,
|
||||
final byte[] data) throws IOException {
|
||||
/**
|
||||
* Verify the integrity of the object.
|
||||
*
|
||||
* @param id
|
||||
* identity of the object to be checked.
|
||||
* @param type
|
||||
* the type of the object.
|
||||
* @param data
|
||||
* raw content of the object.
|
||||
* @throws CorruptObjectException
|
||||
* @since 4.9
|
||||
*
|
||||
*/
|
||||
protected void verifySafeObject(final AnyObjectId id, final int type,
|
||||
final byte[] data) throws CorruptObjectException {
|
||||
if (objCheck != null) {
|
||||
try {
|
||||
objCheck.check(id, type, data);
|
||||
|
@ -1078,11 +1095,11 @@ private void verifySafeObject(final AnyObjectId id, final int type,
|
|||
if (e.getErrorType() != null) {
|
||||
throw e;
|
||||
}
|
||||
throw new CorruptObjectException(MessageFormat.format(
|
||||
JGitText.get().invalidObject,
|
||||
Constants.typeString(type),
|
||||
id.name(),
|
||||
e.getMessage()), e);
|
||||
throw new CorruptObjectException(
|
||||
MessageFormat.format(JGitText.get().invalidObject,
|
||||
Constants.typeString(type), id.name(),
|
||||
e.getMessage()),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
package org.eclipse.jgit.transport;
|
||||
|
||||
import org.eclipse.jgit.lib.AnyObjectId;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectIdOwnerMap;
|
||||
|
||||
/**
|
||||
|
@ -59,6 +60,8 @@ public class PackedObjectInfo extends ObjectIdOwnerMap.Entry {
|
|||
|
||||
private int crc;
|
||||
|
||||
private int type = Constants.OBJ_BAD;
|
||||
|
||||
PackedObjectInfo(final long headerOffset, final int packedCRC,
|
||||
final AnyObjectId id) {
|
||||
super(id);
|
||||
|
@ -112,4 +115,24 @@ public int getCRC() {
|
|||
public void setCRC(final int crc) {
|
||||
this.crc = crc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the object type. The default type is OBJ_BAD, which is considered
|
||||
* as unknown or invalid type.
|
||||
* @since 4.9
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the object type if applicable.
|
||||
*
|
||||
* @param type
|
||||
* the object type.
|
||||
* @since 4.9
|
||||
*/
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue