]> source.dussan.org Git - jgit.git/commitdiff
Partial support for index file format "3". 46/1446/4
authorMarc Strapetz <marc.strapetz@syntevo.com>
Tue, 31 Aug 2010 11:26:29 +0000 (13:26 +0200)
committerShawn O. Pearce <spearce@spearce.org>
Tue, 31 Aug 2010 19:08:09 +0000 (12:08 -0700)
Extended flags are processed and available via DirCacheEntry's
new isSkipWorkTree() and isIntentToAdd() methods.  "resolve-undo"
information is completely ignored since its an optional extension.

Change-Id: Ie6e9c6784c9f265ca3c013c6dc0e6bd29d3b7233

org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTree [new file with mode: 0644]
org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCache.java
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java

diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTree b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTree
new file mode 100644 (file)
index 0000000..4cbd703
Binary files /dev/null and b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index.v3.skipWorkTree differ
index f37d04004950b21268e1048002c96b6074aeba8d..f5cdfae2951509d0e2b398a270bc49c045ac5a40 100644 (file)
 package org.eclipse.jgit.dircache;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -59,6 +61,7 @@ import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.JGitTestUtil;
 
 public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
@@ -179,6 +182,35 @@ public class DirCacheCGitCompatabilityTest extends LocalDiskRepositoryTestCase {
                }
        }
 
+       public void testReadWriteV3() throws Exception {
+               final File file = pathOf("gitgit.index.v3.skipWorkTree");
+               final DirCache dc = new DirCache(file, FS.DETECTED);
+               dc.read();
+
+               assertEquals(7, dc.getEntryCount());
+               assertV3TreeEntry(0, "dir1/file1.txt", false, false, dc);
+               assertV3TreeEntry(1, "dir2/file2.txt", true, false, dc);
+               assertV3TreeEntry(2, "dir3/file3.txt", false, false, dc);
+               assertV3TreeEntry(3, "dir3/file3a.txt", true, false, dc);
+               assertV3TreeEntry(4, "dir4/file4.txt", true, false, dc);
+               assertV3TreeEntry(5, "dir4/file4a.txt", false, false, dc);
+               assertV3TreeEntry(6, "file.txt", true, false, dc);
+
+               final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+               dc.writeTo(bos);
+               final byte[] indexBytes = bos.toByteArray();
+               final byte[] expectedBytes = IO.readFully(file);
+               assertTrue(Arrays.equals(expectedBytes, indexBytes));
+       }
+
+       private static void assertV3TreeEntry(int indexPosition, String path,
+                       boolean skipWorkTree, boolean intentToAdd, DirCache dc) {
+               final DirCacheEntry entry = dc.getEntry(indexPosition);
+               assertEquals(path, entry.getPathString());
+               assertEquals(skipWorkTree, entry.isSkipWorkTree());
+               assertEquals(intentToAdd, entry.isIntentToAdd());
+       }
+
        private File pathOf(final String name) {
                return JGitTestUtil.getTestResourceFile(name);
        }
index 14c0ba0fc8c25bc917198a54b1ae2cc1f35f9501..5bebd18b30de100e8f532bc4f6e57f1903226544 100644 (file)
@@ -2,6 +2,7 @@ DIRCChecksumMismatch=DIRC checksum mismatch
 DIRCExtensionIsTooLargeAt=DIRC extension {0} is too large at {1} bytes.
 DIRCExtensionNotSupportedByThisVersion=DIRC extension {0} not supported by this version.
 DIRCHasTooManyEntries=DIRC has too many entries.
+DIRCUnrecognizedExtendedFlags=Unrecognized extended flags: {0}
 JRELacksMD5Implementation=JRE lacks MD5 implementation
 URINotSupported=URI not supported: {0}
 URLNotFound={0} not found
index ea40fe8847405ac80f092499aaaa10df41bc8625..927fa7c52824e8bbca40b78341ebe61a3ad7a94b 100644 (file)
@@ -62,6 +62,7 @@ public class JGitText extends TranslationBundle {
        /***/ public String DIRCExtensionIsTooLargeAt;
        /***/ public String DIRCExtensionNotSupportedByThisVersion;
        /***/ public String DIRCHasTooManyEntries;
+       /***/ public String DIRCUnrecognizedExtendedFlags;
        /***/ public String JRELacksMD5Implementation;
        /***/ public String URINotSupported;
        /***/ public String URLNotFound;
index a117c8df21fc466254a5989d8863bcb2e732d55c..143447c8d6b1871e4dcd976b925239817ba35f83 100644 (file)
@@ -91,8 +91,6 @@ public class DirCache {
 
        private static final int EXT_TREE = 0x54524545 /* 'TREE' */;
 
-       private static final int INFO_LEN = DirCacheEntry.INFO_LEN;
-
        private static final DirCacheEntry[] NO_ENTRIES = {};
 
        static final Comparator<DirCacheEntry> ENT_CMP = new Comparator<DirCacheEntry>() {
@@ -322,7 +320,7 @@ public class DirCache {
                tree = null;
        }
 
-       private void readFrom(final FileInputStream inStream) throws IOException,
+       private void readFrom(final InputStream inStream) throws IOException,
                        CorruptObjectException {
                final BufferedInputStream in = new BufferedInputStream(inStream);
                final MessageDigest md = Constants.newMessageDigest();
@@ -335,7 +333,10 @@ public class DirCache {
                if (!is_DIRC(hdr))
                        throw new CorruptObjectException(JGitText.get().notADIRCFile);
                final int ver = NB.decodeInt32(hdr, 4);
-               if (ver != 2)
+               boolean extended = false;
+               if (ver == 3)
+                       extended = true;
+               else if (ver != 2)
                        throw new CorruptObjectException(MessageFormat.format(JGitText.get().unknownDIRCVersion, ver));
                entryCnt = NB.decodeInt32(hdr, 8);
                if (entryCnt < 0)
@@ -343,10 +344,13 @@ public class DirCache {
 
                // Load the individual file entries.
                //
-               final byte[] infos = new byte[INFO_LEN * entryCnt];
+               final int infoLength = DirCacheEntry.getMaximumInfoLength(extended);
+               final byte[] infos = new byte[infoLength * entryCnt];
                sortedEntries = new DirCacheEntry[entryCnt];
+
+               final MutableInteger infoAt = new MutableInteger();
                for (int i = 0; i < entryCnt; i++)
-                       sortedEntries[i] = new DirCacheEntry(infos, i * INFO_LEN, in, md);
+                       sortedEntries[i] = new DirCacheEntry(infos, infoAt, in, md);
                lastModified = liveFile.lastModified();
 
                // After the file entries are index extensions, and then a footer.
@@ -484,15 +488,19 @@ public class DirCache {
                }
        }
 
-       private void writeTo(final OutputStream os) throws IOException {
+       void writeTo(final OutputStream os) throws IOException {
                final MessageDigest foot = Constants.newMessageDigest();
                final DigestOutputStream dos = new DigestOutputStream(os, foot);
 
+               boolean extended = false;
+               for (int i = 0; i < entryCnt; i++)
+                       extended |= sortedEntries[i].isExtended();
+
                // Write the header.
                //
                final byte[] tmp = new byte[128];
                System.arraycopy(SIG_DIRC, 0, tmp, 0, SIG_DIRC.length);
-               NB.encodeInt32(tmp, 4, /* version */2);
+               NB.encodeInt32(tmp, 4, extended ? 3 : 2);
                NB.encodeInt32(tmp, 8, entryCnt);
                dos.write(tmp, 0, 12);
 
index 308d4d168ffa72cf8f151bc04c3fb084b94da584..defab97a08621a472c41e363620f2431df341288 100644 (file)
@@ -62,6 +62,7 @@ import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.util.IO;
+import org.eclipse.jgit.util.MutableInteger;
 import org.eclipse.jgit.util.NB;
 
 /**
@@ -108,12 +109,19 @@ public class DirCacheEntry {
        private static final int P_OBJECTID = 40;
 
        private static final int P_FLAGS = 60;
+       private static final int P_FLAGS2 = 62;
 
        /** Mask applied to data in {@link #P_FLAGS} to get the name length. */
        private static final int NAME_MASK = 0xfff;
 
-       static final int INFO_LEN = 62;
+       private static final int INTENT_TO_ADD = 0x20000000;
+       private static final int SKIP_WORKTREE = 0x40000000;
+       private static final int EXTENDED_FLAGS = (INTENT_TO_ADD | SKIP_WORKTREE);
 
+       private static final int INFO_LEN = 62;
+       private static final int INFO_LEN_EXTENDED = 64;
+
+       private static final int EXTENDED = 0x40;
        private static final int ASSUME_VALID = 0x80;
 
        /** In-core flag signaling that the entry should be considered as modified. */
@@ -131,13 +139,26 @@ public class DirCacheEntry {
        /** Flags which are never stored to disk. */
        private byte inCoreFlags;
 
-       DirCacheEntry(final byte[] sharedInfo, final int infoAt,
+       DirCacheEntry(final byte[] sharedInfo, final MutableInteger infoAt,
                        final InputStream in, final MessageDigest md) throws IOException {
                info = sharedInfo;
-               infoOffset = infoAt;
+               infoOffset = infoAt.value;
 
                IO.readFully(in, info, infoOffset, INFO_LEN);
-               md.update(info, infoOffset, INFO_LEN);
+
+               final int len;
+               if (isExtended()) {
+                       len = INFO_LEN_EXTENDED;
+                       IO.readFully(in, info, infoOffset + INFO_LEN, INFO_LEN_EXTENDED - INFO_LEN);
+
+                       if ((getExtendedFlags() & ~EXTENDED_FLAGS) != 0)
+                               throw new IOException(MessageFormat.format(JGitText.get()
+                                               .DIRCUnrecognizedExtendedFlags, String.valueOf(getExtendedFlags())));
+               } else
+                       len = INFO_LEN;
+
+               infoAt.value += len;
+               md.update(info, infoOffset, len);
 
                int pathLen = NB.decodeUInt16(info, infoOffset + P_FLAGS) & NAME_MASK;
                int skipped = 0;
@@ -170,7 +191,7 @@ public class DirCacheEntry {
                // Index records are padded out to the next 8 byte alignment
                // for historical reasons related to how C Git read the files.
                //
-               final int actLen = INFO_LEN + pathLen;
+               final int actLen = len + pathLen;
                final int expLen = (actLen + 8) & ~7;
                final int padLen = expLen - actLen - skipped;
                if (padLen > 0) {
@@ -258,14 +279,15 @@ public class DirCacheEntry {
        }
 
        void write(final OutputStream os) throws IOException {
+               final int len = isExtended() ? INFO_LEN_EXTENDED : INFO_LEN;
                final int pathLen = path.length;
-               os.write(info, infoOffset, INFO_LEN);
+               os.write(info, infoOffset, len);
                os.write(path, 0, pathLen);
 
                // Index records are padded out to the next 8 byte alignment
                // for historical reasons related to how C Git read the files.
                //
-               final int actLen = INFO_LEN + pathLen;
+               final int actLen = len + pathLen;
                final int expLen = (actLen + 8) & ~7;
                if (actLen != expLen)
                        os.write(nullpad, 0, expLen - actLen);
@@ -400,6 +422,24 @@ public class DirCacheEntry {
                return (info[infoOffset + P_FLAGS] >>> 4) & 0x3;
        }
 
+       /**
+        * Returns whether this entry should be skipped from the working tree.
+        *
+        * @return true if this entry should be skipepd.
+        */
+       public boolean isSkipWorkTree() {
+               return (getExtendedFlags() & SKIP_WORKTREE) != 0;
+       }
+
+       /**
+        * Returns whether this entry is intent to be added to the Index.
+        *
+        * @return true if this entry is intent to add.
+        */
+       public boolean isIntentToAdd() {
+               return (getExtendedFlags() & INTENT_TO_ADD) != 0;
+       }
+
        /**
         * Obtain the raw {@link FileMode} bits for this entry.
         *
@@ -575,6 +615,13 @@ public class DirCacheEntry {
                                | NB.decodeUInt16(info, infoOffset + P_FLAGS) & ~NAME_MASK);
        }
 
+       /**
+        * @return true if the entry contains extended flags.
+        */
+       boolean isExtended() {
+               return (info[infoOffset + P_FLAGS] & EXTENDED) != 0;
+       }
+
        private long decodeTS(final int pIdx) {
                final int base = infoOffset + pIdx;
                final int sec = NB.decodeInt32(info, base);
@@ -588,6 +635,13 @@ public class DirCacheEntry {
                NB.encodeInt32(info, base + 4, ((int) (when % 1000)) * 1000000);
        }
 
+       private int getExtendedFlags() {
+               if (isExtended())
+                       return NB.decodeUInt16(info, infoOffset + P_FLAGS2) << 16;
+               else
+                       return 0;
+       }
+
        private static String toString(final byte[] path) {
                return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString();
        }
@@ -615,4 +669,8 @@ public class DirCacheEntry {
                }
                return componentHasChars;
        }
+
+       static int getMaximumInfoLength(boolean extended) {
+               return extended ? INFO_LEN_EXTENDED : INFO_LEN;
+       }
 }