Single tree record from the 'TREE' DirCache extension. A valid cache tree record contains the object id of a tree object and the total number of DirCacheEntry instances (counted recursively) from the DirCache contained within the tree. This information facilitates faster traversal of the index and quicker generation of tree objects prior to creating a new commit. An invalid cache tree record indicates a known subtree whose file entries have changed in ways that cause the tree to no longer have a known object id. Invalid cache tree records must be revalidated prior to use.
示例#1
0
        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++;
        }
示例#2
0
        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);
        }
示例#3
0
 /// <summary>
 /// Empty this index, removing all entries.
 /// </summary>
 public void clear()
 {
     _lastModified  = 0;
     _sortedEntries = NoEntries;
     _entryCnt      = 0;
     _cacheTree     = null;
 }
示例#4
0
 /// <summary>
 /// Empty this index, removing all entries.
 /// </summary>
 public void clear()
 {
     _lastModified  = DateTime.MinValue;
     _sortedEntries = NoEntries;
     _entryCnt      = 0;
     _cacheTree     = null;
 }
示例#5
0
 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;
        }
示例#7
0
 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();
 }
示例#8
0
 /// <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);
 }
示例#9
0
 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();
 }
示例#11
0
        ///	<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);
        }
示例#12
0
        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);
        }
示例#13
0
        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;
        }
示例#14
0
		/// <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;
        }
示例#15
0
		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;
		}
示例#16
0
		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++;
		}
示例#17
0
		///	<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;
			}
		}
示例#18
0
		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;
		}
示例#19
0
		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;
		}
示例#20
0
        ///	<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;
            }
        }
示例#21
0
		public void replace(DirCacheEntry[] e, int cnt)
		{
			_sortedEntries = e;
			_entryCnt = cnt;
			_cacheTree = null;
		}
示例#22
0
        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;
        }
示例#23
0
		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");
			}
		}
示例#24
0
 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();
 }
示例#25
0
        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");
            }
        }
示例#26
0
 /// <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();
 }
示例#28
0
 /// <summary>
 /// Empty this index, removing all entries.
 /// </summary>
 public void clear()
 {
     _lastModified = 0;
     _sortedEntries = NoEntries;
     _entryCnt = 0;
     _cacheTree = null;
 }
示例#29
0
 public void replace(DirCacheEntry[] e, int cnt)
 {
     _sortedEntries = e;
     _entryCnt      = cnt;
     _cacheTree     = null;
 }
示例#30
0
		/// <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;
        }
示例#32
0
		/// <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;
		}
示例#33
0
 /// <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;
 }