private GitProcess.Result TryAddPackFile(Stream contents, bool unpackObjects, GitProcess gitProcess) { GitProcess.Result result; this.fileSystem.CreateDirectory(this.Enlistment.GitPackRoot); if (unpackObjects) { result = new GitProcess(this.Enlistment).UnpackObjects(contents); } else { string tempPackPath = this.WriteTempPackFile(contents); return(this.IndexTempPackFile(tempPackPath, gitProcess)); } return(result); }
/// <summary> /// Uses a <see cref="PrefetchPacksDeserializer"/> to read the packs from the stream. /// </summary> private RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult DeserializePrefetchPacks( GitEndPointResponseData response, ref long latestTimestamp, ref long bytesDownloaded, ref List <string> packIndexes, GitProcess gitProcess) { if (packIndexes == null) { packIndexes = new List <string>(); } using (ITracer activity = this.Tracer.StartActivity("DeserializePrefetchPacks", EventLevel.Informational)) { PrefetchPacksDeserializer deserializer = new PrefetchPacksDeserializer(response.Stream); string tempPackFolderPath = Path.Combine(this.Enlistment.GitPackRoot, TempPackFolder); this.fileSystem.CreateDirectory(tempPackFolderPath); List <TempPrefetchPackAndIdx> tempPacks = new List <TempPrefetchPackAndIdx>(); foreach (PrefetchPacksDeserializer.PackAndIndex pack in deserializer.EnumeratePacks()) { // The advertised size may not match the actual, on-disk size. long indexLength = 0; long packLength; // Write the temp and index to a temp folder to avoid putting corrupt files in the pack folder // Once the files are validated and flushed they can be moved to the pack folder string packName = string.Format("{0}-{1}-{2}.pack", GSDConstants.PrefetchPackPrefix, pack.Timestamp, pack.UniqueId); string packTempPath = Path.Combine(tempPackFolderPath, packName); string idxName = string.Format("{0}-{1}-{2}.idx", GSDConstants.PrefetchPackPrefix, pack.Timestamp, pack.UniqueId); string idxTempPath = Path.Combine(tempPackFolderPath, idxName); EventMetadata data = CreateEventMetadata(); data["timestamp"] = pack.Timestamp.ToString(); data["uniqueId"] = pack.UniqueId; activity.RelatedEvent(EventLevel.Informational, "Receiving Pack/Index", data); // Write the pack // If it fails, TryWriteTempFile cleans up the file and we retry the prefetch Task packFlushTask; if (!this.TryWriteTempFile(activity, pack.PackStream, packTempPath, out packLength, out packFlushTask)) { bytesDownloaded += packLength; return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(null, true)); } bytesDownloaded += packLength; // We will try to build an index if the server does not send one if (pack.IndexStream == null) { GitProcess.Result result; if (!this.TryBuildIndex(activity, packTempPath, out result, gitProcess)) { if (packFlushTask != null) { packFlushTask.Wait(); } // Move whatever has been successfully downloaded so far Exception moveException; this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out moveException); return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(null, true)); } tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, idxFlushTask: null)); } else { Task indexFlushTask; if (this.TryWriteTempFile(activity, pack.IndexStream, idxTempPath, out indexLength, out indexFlushTask)) { tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, indexFlushTask)); } else { bytesDownloaded += indexLength; // Try to build the index manually, then retry the prefetch GitProcess.Result result; if (this.TryBuildIndex(activity, packTempPath, out result, gitProcess)) { // If we were able to recreate the failed index // we can start the prefetch at the next timestamp tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, idxFlushTask: null)); } else { if (packFlushTask != null) { packFlushTask.Wait(); } } // Move whatever has been successfully downloaded so far Exception moveException; this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out moveException); // The download stream will not be in a good state if the index download fails. // So we have to restart the prefetch return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(null, true)); } } bytesDownloaded += indexLength; } Exception exception = null; if (!this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out exception)) { return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(exception, true)); } foreach (TempPrefetchPackAndIdx tempPack in tempPacks) { packIndexes.Add(tempPack.IdxName); } return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult( new GitObjectsHttpRequestor.GitObjectTaskResult(success: true))); } }
private X509Certificate2 GetCertificateFromFile(ITracer tracer, EventMetadata metadata, GitProcess gitProcess) { string certificatePassword = null; if (this.isCertificatePasswordProtected) { certificatePassword = this.GetCertificatePassword(tracer, gitProcess); if (string.IsNullOrEmpty(certificatePassword)) { tracer.RelatedWarning( metadata, "Git config indicates, that certificate is password protected, but retrieved password was null or empty!"); } metadata.Add("isPasswordSpecified", string.IsNullOrEmpty(certificatePassword)); } if (this.fileSystem.FileExists(this.certificatePathOrSubjectCommonName)) { try { byte[] certificateContent = this.fileSystem.ReadAllBytes(this.certificatePathOrSubjectCommonName); X509Certificate2 cert = new X509Certificate2(certificateContent, certificatePassword); if (this.ShouldVerify && cert != null && !this.certificateVerifier.Verify(cert)) { tracer.RelatedWarning(metadata, "Certficate was found, but is invalid."); return(null); } return(cert); } catch (CryptographicException cryptEx) { metadata.Add("Exception", cryptEx.ToString()); tracer.RelatedError(metadata, "Error, while loading certificate from disk"); return(null); } } return(null); }
public virtual GitProcess.Result IndexPackFile(string packfilePath, GitProcess gitProcess) { string tempIdxPath = Path.ChangeExtension(packfilePath, TempIdxExtension); string idxPath = Path.ChangeExtension(packfilePath, ".idx"); Exception indexPackException = null; try { if (gitProcess == null) { gitProcess = new GitProcess(this.Enlistment); } GitProcess.Result result = gitProcess.IndexPack(packfilePath, tempIdxPath); if (result.ExitCodeIsFailure) { Exception exception; if (!this.fileSystem.TryDeleteFile(tempIdxPath, exception: out exception)) { EventMetadata metadata = CreateEventMetadata(exception); metadata.Add("tempIdxPath", tempIdxPath); this.Tracer.RelatedWarning(metadata, $"{nameof(this.IndexPackFile)}: Failed to cleanup temp idx file after index pack failure"); } } else { if (this.Enlistment.FlushFileBuffersForPacks) { Exception exception; string error; if (!this.TryFlushFileBuffers(tempIdxPath, out exception, out error)) { EventMetadata metadata = CreateEventMetadata(exception); metadata.Add("packfilePath", packfilePath); metadata.Add("tempIndexPath", tempIdxPath); metadata.Add("error", error); this.Tracer.RelatedWarning(metadata, $"{nameof(this.IndexPackFile)}: Failed to flush temp idx file buffers"); } } this.fileSystem.MoveAndOverwriteFile(tempIdxPath, idxPath); } return(result); } catch (Win32Exception e) { indexPackException = e; } catch (IOException e) { indexPackException = e; } catch (UnauthorizedAccessException e) { indexPackException = e; } EventMetadata failureMetadata = CreateEventMetadata(indexPackException); failureMetadata.Add("packfilePath", packfilePath); failureMetadata.Add("tempIdxPath", tempIdxPath); failureMetadata.Add("idxPath", idxPath); this.fileSystem.TryDeleteFile(tempIdxPath, metadataKey: nameof(tempIdxPath), metadata: failureMetadata); this.fileSystem.TryDeleteFile(idxPath, metadataKey: nameof(idxPath), metadata: failureMetadata); this.Tracer.RelatedWarning(failureMetadata, $"{nameof(this.IndexPackFile): Exception caught while trying to index pack file}"); return(new GitProcess.Result( string.Empty, indexPackException != null ? indexPackException.Message : "Failed to index pack file", GitProcess.Result.GenericFailureCode)); }
public void ConfigureHttpClientHandlerSslIfNeeded(ITracer tracer, HttpClientHandler httpClientHandler, GitProcess gitProcess) { X509Certificate2 cert = this.GitSsl?.GetCertificate(tracer, gitProcess); if (cert != null) { if (this.GitSsl != null && !this.GitSsl.ShouldVerify) { httpClientHandler.ServerCertificateCustomValidationCallback = (httpRequestMessage, c, cetChain, policyErrors) => { return(true); }; } httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual; httpClientHandler.ClientCertificates.Add(cert); } }