private void InsertChild(int stIdx, DirCacheTree st) { DirCacheTree[] c = _children; if (_childCount + 1 <= c.Length) { if (stIdx < _childCount) { Array.Copy(c, stIdx, c, stIdx + 1, _childCount - stIdx); } c[stIdx] = st; _childCount++; return; } int n = c.Length; var a = new DirCacheTree[n + 1]; if (stIdx > 0) { Array.Copy(c, 0, a, 0, stIdx); } a[stIdx] = st; if (stIdx < n) { Array.Copy(c, stIdx, a, stIdx + 1, n - stIdx); } _children = a; _childCount++; }
private static int NameComparison(byte[] a, int aPos, 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] & 0xff) - (b[bPos] & 0xff); if (cmp != 0) { return(cmp); } } if (bPos == bLen) { return(a[aPos] == '/' ? 0 : -1); } return(aLen - bLen); }
/// <summary> /// Empty this index, removing all entries. /// </summary> public void clear() { _lastModified = 0; _sortedEntries = NoEntries; _entryCnt = 0; _cacheTree = null; }
/// <summary> /// Empty this index, removing all entries. /// </summary> public void clear() { _lastModified = DateTime.MinValue; _sortedEntries = NoEntries; _entryCnt = 0; _cacheTree = null; }
private DirCacheTree(DirCacheTree myParent, byte[] path, int pathOff, int pathLen) { _parent = myParent; _encodedName = new byte[pathLen]; Array.Copy(path, pathOff, _encodedName, 0, pathLen); _children = NoChildren; _childCount = 0; _entrySpan = -1; }
/// <summary> /// Create a new iterator for an already loaded <see cref="DirCache"/> instance. /// <para/> /// 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. /// </summary> /// <param name="parentIterator">The parent iterator</param> /// <param name="cacheTree">The cache tree</param> DirCacheBuildIterator(DirCacheBuildIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, cacheTree) { if (parentIterator == null) { throw new System.ArgumentNullException("parentIterator"); } _builder = parentIterator._builder; }
public DirCacheIterator(DirCacheIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, parentIterator.Path, parentIterator.PathLen + 1) { Cache = parentIterator.Cache; Tree = cacheTree; TreeStart = parentIterator._pointer; TreeEnd = TreeStart + Tree.getEntrySpan(); SubtreeId = parentIterator.SubtreeId; _pointer = parentIterator._pointer; ParseEntry(); }
/// <summary> /// Obtain (or build) the current cache tree structure. /// <para /> /// This method can optionally recreate the cache tree, without flushing the /// tree objects themselves to disk. /// </summary> /// <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 <paramref name="build"/> was false. /// </returns> public DirCacheTree getCacheTree(bool build) { if (build) { if (_cacheTree == null) { _cacheTree = new DirCacheTree(); } _cacheTree.validate(_sortedEntries, _entryCnt, 0, 0); } return(_cacheTree); }
public 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 DirCacheIterator(DirCacheIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, parentIterator.Path, parentIterator.PathLen + 1) { if (parentIterator == null) { throw new System.ArgumentNullException("parentIterator"); } Cache = parentIterator.Cache; Tree = cacheTree; TreeStart = parentIterator._pointer; TreeEnd = TreeStart + Tree.getEntrySpan(); SubtreeId = parentIterator.SubtreeId; _pointer = parentIterator._pointer; ParseEntry(); }
/// <summary> /// Write (if necessary) this tree to the object store. /// </summary> /// <param name="cacheEntry">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="UnmergedPathException"> /// one or more paths contain higher-order stages (stage > 0), /// which cannot be stored in a tree object. /// </exception> /// <exception cref="IOException"> /// an unexpected error occurred writing to the object store. /// </exception> public ObjectId writeTree(DirCacheEntry[] cacheEntry, int cIdx, int pathOffset, ObjectWriter ow) { if (_id == null) { int endIdx = cIdx + _entrySpan; int size = ComputeSize(cacheEntry, cIdx, pathOffset, ow); var @out = new MemoryStream(size); int childIdx = 0; int entryIdx = cIdx; while (entryIdx < endIdx) { DirCacheEntry e = cacheEntry[entryIdx]; byte[] ep = e.Path; if (childIdx < _childCount) { DirCacheTree st = _children[childIdx]; if (st.contains(ep, pathOffset, ep.Length)) { FileMode.Tree.CopyTo(@out); @out.Write(new[] { (byte)' ' }, 0, 1); @out.Write(st._encodedName, 0, st._encodedName.Length); @out.Write(new[] { (byte)0 }, 0, 1); st._id.copyRawTo(@out); entryIdx += st._entrySpan; childIdx++; continue; } } e.getFileMode().CopyTo(@out); @out.Write(new[] { (byte)' ' }, 0, 1); @out.Write(ep, pathOffset, ep.Length - pathOffset); @out.Write(new byte[] { 0 }, 0, 1); @out.Write(e.idBuffer(), e.idOffset(), Constants.OBJECT_ID_LENGTH); entryIdx++; } _id = ow.WriteCanonicalTree(@out.ToArray()); } return(_id); }
private int ComputeSize(DirCacheEntry[] cache, int cIdx, int pathOffset, ObjectWriter ow) { int endIdx = cIdx + _entrySpan; int childIdx = 0; int entryIdx = cIdx; int size = 0; while (entryIdx < endIdx) { DirCacheEntry e = cache[entryIdx]; if (e.getStage() != 0) { throw new UnmergedPathException(e); } byte[] ep = e.Path; if (childIdx < _childCount) { DirCacheTree st = _children[childIdx]; if (st.contains(ep, pathOffset, ep.Length)) { int stOffset = pathOffset + st.nameLength() + 1; st.writeTree(cache, entryIdx, stOffset, ow); size += FileMode.Tree.copyToLength(); size += st.nameLength(); size += Constants.OBJECT_ID_LENGTH + 2; entryIdx += st._entrySpan; childIdx++; continue; } } FileMode mode = e.getFileMode(); size += mode.copyToLength(); size += ep.Length - pathOffset; size += Constants.OBJECT_ID_LENGTH + 2; entryIdx++; } return(size); }
private void ParseEntry() { _currentEntry = Cache.getEntry(_pointer); 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); } else { SubtreeId.Fill((byte)0); } Mode = FileMode.Tree.Bits; 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.getRawMode(); Path = cep; PathLen = cep.Length; _currentSubtree = null; }
/// <summary> /// Create a new iterator for an already loaded <see cref="DirCache"/> instance. /// <para/> /// 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. /// </summary> /// <param name="parentIterator">The parent iterator</param> /// <param name="cacheTree">The cache tree</param> DirCacheBuildIterator(DirCacheBuildIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, cacheTree) { if (parentIterator == null) throw new System.ArgumentNullException ("parentIterator"); _builder = parentIterator._builder; }
private static int NameComparison(byte[] a, int aPos, 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] & 0xff) - (b[bPos] & 0xff); if (cmp != 0) { return cmp; } } if (bPos == bLen) { return a[aPos] == '/' ? 0 : -1; } return aLen - bLen; }
private void InsertChild(int stIdx, DirCacheTree st) { DirCacheTree[] c = _children; if (_childCount + 1 <= c.Length) { if (stIdx < _childCount) { Array.Copy(c, stIdx, c, stIdx + 1, _childCount - stIdx); } c[stIdx] = st; _childCount++; return; } int n = c.Length; var a = new DirCacheTree[n + 1]; if (stIdx > 0) { Array.Copy(c, 0, a, 0, stIdx); } a[stIdx] = st; if (stIdx < n) { Array.Copy(c, stIdx, a, stIdx + 1, n - stIdx); } _children = a; _childCount++; }
/// <summary> /// Update (if necessary) this tree's entrySpan. /// </summary> /// <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> public 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; } DirCacheTree st = stIdx < _childCount ? _children[stIdx] : null; int cc = NameComparison(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 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++; } if (stIdx < _childCount) { // None of our remaining children can be in this tree // as the current cache entry is After our own name. // var dct = new DirCacheTree[stIdx]; Array.Copy(_children, 0, dct, 0, stIdx); _children = dct; } }
public DirCacheTree(byte[] @in, MutableInteger off, DirCacheTree myParent) { _parent = myParent; int ptr = RawParseUtils.next(@in, off.value, (byte)'\0'); int nameLen = ptr - off.value - 1; if (nameLen > 0) { _encodedName = new byte[nameLen]; Array.Copy(@in, off.value, _encodedName, 0, nameLen); } else { _encodedName = NoName; } _entrySpan = RawParseUtils.parseBase10(@in, ptr, off); int subcnt = RawParseUtils.parseBase10(@in, off.value, off); off.value = RawParseUtils.next(@in, off.value, (byte)'\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 DirCacheTree[subcnt]; for (int i = 0; i < subcnt; i++) { _children[i] = new 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 && TreeComparison(_children[i - 1], _children[i]) > 0) { alreadySorted = false; } } if (!alreadySorted) { Array.Sort(_children, TreeComparison); } } else { // Leaf level trees have no children, only (file) entries. // _children = NoChildren; } _childCount = subcnt; }
private DirCacheTree(DirCacheTree myParent, byte[] path, int pathOff, int pathLen) { _parent = myParent; _encodedName = new byte[pathLen]; Array.Copy(path, pathOff, _encodedName, 0, pathLen); _children = NoChildren; _childCount = 0; _entrySpan = -1; }
/// <summary> /// Update (if necessary) this tree's entrySpan. /// </summary> /// <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> public 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; } DirCacheTree st = stIdx < _childCount ? _children[stIdx] : null; int cc = NameComparison(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 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++; } if (stIdx < _childCount) { // None of our remaining children can be in this tree // as the current cache entry is After our own name. // var dct = new DirCacheTree[stIdx]; Array.Copy(_children, 0, dct, 0, stIdx); _children = dct; } }
public void replace(DirCacheEntry[] e, int cnt) { _sortedEntries = e; _entryCnt = cnt; _cacheTree = null; }
public DirCacheTree(byte[] @in, MutableInteger off, DirCacheTree myParent) { _parent = myParent; int ptr = RawParseUtils.next(@in, off.value, (byte)'\0'); int nameLen = ptr - off.value - 1; if (nameLen > 0) { _encodedName = new byte[nameLen]; Array.Copy(@in, off.value, _encodedName, 0, nameLen); } else { _encodedName = NoName; } _entrySpan = RawParseUtils.parseBase10(@in, ptr, off); int subcnt = RawParseUtils.parseBase10(@in, off.value, off); off.value = RawParseUtils.next(@in, off.value, (byte)'\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 DirCacheTree[subcnt]; for (int i = 0; i < subcnt; i++) { _children[i] = new 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 && TreeComparison(_children[i - 1], _children[i]) > 0) { alreadySorted = false; } } if (!alreadySorted) { Array.Sort(_children, TreeComparison); } } else { // Leaf level trees have no children, only (file) entries. // _children = NoChildren; } _childCount = subcnt; }
private void ReadFrom(Stream inStream) { var @in = new StreamReader(inStream); MessageDigest md = Constants.newMessageDigest(); // Read the index header and verify we understand it. // var hdr = new byte[20]; IO.ReadFully(inStream, hdr, 0, 12); md.Update(hdr, 0, 12); if (!IsDIRC(hdr)) { throw new CorruptObjectException("Not a DIRC file."); } int ver = NB.DecodeInt32(hdr, 4); if (ver != 2) { throw new CorruptObjectException("Unknown DIRC version " + ver); } _entryCnt = NB.DecodeInt32(hdr, 8); if (_entryCnt < 0) { throw new CorruptObjectException("DIRC has too many entries."); } // Load the individual file entries. // var infos = new byte[InfoLen * _entryCnt]; _sortedEntries = new DirCacheEntry[_entryCnt]; for (int i = 0; i < _entryCnt; i++) { _sortedEntries[i] = new DirCacheEntry(infos, i * InfoLen, inStream, md); } _lastModified = _liveFile.LastWriteTime; // After the file entries are index extensions, and then a footer. // while (true) { var pos = inStream.Position; IO.ReadFully(inStream, hdr, 0, 20); int nextByte = @in.Read(); if (nextByte < 0 || inStream.Position == inStream.Length) { // No extensions present; the file ended where we expected. // break; } inStream.Seek(pos, SeekOrigin.Begin); switch (NB.DecodeInt32(hdr, 0)) { case ExtTree: var raw = new byte[NB.DecodeInt32(hdr, 4)]; md.Update(hdr, 0, 8); IO.skipFully(inStream, 8); IO.ReadFully(inStream, raw, 0, raw.Length); md.Update(raw, 0, raw.Length); _cacheTree = new DirCacheTree(raw, new MutableInteger(), null); break; default: if (hdr[0] >= (byte)'A' && hdr[0] <= (byte)'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. // IO.skipFully(inStream, NB.decodeUInt32(hdr, 4)); } 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("DIRC extension '" + Constants.CHARSET.GetString(hdr.Take(4).ToArray()) + "' not supported by this version."); } break; } } byte[] exp = md.Digest(); if (!exp.SequenceEqual(hdr)) { throw new CorruptObjectException("DIRC checksum mismatch"); } }
public DirCacheIterator(DirCacheIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, parentIterator.Path, parentIterator.PathLen + 1) { Cache = parentIterator.Cache; Tree = cacheTree; TreeStart = parentIterator._pointer; TreeEnd = TreeStart + Tree.getEntrySpan(); SubtreeId = parentIterator.SubtreeId; _pointer = parentIterator._pointer; ParseEntry(); }
private void ReadFrom(Stream inStream) { var @in = new StreamReader(inStream); MessageDigest md = Constants.newMessageDigest(); // Read the index header and verify we understand it. // var hdr = new byte[20]; IO.ReadFully(inStream, hdr, 0, 12); md.Update(hdr, 0, 12); if (!IsDIRC(hdr)) { throw new CorruptObjectException("Not a DIRC file."); } int ver = NB.DecodeInt32(hdr, 4); if (ver != 2) { throw new CorruptObjectException("Unknown DIRC version " + ver); } _entryCnt = NB.DecodeInt32(hdr, 8); if (_entryCnt < 0) { throw new CorruptObjectException("DIRC has too many entries."); } // Load the individual file entries. // var infos = new byte[InfoLen * _entryCnt]; _sortedEntries = new DirCacheEntry[_entryCnt]; for (int i = 0; i < _entryCnt; i++) { _sortedEntries[i] = new DirCacheEntry(infos, i * InfoLen, inStream, md); } _lastModified = _liveFile.lastModified(); // After the file entries are index extensions, and then a footer. // while (true) { var pos = inStream.Position; IO.ReadFully(inStream, hdr, 0, 20); if (inStream.ReadByte() < 0) { // No extensions present; the file ended where we expected. // break; } inStream.Seek(pos, SeekOrigin.Begin); md.Update(hdr, 0, 8); IO.skipFully(inStream, 8); long sz = NB.decodeUInt32(hdr, 4); switch (NB.DecodeInt32(hdr, 0)) { case ExtTree: if (int.MaxValue < sz) { throw new CorruptObjectException("DIRC extension " + formatExtensionName(hdr) + " is too large at " + sz + " bytes."); } byte[] raw = new byte[(int)sz]; IO.ReadFully(inStream, raw, 0, raw.Length); md.Update(raw, 0, raw.Length); _cacheTree = new DirCacheTree(raw, new MutableInteger(), null); break; default: if (hdr[0] >= (byte)'A' && hdr[0] <= (byte)'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(inStream, 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("DIRC extension " + formatExtensionName(hdr) + " not supported by this version."); } break; } } byte[] exp = md.Digest(); if (!exp.SequenceEqual(hdr)) { throw new CorruptObjectException("DIRC checksum mismatch"); } }
/// <summary> /// Create a new iterator for an already loaded <see cref="DirCache"/> instance. /// <para/> /// 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. /// </summary> /// <param name="parentIterator">The parent iterator</param> /// <param name="cacheTree">The cache tree</param> DirCacheBuildIterator(DirCacheBuildIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, cacheTree) { _builder = parentIterator._builder; }
public DirCacheIterator(DirCacheIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, parentIterator.Path, parentIterator.PathLen + 1) { if ( parentIterator == null) { throw new System.ArgumentNullException("parentIterator"); } Cache = parentIterator.Cache; Tree = cacheTree; TreeStart = parentIterator._pointer; TreeEnd = TreeStart + Tree.getEntrySpan(); SubtreeId = parentIterator.SubtreeId; _pointer = parentIterator._pointer; ParseEntry(); }
/// <summary> /// Empty this index, removing all entries. /// </summary> public void clear() { _lastModified = 0; _sortedEntries = NoEntries; _entryCnt = 0; _cacheTree = null; }
public void replace(DirCacheEntry[] e, int cnt) { _sortedEntries = e; _entryCnt = cnt; _cacheTree = null; }
/// <summary> /// Empty this index, removing all entries. /// </summary> public void clear() { _lastModified = DateTime.MinValue; _sortedEntries = NoEntries; _entryCnt = 0; _cacheTree = null; }
private void ParseEntry() { _currentEntry = Cache.getEntry(_pointer); 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); } else { SubtreeId.Fill((byte)0); } Mode = FileMode.Tree.Bits; 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.getRawMode(); Path = cep; PathLen = cep.Length; _currentSubtree = null; }
/// <summary> /// Obtain (or build) the current cache tree structure. /// <para /> /// This method can optionally recreate the cache tree, without flushing the /// tree objects themselves to disk. /// </summary> /// <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 <paramref name="build"/> was false. /// </returns> public DirCacheTree getCacheTree(bool build) { if (build) { if (_cacheTree == null) { _cacheTree = new DirCacheTree(); } _cacheTree.validate(_sortedEntries, _entryCnt, 0, 0); } return _cacheTree; }
/// <summary> /// Create a new iterator for an already loaded <see cref="DirCache"/> instance. /// <para/> /// 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. /// </summary> /// <param name="parentIterator">The parent iterator</param> /// <param name="cacheTree">The cache tree</param> DirCacheBuildIterator(DirCacheBuildIterator parentIterator, DirCacheTree cacheTree) : base(parentIterator, cacheTree) { _builder = parentIterator._builder; }