Skip to content

Commit 317d1c2

Browse files
committed
Always index locally for prefetch packs
The GVFS protocol includes an index file along with pack file in the prefetch workflow (primarily used on a new clone to fetch all commits and trees). Currently, GVFS blindly accepts that index file. This pull request changes GVFS prefetch to discard the index sent by the server and always create an index locally. This provides improved security and verification of the pack file, at the expense of performance for the first clone of a repository on a new drive.
1 parent 6b8e93b commit 317d1c2

1 file changed

Lines changed: 34 additions & 45 deletions

File tree

GVFS/GVFS.Common/Git/GitObjects.cs

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -706,64 +706,53 @@ private LooseObjectToWrite GetLooseObjectDestination(string sha)
706706

707707
bytesDownloaded += packLength;
708708

709-
// We will try to build an index if the server does not send one
710-
if (pack.IndexStream == null)
709+
// We can't trust the index file from the server, so we will always build our own.
710+
// We still need to consume and handle any exceptions from the index stream though.
711+
var canContinue = true;
712+
GitProcess.Result result;
713+
if (this.TryBuildIndex(activity, packTempPath, out result, gitProcess))
711714
{
712-
GitProcess.Result result;
713-
if (!this.TryBuildIndex(activity, packTempPath, out result, gitProcess))
715+
tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, idxFlushTask: null));
716+
if (pack.IndexStream != null)
714717
{
715-
if (packFlushTask != null)
718+
try
716719
{
717-
packFlushTask.Wait();
720+
bytesDownloaded += pack.IndexStream.Length;
721+
if (pack.IndexStream.CanSeek)
722+
{
723+
pack.IndexStream.Seek(0, SeekOrigin.End);
724+
}
725+
else
726+
{
727+
pack.IndexStream.CopyTo(Stream.Null);
728+
}
729+
}
730+
catch (Exception e)
731+
{
732+
canContinue = false;
733+
EventMetadata metadata = CreateEventMetadata(e);
734+
activity.RelatedWarning(metadata, "Failed to read to end of index stream");
718735
}
719-
720-
// Move whatever has been successfully downloaded so far
721-
Exception moveException;
722-
this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out moveException);
723-
724-
return new RetryWrapper<GitObjectsHttpRequestor.GitObjectTaskResult>.CallbackResult(null, true);
725736
}
726-
727-
tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, idxFlushTask: null));
728737
}
729738
else
730739
{
731-
Task indexFlushTask;
732-
if (this.TryWriteTempFile(activity, pack.IndexStream, idxTempPath, out indexLength, out indexFlushTask))
740+
canContinue = false;
741+
}
742+
743+
if (!canContinue)
744+
{
745+
if (packFlushTask != null)
733746
{
734-
tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, indexFlushTask));
747+
packFlushTask.Wait();
735748
}
736-
else
737-
{
738-
bytesDownloaded += indexLength;
739-
740-
// Try to build the index manually, then retry the prefetch
741-
GitProcess.Result result;
742-
if (this.TryBuildIndex(activity, packTempPath, out result, gitProcess))
743-
{
744-
// If we were able to recreate the failed index
745-
// we can start the prefetch at the next timestamp
746-
tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, idxFlushTask: null));
747-
}
748-
else
749-
{
750-
if (packFlushTask != null)
751-
{
752-
packFlushTask.Wait();
753-
}
754-
}
755749

756-
// Move whatever has been successfully downloaded so far
757-
Exception moveException;
758-
this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out moveException);
750+
// Move whatever has been successfully downloaded so far
751+
Exception moveException;
752+
this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out moveException);
759753

760-
// The download stream will not be in a good state if the index download fails.
761-
// So we have to restart the prefetch
762-
return new RetryWrapper<GitObjectsHttpRequestor.GitObjectTaskResult>.CallbackResult(null, true);
763-
}
754+
return new RetryWrapper<GitObjectsHttpRequestor.GitObjectTaskResult>.CallbackResult(null, true);
764755
}
765-
766-
bytesDownloaded += indexLength;
767756
}
768757

769758
Exception exception = null;

0 commit comments

Comments
 (0)