From aaf3c5154ea3b8a367266a7be7100ad7386a84b3 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sat, 25 Mar 2017 02:33:06 +0100 Subject: [PATCH] Only mark packfile invalid if exception signals permanent problem Add NoPackSignatureException and UnsupportedPackVersionException to explicitly mark permanent unrecoverable problems with a pack Assume problem with a pack is permanent only if we are sure the exception signals a non-transient problem we can't recover from: - AccessDeniedException: we lack permissions - CorruptObjectException: we detected corruption - EOFException: file ended unexpectedly - NoPackSignatureException: pack has no pack signature - NoSuchFileException: file has gone missing - PackMismatchException: pack no longer matches its index - UnpackException: unpacking failed - UnsupportedPackIndexVersionException: unsupported pack index version - UnsupportedPackVersionException: unsupported pack version Do not attempt to handle Errors since they are thrown for serious problems applications should not try to recover from. Change-Id: I2c416ce2b0e23255c4fb03a3f9a0ee237f7a484a Signed-off-by: Matthias Sohn --- org.eclipse.jgit/.settings/.api_filters | 11 +++ .../jgit/errors/NoPackSignatureException.java | 66 ++++++++++++++++++ .../UnsupportedPackIndexVersionException.java | 69 +++++++++++++++++++ .../UnsupportedPackVersionException.java | 69 +++++++++++++++++++ .../jgit/internal/storage/file/PackFile.java | 43 ++++++++---- .../jgit/internal/storage/file/PackIndex.java | 5 +- 6 files changed, 245 insertions(+), 18 deletions(-) create mode 100644 org.eclipse.jgit/.settings/.api_filters create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters new file mode 100644 index 000000000..2c27b051b --- /dev/null +++ b/org.eclipse.jgit/.settings/.api_filters @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java new file mode 100644 index 000000000..28e978897 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/NoPackSignatureException.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017, Matthias Sohn + * 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 java.io.IOException; + +/** + * Thrown when a PackFile is found not to contain the pack signature defined by + * git. + * + * @since 4.5 + */ +public class NoPackSignatureException extends IOException { + private static final long serialVersionUID = 1L; + + /** + * Construct an exception. + * + * @param why + * description of the type of error. + */ + public NoPackSignatureException(final String why) { + super(why); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java new file mode 100644 index 000000000..0b7ccf577 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackIndexVersionException.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017, Matthias Sohn + * 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 java.io.IOException; +import java.text.MessageFormat; + +import org.eclipse.jgit.internal.JGitText; + +/** + * Thrown when a PackIndex uses an index version not supported by JGit. + * + * @since 4.5 + */ +public class UnsupportedPackIndexVersionException extends IOException { + private static final long serialVersionUID = 1L; + + /** + * Construct an exception. + * + * @param version + * pack index version + */ + public UnsupportedPackIndexVersionException(final int version) { + super(MessageFormat.format(JGitText.get().unsupportedPackIndexVersion, + Integer.valueOf(version))); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java new file mode 100644 index 000000000..23611867b --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/UnsupportedPackVersionException.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017, Matthias Sohn + * 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 java.io.IOException; +import java.text.MessageFormat; + +import org.eclipse.jgit.internal.JGitText; + +/** + * Thrown when a PackFile uses a pack version not supported by JGit. + * + * @since 4.5 + */ +public class UnsupportedPackVersionException extends IOException { + private static final long serialVersionUID = 1L; + + /** + * Construct an exception. + * + * @param version + * pack version + */ + public UnsupportedPackVersionException(final long version) { + super(MessageFormat.format(JGitText.get().unsupportedPackVersion, + Long.valueOf(version))); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java index d33148152..038172f92 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java @@ -56,6 +56,8 @@ import java.io.InterruptedIOException; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel.MapMode; +import java.nio.file.AccessDeniedException; +import java.nio.file.NoSuchFileException; import java.text.MessageFormat; import java.util.Arrays; import java.util.Collections; @@ -70,9 +72,13 @@ import java.util.zip.Inflater; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.NoPackSignatureException; import org.eclipse.jgit.errors.PackInvalidException; import org.eclipse.jgit.errors.PackMismatchException; import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException; +import org.eclipse.jgit.errors.UnpackException; +import org.eclipse.jgit.errors.UnsupportedPackIndexVersionException; +import org.eclipse.jgit.errors.UnsupportedPackVersionException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.pack.BinaryDelta; import org.eclipse.jgit.internal.storage.pack.ObjectToPack; @@ -642,15 +648,19 @@ public class PackFile implements Iterable { // max open files) openFail(!packFile.exists()); throw fn; - } catch (IOException ioe) { + } catch (EOFException | AccessDeniedException | NoSuchFileException + | CorruptObjectException | NoPackSignatureException + | PackMismatchException | UnpackException + | UnsupportedPackIndexVersionException + | UnsupportedPackVersionException pe) { + // exceptions signaling permanent problems with a pack openFail(true); - throw ioe; - } catch (RuntimeException re) { - openFail(true); - throw re; - } catch (Error re) { - openFail(true); - throw re; + throw pe; + } catch (IOException | RuntimeException ge) { + // generic exceptions could be transient so we should not mark the + // pack invalid to avoid false MissingObjectExceptions + openFail(false); + throw ge; } } @@ -717,28 +727,31 @@ public class PackFile implements Iterable { fd.seek(0); fd.readFully(buf, 0, 12); - if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4) - throw new IOException(JGitText.get().notAPACKFile); + if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4) { + throw new NoPackSignatureException(JGitText.get().notAPACKFile); + } final long vers = NB.decodeUInt32(buf, 4); final long packCnt = NB.decodeUInt32(buf, 8); - if (vers != 2 && vers != 3) - throw new IOException(MessageFormat.format( - JGitText.get().unsupportedPackVersion, Long.valueOf(vers))); + if (vers != 2 && vers != 3) { + throw new UnsupportedPackVersionException(vers); + } - if (packCnt != idx.getObjectCount()) + if (packCnt != idx.getObjectCount()) { throw new PackMismatchException(MessageFormat.format( JGitText.get().packObjectCountMismatch, Long.valueOf(packCnt), Long.valueOf(idx.getObjectCount()), getPackFile())); + } fd.seek(length - 20); fd.readFully(buf, 0, 20); - if (!Arrays.equals(buf, packChecksum)) + if (!Arrays.equals(buf, packChecksum)) { throw new PackMismatchException(MessageFormat.format( JGitText.get().packObjectCountMismatch , ObjectId.fromRaw(buf).name() , ObjectId.fromRaw(idx.packChecksum).name() , getPackFile())); + } } ObjectLoader load(final WindowCursor curs, long pos) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java index f36bd4d70..5d4a30ff2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackIndex.java @@ -55,6 +55,7 @@ import java.util.Set; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.UnsupportedPackIndexVersionException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; @@ -138,9 +139,7 @@ public abstract class PackIndex case 2: return new PackIndexV2(fd); default: - throw new IOException(MessageFormat.format( - JGitText.get().unsupportedPackIndexVersion, - Integer.valueOf(v))); + throw new UnsupportedPackIndexVersionException(v); } } return new PackIndexV1(fd, hdr);