Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion GVFS/GVFS.Common/FileSystem/IKernelDriver.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GVFS.Common.Tracing;
using System;

namespace GVFS.Common.FileSystem
{
Expand All @@ -8,7 +9,7 @@ public interface IKernelDriver
string DriverLogFolderName { get; }
bool IsSupported(string normalizedEnlistmentRootPath, out string warning, out string error);
string FlushDriverLogs();
bool TryPrepareFolderForCallbacks(string folderPath, out string error);
bool TryPrepareFolderForCallbacks(string folderPath, out string error, out Exception exception);
bool IsReady(JsonTracer tracer, string enlistmentRoot, out string error);
}
}
3 changes: 2 additions & 1 deletion GVFS/GVFS.Platform.Mac/ProjFSKext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ public bool IsReady(JsonTracer tracer, string enlistmentRoot, out string error)
return true;
}

public bool TryPrepareFolderForCallbacks(string folderPath, out string error)
public bool TryPrepareFolderForCallbacks(string folderPath, out string error, out Exception exception)
{
exception = null;
error = string.Empty;
Result result = VirtualizationInstance.ConvertDirectoryToVirtualizationRoot(folderPath);
if (result != Result.Success)
Expand Down
51 changes: 42 additions & 9 deletions GVFS/GVFS.Platform.Windows/ProjFSFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class ProjFSFilter : IKernelDriver
private const string FilterLoggerSessionName = "Microsoft-Windows-ProjFS-Filter-Log";

private const string ProjFSNativeLibFileName = "ProjectedFSLib.dll";
private const string ProjFSManagedLibFileName = "ProjectedFSLib.Managed.dll";

private const uint OkResult = 0;
private const uint NameCollisionErrorResult = 0x801F0012;
Expand Down Expand Up @@ -320,18 +321,34 @@ public string FlushDriverLogs()
return sb.ToString();
}

public bool TryPrepareFolderForCallbacks(string folderPath, out string error)
public bool TryPrepareFolderForCallbacks(string folderPath, out string error, out Exception exception)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: both of the out params are only used for tracing errors. Should this method just take an ITracer as an input param and writes out its own errors?

Copy link
Copy Markdown
Member Author

@wilbaker wilbaker Sep 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both of the out params are only used for tracing errors

@sanoursa, the exception parameter is only used for tracing, but the error out param is used for both tracing and for letter the user know (on the command line) why their clone has failed.

I can update TryPrepareFolderForCallbacks to take an ITracer (and remove the out exception), but we'd still need an out error parameter.

Let me know if you think it's worth making that change.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed with @sanoursa offline and I will merge this in as-is.

{
error = string.Empty;
Guid virtualizationInstanceGuid = Guid.NewGuid();
HResult result = VirtualizationInstance.ConvertDirectoryToVirtualizationRoot(virtualizationInstanceGuid, folderPath);
if (result != HResult.Ok)
exception = null;
try
{
error = "Failed to prepare \"" + folderPath + "\" for callbacks, error: " + result.ToString("F");
return false;
return this.TryPrepareFolderForCallbacksImpl(folderPath, out error);
}
catch (FileNotFoundException e)
{
exception = e;

return true;
if (e.FileName.Equals(ProjFSManagedLibFileName, StringComparison.OrdinalIgnoreCase))
{
error = $"Failed to load {ProjFSManagedLibFileName}. Ensure that ProjFS is installed and enabled";
}
else
{
error = $"FileNotFoundException while trying to prepare \"{folderPath}\" for callbacks: {e.Message}";
}

return false;
}
catch (Exception e)
{
exception = e;
error = $"Exception while trying to prepare \"{folderPath}\" for callbacks: {e.Message}";
return false;
}
}

// TODO 1050199: Once the service is an optional component, GVFS should only attempt to attach
Expand Down Expand Up @@ -562,7 +579,23 @@ private static EventMetadata CreateEventMetadata(Exception e = null)
private static ProcessResult CallPowershellCommand(string command)
{
return ProcessHelper.Run("powershell.exe", "-NonInteractive -NoProfile -Command \"& { " + command + " }\"");
}
}

// Using an Impl method allows TryPrepareFolderForCallbacks to catch any ProjFS dependency related exceptions
// thrown in the process of calling this method.
private bool TryPrepareFolderForCallbacksImpl(string folderPath, out string error)
{
error = string.Empty;
Guid virtualizationInstanceGuid = Guid.NewGuid();
HResult result = VirtualizationInstance.ConvertDirectoryToVirtualizationRoot(virtualizationInstanceGuid, folderPath);
if (result != HResult.Ok)
{
error = "Failed to prepare \"" + folderPath + "\" for callbacks, error: " + result.ToString("F");
return false;
}

return true;
}

private static class NativeMethods
{
Expand Down
12 changes: 10 additions & 2 deletions GVFS/GVFS/CommandLine/CloneVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,18 @@ private Result CreateClone(
}

// Prepare the working directory folder for GVFS last to ensure that gvfs mount will fail if gvfs clone has failed
Exception exception;
string prepFileSystemError;
if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out prepFileSystemError))
if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out prepFileSystemError, out exception))
{
tracer.RelatedError(prepFileSystemError);
EventMetadata metadata = new EventMetadata();
metadata.Add(nameof(prepFileSystemError), prepFileSystemError);
if (exception != null)
{
metadata.Add("Exception", exception.ToString());
}

tracer.RelatedError(metadata, $"{nameof(this.CreateClone)}: TryPrepareFolderForCallbacks failed");
return new Result(prepFileSystemError);
}

Expand Down
11 changes: 10 additions & 1 deletion GVFS/GVFS/CommandLine/DehydrateVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,18 @@ private void Mount(ITracer tracer)

private void PrepareSrcFolder(ITracer tracer, GVFSEnlistment enlistment)
{
Exception exception;
string error;
if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out error))
if (!GVFSPlatform.Instance.KernelDriver.TryPrepareFolderForCallbacks(enlistment.WorkingDirectoryRoot, out error, out exception))
{
EventMetadata metadata = new EventMetadata();
metadata.Add(nameof(error), error);
if (exception != null)
{
metadata.Add("Exception", exception.ToString());
}

tracer.RelatedError(metadata, $"{nameof(this.PrepareSrcFolder)}: TryPrepareFolderForCallbacks failed");
this.ReportErrorAndExit(tracer, "Failed to recreate the virtualization root: " + error);
}
}
Expand Down