/// <summary>Write (if necessary) this tree to the object store.</summary> /// <remarks>Write (if necessary) this tree to the object store.</remarks> /// <param name="cache">the complete cache from DirCache.</param> /// <param name="cIdx"> /// first position of <code>cache</code> that is a member of this /// tree. The path of <code>cache[cacheIdx].path</code> for the /// range <code>[0,pathOff-1)</code> matches the complete path of /// this tree, from the root of the repository. /// </param> /// <param name="pathOffset"> /// number of bytes of <code>cache[cacheIdx].path</code> that /// matches this tree's path. The value at array position /// <code>cache[cacheIdx].path[pathOff-1]</code> is always '/' if /// <code>pathOff</code> is > 0. /// </param> /// <param name="ow">the writer to use when serializing to the store.</param> /// <returns>identity of this tree.</returns> /// <exception cref="NGit.Errors.UnmergedPathException"> /// one or more paths contain higher-order stages (stage > 0), /// which cannot be stored in a tree object. /// </exception> /// <exception cref="System.IO.IOException">an unexpected error occurred writing to the object store. /// </exception> internal virtual ObjectId WriteTree(DirCacheEntry[] cache, int cIdx, int pathOffset , ObjectInserter ow) { if (id == null) { int endIdx = cIdx + entrySpan; TreeFormatter fmt = new TreeFormatter(ComputeSize(cache, cIdx, pathOffset, ow)); int childIdx = 0; int entryIdx = cIdx; while (entryIdx < endIdx) { DirCacheEntry e = cache[entryIdx]; byte[] ep = e.path; if (childIdx < childCnt) { NGit.Dircache.DirCacheTree st = children[childIdx]; if (st.Contains(ep, pathOffset, ep.Length)) { fmt.Append(st.encodedName, FileMode.TREE, st.id); entryIdx += st.entrySpan; childIdx++; continue; } } fmt.Append(ep, pathOffset, ep.Length - pathOffset, e.FileMode, e.IdBuffer, e.IdOffset ); entryIdx++; } id = ow.Insert(fmt); } return(id); }
private void ParseEntry() { currentEntry = cache.GetEntry(ptr); byte[] cep = currentEntry.path; if (nextSubtreePos != tree.GetChildCount()) { DirCacheTree s = tree.GetChild(nextSubtreePos); if (s.Contains(cep, pathOffset, cep.Length)) { // The current position is the first file of this subtree. // Use the subtree instead as the current position. // currentSubtree = s; nextSubtreePos++; if (s.IsValid()) { s.GetObjectId().CopyRawTo(subtreeId, 0); } mode = FileMode.TREE.GetBits(); path = cep; pathLen = pathOffset + s.NameLength(); return; } } // The current position is a file/symlink/gitlink so we // do not have a subtree located here. // mode = currentEntry.RawMode; path = cep; pathLen = cep.Length; currentSubtree = null; }
/// <exception cref="NGit.Errors.UnmergedPathException"></exception> /// <exception cref="System.IO.IOException"></exception> private int ComputeSize(DirCacheEntry[] cache, int cIdx, int pathOffset, ObjectInserter ow) { int endIdx = cIdx + entrySpan; int childIdx = 0; int entryIdx = cIdx; int size = 0; while (entryIdx < endIdx) { DirCacheEntry e = cache[entryIdx]; if (e.Stage != 0) { throw new UnmergedPathException(e); } byte[] ep = e.path; if (childIdx < childCnt) { NGit.Dircache.DirCacheTree st = children[childIdx]; if (st.Contains(ep, pathOffset, ep.Length)) { int stOffset = pathOffset + st.NameLength() + 1; st.WriteTree(cache, entryIdx, stOffset, ow); size += TreeFormatter.EntrySize(FileMode.TREE, st.NameLength()); entryIdx += st.entrySpan; childIdx++; continue; } } size += TreeFormatter.EntrySize(e.FileMode, ep.Length - pathOffset); entryIdx++; } return(size); }
private static int Namecmp(byte[] a, int aPos, NGit.Dircache.DirCacheTree ct) { if (ct == null) { return(-1); } byte[] b = ct.encodedName; int aLen = a.Length; int bLen = b.Length; int bPos = 0; for (; aPos < aLen && bPos < bLen; aPos++, bPos++) { int cmp = (a[aPos] & unchecked ((int)(0xff))) - (b[bPos] & unchecked ((int)(0xff))); if (cmp != 0) { return(cmp); } } if (bPos == bLen) { return(a[aPos] == '/' ? 0 : -1); } return(aLen - bLen); }
private void InsertChild(int stIdx, NGit.Dircache.DirCacheTree st) { NGit.Dircache.DirCacheTree[] c = children; if (childCnt + 1 <= c.Length) { if (stIdx < childCnt) { System.Array.Copy(c, stIdx, c, stIdx + 1, childCnt - stIdx); } c[stIdx] = st; childCnt++; return; } int n = c.Length; NGit.Dircache.DirCacheTree[] a = new NGit.Dircache.DirCacheTree[n + 1]; if (stIdx > 0) { System.Array.Copy(c, 0, a, 0, stIdx); } a[stIdx] = st; if (stIdx < n) { System.Array.Copy(c, stIdx, a, stIdx + 1, n - stIdx); } children = a; childCnt++; }
/// <summary>Empty this index, removing all entries.</summary> /// <remarks>Empty this index, removing all entries.</remarks> public virtual void Clear() { snapshot = null; sortedEntries = NO_ENTRIES; entryCnt = 0; tree = null; }
/// <summary>Empty this index, removing all entries.</summary> /// <remarks>Empty this index, removing all entries.</remarks> public virtual void Clear() { snapshot = null; sortedEntries = NO_ENTRIES; entryCnt = 0; tree = null; readIndexChecksum = NO_CHECKSUM; }
internal DirCacheTree(byte[] @in, MutableInteger off, NGit.Dircache.DirCacheTree myParent) { parent = myParent; int ptr = RawParseUtils.Next(@in, off.value, '\0'); int nameLen = ptr - off.value - 1; if (nameLen > 0) { encodedName = new byte[nameLen]; System.Array.Copy(@in, off.value, encodedName, 0, nameLen); } else { encodedName = NO_NAME; } entrySpan = RawParseUtils.ParseBase10(@in, ptr, off); int subcnt = RawParseUtils.ParseBase10(@in, off.value, off); off.value = RawParseUtils.Next(@in, off.value, '\n'); if (entrySpan >= 0) { // Valid trees have a positive entry count and an id of a // tree object that should exist in the object database. // id = ObjectId.FromRaw(@in, off.value); off.value += Constants.OBJECT_ID_LENGTH; } if (subcnt > 0) { bool alreadySorted = true; children = new NGit.Dircache.DirCacheTree[subcnt]; for (int i = 0; i < subcnt; i++) { children[i] = new NGit.Dircache.DirCacheTree(@in, off, this); // C Git's ordering differs from our own; it prefers to // sort by length first. This sometimes produces a sort // we do not desire. On the other hand it may have been // created by us, and be sorted the way we want. // if (alreadySorted && i > 0 && TREE_CMP.Compare(children[i - 1], children[i]) > 0) { alreadySorted = false; } } if (!alreadySorted) { Arrays.Sort(children, 0, subcnt, TREE_CMP); } } else { // Leaf level trees have no children, only (file) entries. // children = NO_CHILDREN; } childCnt = subcnt; }
private DirCacheTree(NGit.Dircache.DirCacheTree myParent, byte[] path, int pathOff , int pathLen) { parent = myParent; encodedName = new byte[pathLen]; System.Array.Copy(path, pathOff, encodedName, 0, pathLen); children = NO_CHILDREN; childCnt = 0; entrySpan = -1; }
public virtual void TestEmptyCache_Clear_NoCacheTree() { DirCache dc = db.ReadDirCache(); DirCacheTree tree = dc.GetCacheTree(true); NUnit.Framework.Assert.IsNotNull(tree); dc.Clear(); NUnit.Framework.Assert.IsNull(dc.GetCacheTree(false)); NUnit.Framework.Assert.AreNotSame(tree, dc.GetCacheTree(true)); }
internal DirCacheIterator(NGit.Dircache.DirCacheIterator p, DirCacheTree dct) : base (p, p.path, p.pathLen + 1) { cache = p.cache; tree = dct; treeStart = p.ptr; treeEnd = treeStart + tree.GetEntrySpan(); subtreeId = p.subtreeId; ptr = p.ptr; ParseEntry(); }
/// <summary>Create a new iterator for an already loaded DirCache instance.</summary> /// <remarks> /// Create a new iterator for an already loaded DirCache instance. /// <p> /// The iterator implementation may copy part of the cache's data during /// construction, so the cache must be read in prior to creating the /// iterator. /// </remarks> /// <param name="dc">the cache to walk. It must be already loaded into memory.</param> public DirCacheIterator(DirCache dc) { cache = dc; tree = dc.GetCacheTree(true); treeStart = 0; treeEnd = tree.GetEntrySpan(); subtreeId = new byte[Constants.OBJECT_ID_LENGTH]; if (!Eof) { ParseEntry(); } }
/// <summary>Obtain (or build) the current cache tree structure.</summary> /// <remarks> /// Obtain (or build) the current cache tree structure. /// <p> /// This method can optionally recreate the cache tree, without flushing the /// tree objects themselves to disk. /// </remarks> /// <param name="build"> /// if true and the cache tree is not present in the index it will /// be generated and returned to the caller. /// </param> /// <returns> /// the cache tree; null if there is no current cache tree available /// and <code>build</code> was false. /// </returns> public virtual DirCacheTree GetCacheTree(bool build) { if (build) { if (tree == null) { tree = new DirCacheTree(); } tree.Validate(sortedEntries, entryCnt, 0, 0); } return(tree); }
internal virtual int NextEntry(byte[] p, int pLen, int nextIdx) { while (nextIdx < entryCnt) { DirCacheEntry next = sortedEntries[nextIdx]; if (!DirCacheTree.Peq(p, next.path, pLen)) { break; } nextIdx++; } return(nextIdx); }
public virtual void TestTwoLevelSubtree() { DirCache dc = db.ReadDirCache(); string[] paths = new string[] { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" }; DirCacheEntry[] ents = new DirCacheEntry[paths.Length]; for (int i = 0; i < paths.Length; i++) { ents[i] = new DirCacheEntry(paths[i]); ents[i].FileMode = FileMode.REGULAR_FILE; } int aFirst = 1; int aLast = 4; int acFirst = 2; int acLast = 3; DirCacheBuilder b = dc.Builder(); for (int i_1 = 0; i_1 < ents.Length; i_1++) { b.Add(ents[i_1]); } b.Finish(); NUnit.Framework.Assert.IsNull(dc.GetCacheTree(false)); DirCacheTree root = dc.GetCacheTree(true); NUnit.Framework.Assert.IsNotNull(root); NUnit.Framework.Assert.AreSame(root, dc.GetCacheTree(true)); NUnit.Framework.Assert.AreEqual(string.Empty, root.GetNameString()); NUnit.Framework.Assert.AreEqual(string.Empty, root.GetPathString()); NUnit.Framework.Assert.AreEqual(1, root.GetChildCount()); NUnit.Framework.Assert.AreEqual(dc.GetEntryCount(), root.GetEntrySpan()); NUnit.Framework.Assert.IsFalse(root.IsValid()); DirCacheTree aTree = root.GetChild(0); NUnit.Framework.Assert.IsNotNull(aTree); NUnit.Framework.Assert.AreSame(aTree, root.GetChild(0)); NUnit.Framework.Assert.AreEqual("a", aTree.GetNameString()); NUnit.Framework.Assert.AreEqual("a/", aTree.GetPathString()); NUnit.Framework.Assert.AreEqual(1, aTree.GetChildCount()); NUnit.Framework.Assert.AreEqual(aLast - aFirst + 1, aTree.GetEntrySpan()); NUnit.Framework.Assert.IsFalse(aTree.IsValid()); DirCacheTree acTree = aTree.GetChild(0); NUnit.Framework.Assert.IsNotNull(acTree); NUnit.Framework.Assert.AreSame(acTree, aTree.GetChild(0)); NUnit.Framework.Assert.AreEqual("c", acTree.GetNameString()); NUnit.Framework.Assert.AreEqual("a/c/", acTree.GetPathString()); NUnit.Framework.Assert.AreEqual(0, acTree.GetChildCount()); NUnit.Framework.Assert.AreEqual(acLast - acFirst + 1, acTree.GetEntrySpan()); NUnit.Framework.Assert.IsFalse(acTree.IsValid()); }
public virtual void TestEmptyCache_CreateEmptyCacheTree() { DirCache dc = db.ReadDirCache(); DirCacheTree tree = dc.GetCacheTree(true); NUnit.Framework.Assert.IsNotNull(tree); NUnit.Framework.Assert.AreSame(tree, dc.GetCacheTree(false)); NUnit.Framework.Assert.AreSame(tree, dc.GetCacheTree(true)); NUnit.Framework.Assert.AreEqual(string.Empty, tree.GetNameString()); NUnit.Framework.Assert.AreEqual(string.Empty, tree.GetPathString()); NUnit.Framework.Assert.AreEqual(0, tree.GetChildCount()); NUnit.Framework.Assert.AreEqual(0, tree.GetEntrySpan()); NUnit.Framework.Assert.IsFalse(tree.IsValid()); }
public virtual void TestReadIndex_DirCacheTree() { IDictionary <string, DirCacheCGitCompatabilityTest.CGitIndexRecord> cList = ReadLsFiles (); IDictionary <string, DirCacheCGitCompatabilityTest.CGitLsTreeRecord> cTree = ReadLsTree (); DirCache dc = new DirCache(index, FS.DETECTED); NUnit.Framework.Assert.AreEqual(0, dc.GetEntryCount()); dc.Read(); NUnit.Framework.Assert.AreEqual(cList.Count, dc.GetEntryCount()); DirCacheTree jTree = dc.GetCacheTree(false); NUnit.Framework.Assert.IsNotNull(jTree); NUnit.Framework.Assert.AreEqual(string.Empty, jTree.GetNameString()); NUnit.Framework.Assert.AreEqual(string.Empty, jTree.GetPathString()); NUnit.Framework.Assert.IsTrue(jTree.IsValid()); NUnit.Framework.Assert.AreEqual(ObjectId.FromString("698dd0b8d0c299f080559a1cffc7fe029479a408" ), jTree.GetObjectId()); NUnit.Framework.Assert.AreEqual(cList.Count, jTree.GetEntrySpan()); AList <DirCacheCGitCompatabilityTest.CGitLsTreeRecord> subtrees = new AList <DirCacheCGitCompatabilityTest.CGitLsTreeRecord >(); foreach (DirCacheCGitCompatabilityTest.CGitLsTreeRecord r in cTree.Values) { if (FileMode.TREE.Equals(r.mode)) { subtrees.AddItem(r); } } NUnit.Framework.Assert.AreEqual(subtrees.Count, jTree.GetChildCount()); for (int i = 0; i < jTree.GetChildCount(); i++) { DirCacheTree sj = jTree.GetChild(i); DirCacheCGitCompatabilityTest.CGitLsTreeRecord sc = subtrees[i]; NUnit.Framework.Assert.AreEqual(sc.path, sj.GetNameString()); NUnit.Framework.Assert.AreEqual(sc.path + "/", sj.GetPathString()); NUnit.Framework.Assert.IsTrue(sj.IsValid()); NUnit.Framework.Assert.AreEqual(sc.id, sj.GetObjectId()); } }
internal DirCacheBuildIterator(NGit.Dircache.DirCacheBuildIterator p, DirCacheTree dct) : base(p, dct) { builder = p.builder; }
/// <exception cref="System.IO.IOException"></exception> /// <exception cref="NGit.Errors.CorruptObjectException"></exception> private void ReadFrom(InputStream inStream) { BufferedInputStream @in = new BufferedInputStream(inStream); MessageDigest md = Constants.NewMessageDigest(); // Read the index header and verify we understand it. // byte[] hdr = new byte[20]; IOUtil.ReadFully(@in, hdr, 0, 12); md.Update(hdr, 0, 12); if (!Is_DIRC(hdr)) { throw new CorruptObjectException(JGitText.Get().notADIRCFile); } int ver = NB.DecodeInt32(hdr, 4); bool 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) { throw new CorruptObjectException(JGitText.Get().DIRCHasTooManyEntries); } // Load the individual file entries. // int infoLength = DirCacheEntry.GetMaximumInfoLength(extended); byte[] infos = new byte[infoLength * entryCnt]; sortedEntries = new DirCacheEntry[entryCnt]; MutableInteger infoAt = new MutableInteger(); for (int i = 0; i < entryCnt; i++) { sortedEntries[i] = new DirCacheEntry(infos, infoAt, @in, md); } snapshot = FileSnapshot.Save(liveFile); // After the file entries are index extensions, and then a footer. // for (; ;) { @in.Mark(21); IOUtil.ReadFully(@in, hdr, 0, 20); if (@in.Read() < 0) { // No extensions present; the file ended where we expected. // break; } @in.Reset(); md.Update(hdr, 0, 8); IOUtil.SkipFully(@in, 8); long sz = NB.DecodeUInt32(hdr, 4); switch (NB.DecodeInt32(hdr, 0)) { case EXT_TREE: { if (int.MaxValue < sz) { throw new CorruptObjectException(MessageFormat.Format(JGitText.Get().DIRCExtensionIsTooLargeAt , FormatExtensionName(hdr), sz)); } byte[] raw = new byte[(int)sz]; IOUtil.ReadFully(@in, raw, 0, raw.Length); md.Update(raw, 0, raw.Length); tree = new DirCacheTree(raw, new MutableInteger(), null); break; } default: { if (hdr[0] >= 'A' && ((sbyte)hdr[0]) <= 'Z') { // The extension is optional and is here only as // a performance optimization. Since we do not // understand it, we can safely skip past it, after // we include its data in our checksum. // SkipOptionalExtension(@in, md, hdr, sz); } else { // The extension is not an optimization and is // _required_ to understand this index format. // Since we did not trap it above we must abort. // throw new CorruptObjectException(MessageFormat.Format(JGitText.Get().DIRCExtensionNotSupportedByThisVersion , FormatExtensionName(hdr))); } break; } } } byte[] exp = md.Digest(); if (!Arrays.Equals(exp, hdr)) { throw new CorruptObjectException(JGitText.Get().DIRCChecksumMismatch); } }
/// <summary>Update (if necessary) this tree's entrySpan.</summary> /// <remarks>Update (if necessary) this tree's entrySpan.</remarks> /// <param name="cache">the complete cache from DirCache.</param> /// <param name="cCnt"> /// number of entries in <code>cache</code> that are valid for /// iteration. /// </param> /// <param name="cIdx"> /// first position of <code>cache</code> that is a member of this /// tree. The path of <code>cache[cacheIdx].path</code> for the /// range <code>[0,pathOff-1)</code> matches the complete path of /// this tree, from the root of the repository. /// </param> /// <param name="pathOff"> /// number of bytes of <code>cache[cacheIdx].path</code> that /// matches this tree's path. The value at array position /// <code>cache[cacheIdx].path[pathOff-1]</code> is always '/' if /// <code>pathOff</code> is > 0. /// </param> internal virtual void Validate(DirCacheEntry[] cache, int cCnt, int cIdx, int pathOff ) { if (entrySpan >= 0) { // If we are valid, our children are also valid. // We have no need to validate them. // return; } entrySpan = 0; if (cCnt == 0) { // Special case of an empty index, and we are the root tree. // return; } byte[] firstPath = cache[cIdx].path; int stIdx = 0; while (cIdx < cCnt) { byte[] currPath = cache[cIdx].path; if (pathOff > 0 && !Peq(firstPath, currPath, pathOff)) { // The current entry is no longer in this tree. Our // span is updated and the remainder goes elsewhere. // break; } NGit.Dircache.DirCacheTree st = stIdx < childCnt ? children[stIdx] : null; int cc = Namecmp(currPath, pathOff, st); if (cc > 0) { // This subtree is now empty. // RemoveChild(stIdx); continue; } if (cc < 0) { int p = Slash(currPath, pathOff); if (p < 0) { // The entry has no '/' and thus is directly in this // tree. Count it as one of our own. // cIdx++; entrySpan++; continue; } // Build a new subtree for this entry. // st = new NGit.Dircache.DirCacheTree(this, currPath, pathOff, p - pathOff); InsertChild(stIdx, st); } // The entry is contained in this subtree. // st.Validate(cache, cCnt, cIdx, pathOff + st.NameLength() + 1); cIdx += st.entrySpan; entrySpan += st.entrySpan; stIdx++; } // None of our remaining children can be in this tree // as the current cache entry is after our own name. // while (stIdx < childCnt) { RemoveChild(childCnt - 1); } }
internal virtual void Replace(DirCacheEntry[] e, int cnt) { sortedEntries = e; entryCnt = cnt; tree = null; }