public void replace(DirCacheEntry[] e, int cnt) { sortedEntries = e; entryCnt = cnt; tree = null; }
/** Empty this index, removing all entries. */ public void clear() { lastModified = DateTime.MinValue; sortedEntries = NO_ENTRIES; entryCnt = 0; tree = null; }
private void insertChild(int stIdx, DirCacheTree st) { DirCacheTree[] c = children; if (childCnt + 1 <= c.Length) { if (stIdx < childCnt) Array.Copy(c, stIdx, c, stIdx + 1, childCnt - stIdx); c[stIdx] = st; childCnt++; return; } int n = c.Length; DirCacheTree[] 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; childCnt++; }
private static int namecmp(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; }
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 = NO_NAME; 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 && TREE_CMP(children[i - 1], children[i]) > 0) alreadySorted = false; } if (!alreadySorted) Array.Sort(children, TREE_CMP); } else { // Leaf level trees have no children, only (file) entries. // children = NO_CHILDREN; } childCnt = subcnt; }
/** * Update (if necessary) this tree's entrySpan. * * @param cache * the complete cache from DirCache. * @param cCnt * number of entries in <code>cache</code> that are valid for * iteration. * @param 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 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. */ 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 < 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 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 < childCnt) { // None of our remaining children can be in this tree // as the current cache entry is after our own name. // DirCacheTree[] dct = new DirCacheTree[stIdx]; Array.Copy(children, 0, dct, 0, stIdx); children = dct; } }
/// <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 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(); }
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 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 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) { _builder = parentIterator._builder; }
private void readFrom(FileStream inStream) { var @in = new StreamReader(inStream); MessageDigest md = Constants.newMessageDigest(); // Read the index header and verify we understand it. // byte[] hdr = new byte[20]; NB.ReadFully(inStream, hdr, 0, 12); md.Update(hdr, 0, 12); if (!is_DIRC(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. // byte[] infos = new byte[INFO_LEN * entryCnt]; sortedEntries = new DirCacheEntry[entryCnt]; for (int i = 0; i < entryCnt; i++) sortedEntries[i] = new DirCacheEntry(infos, i * INFO_LEN, inStream, md); lastModified = liveFile.LastAccessTime; // After the file entries are index extensions, and then a footer. // for (; ; ) { var pos = inStream.Position; NB.ReadFully(inStream, hdr, 0, 20); if (@in.Read() < 0) { // No extensions present; the file ended where we expected. // break; } inStream.Seek(pos, SeekOrigin.Begin); switch (NB.decodeInt32(hdr, 0)) { case EXT_TREE: { byte[] raw = new byte[NB.decodeInt32(hdr, 4)]; md.Update(hdr, 0, 8); NB.skipFully(inStream, 8); NB.ReadFully(inStream, raw, 0, raw.Length); md.Update(raw, 0, raw.Length); tree = 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. // NB.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"); } }
private DirCacheTree(DirCacheTree myParent, byte[] path, int pathOff, int pathLen) { parent = myParent; encodedName = new byte[pathLen]; Array.Copy(path, pathOff, encodedName, 0, pathLen); children = NO_CHILDREN; childCnt = 0; entrySpan = -1; }
/** * 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. * * @param build * if true and the cache tree is not present in the index it will * be generated and returned to the caller. * @return the cache tree; null if there is no current cache tree available * and <code>build</code> was false. */ public DirCacheTree getCacheTree(bool build) { if (build) { if (tree == null) tree = new DirCacheTree(); tree.validate(sortedEntries, entryCnt, 0, 0); } return tree; }
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; }