public void SmallEntries() { SortedFolderEntries.FreePool(); SortedFolderEntries.InitializePools(new MockTracer(), indexEntryCount: 0); SortedFolderEntries.FilePoolSize().ShouldBeAtLeast(1); SortedFolderEntries.FolderPoolSize().ShouldBeAtLeast(1); SortedFolderEntries.ResetPool(new MockTracer(), indexEntryCount: 0); SortedFolderEntries.FilePoolSize().ShouldBeAtLeast(1); SortedFolderEntries.FolderPoolSize().ShouldBeAtLeast(1); }
/// <summary> /// Takes an action on a GitIndexEntry using the index in indexStream /// </summary> /// <param name="indexStream">Stream for reading a git index file</param> /// <param name="entryAction">Action to take on each GitIndexEntry from the index</param> /// <returns> /// FileSystemTaskResult indicating success or failure of the specified action /// </returns> /// <remarks> /// Only the AddToModifiedFiles method because it updates the modified paths file can result /// in TryIndexAction returning a FileSystemTaskResult other than Success. All other actions result in success (or an exception in the /// case of a corrupt index) /// </remarks> private FileSystemTaskResult ParseIndex( ITracer tracer, Stream indexStream, GitIndexEntry resuableParsedIndexEntry, Func <GitIndexEntry, FileSystemTaskResult> entryAction) { this.indexStream = indexStream; this.indexStream.Position = 0; this.ReadNextPage(); if (this.page[0] != 'D' || this.page[1] != 'I' || this.page[2] != 'R' || this.page[3] != 'C') { throw new InvalidDataException("Incorrect magic signature for index: " + string.Join(string.Empty, this.page.Take(4).Select(c => (char)c))); } this.Skip(4); uint indexVersion = this.ReadFromIndexHeader(); if (indexVersion != 4) { throw new InvalidDataException("Unsupported index version: " + indexVersion); } uint entryCount = this.ReadFromIndexHeader(); // Don't want to flood the logs on large indexes so only log every 500ms const int LoggingTicksThreshold = 5000000; long nextLogTicks = DateTime.UtcNow.Ticks + LoggingTicksThreshold; SortedFolderEntries.InitializePools(tracer, entryCount); LazyUTF8String.InitializePools(tracer, entryCount); resuableParsedIndexEntry.ClearLastParent(); int previousPathLength = 0; bool parseMode = GVFSPlatform.Instance.FileSystem.SupportsFileMode; FileSystemTaskResult result = FileSystemTaskResult.Success; for (int i = 0; i < entryCount; i++) { if (parseMode) { this.Skip(26); // 4-bit object type // valid values in binary are 1000(regular file), 1010(symbolic link) and 1110(gitlink) // 3-bit unused // 9-bit unix permission. Only 0755 and 0644 are valid for regular files. (Legacy repos can also contain 664) // Symbolic links and gitlinks have value 0 in this field. ushort indexFormatTypeAndMode = this.ReadUInt16(); FileTypeAndMode typeAndMode = new FileTypeAndMode(indexFormatTypeAndMode); switch (typeAndMode.Type) { case FileType.Regular: if (typeAndMode.Mode != FileMode755 && typeAndMode.Mode != FileMode644 && typeAndMode.Mode != FileMode664) { throw new InvalidDataException($"Invalid file mode {typeAndMode.GetModeAsOctalString()} found for regular file in index"); } break; case FileType.SymLink: case FileType.GitLink: if (typeAndMode.Mode != 0) { throw new InvalidDataException($"Invalid file mode {typeAndMode.GetModeAsOctalString()} found for link file({typeAndMode.Type:X}) in index"); } break; default: throw new InvalidDataException($"Invalid file type {typeAndMode.Type:X} found in index"); } resuableParsedIndexEntry.TypeAndMode = typeAndMode; this.Skip(12); } else { this.Skip(40); } this.ReadSha(resuableParsedIndexEntry); ushort flags = this.ReadUInt16(); if (flags == 0) { throw new InvalidDataException("Invalid flags found in index"); } resuableParsedIndexEntry.MergeState = (MergeStage)((flags >> 12) & 3); bool isExtended = (flags & ExtendedBit) == ExtendedBit; resuableParsedIndexEntry.PathLength = (ushort)(flags & 0xFFF); resuableParsedIndexEntry.SkipWorktree = false; if (isExtended) { ushort extendedFlags = this.ReadUInt16(); resuableParsedIndexEntry.SkipWorktree = (extendedFlags & SkipWorktreeBit) == SkipWorktreeBit; } int replaceLength = this.ReadReplaceLength(); resuableParsedIndexEntry.ReplaceIndex = previousPathLength - replaceLength; int bytesToRead = resuableParsedIndexEntry.PathLength - resuableParsedIndexEntry.ReplaceIndex + 1; this.ReadPath(resuableParsedIndexEntry, resuableParsedIndexEntry.ReplaceIndex, bytesToRead); previousPathLength = resuableParsedIndexEntry.PathLength; result = entryAction.Invoke(resuableParsedIndexEntry); if (result != FileSystemTaskResult.Success) { return(result); } if (DateTime.UtcNow.Ticks > nextLogTicks) { tracer.RelatedInfo($"{i}/{entryCount} index entries parsed."); nextLogTicks = DateTime.UtcNow.Ticks + LoggingTicksThreshold; } } tracer.RelatedInfo($"Finished parsing {entryCount} index entries."); return(result); }
public void Setup() { LazyUTF8String.InitializePools(new MockTracer(), DefaultIndexEntryCount); SortedFolderEntries.InitializePools(new MockTracer(), DefaultIndexEntryCount); }