/// <summary>Read the index from disk, if it has changed on disk.</summary> /// <remarks> /// Read the index from disk, if it has changed on disk. /// <p> /// This method tries to avoid loading the index if it has not changed since /// the last time we consulted it. A missing index file will be treated as /// though it were present but had no file entries in it. /// </remarks> /// <exception cref="System.IO.IOException"> /// the index file is present but could not be read. This /// DirCache instance may not be populated correctly. /// </exception> /// <exception cref="NGit.Errors.CorruptObjectException"> /// the index file is using a format or extension that this /// library does not support. /// </exception> public virtual void Read() { if (liveFile == null) { throw new IOException(JGitText.Get().dirCacheDoesNotHaveABackingFile); } if (!liveFile.Exists()) { Clear(); } else { if (snapshot == null || snapshot.IsModified(liveFile)) { try { FileInputStream inStream = new FileInputStream(liveFile); try { Clear(); ReadFrom(inStream); } finally { try { inStream.Close(); } catch (IOException) { } } } catch (FileNotFoundException) { // Ignore any close failures. // Someone must have deleted it between our exists test // and actually opening the path. That's fine, its empty. // Clear(); } snapshot = FileSnapshot.Save(liveFile); } } }
/// <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); } }