Skip to content
Draft
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
37 changes: 37 additions & 0 deletions GVFS/GVFS.Common/IScheduledTaskInvoker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Collections.Generic;

namespace GVFS.Common
{
/// <summary>
/// Abstracts the Windows Task Scheduler operations needed by
/// <see cref="LogonTaskRegistration"/>. Production callers use
/// <see cref="SchTasksScheduledTaskInvoker"/>; tests pass a mock so
/// they can exercise <see cref="LogonTaskRegistration"/>'s logic
/// without actually touching the Task Scheduler on the test machine.
/// </summary>
public interface IScheduledTaskInvoker
{
/// <summary>
/// Register the task at <paramref name="taskPath"/> from the given
/// XML, overwriting any existing task at that path. Returns
/// <c>true</c> on success.
/// </summary>
bool TryRegisterFromXml(string taskPath, string xml, out string errorMessage);

/// <summary>
/// Read back the registered XML for the task at
/// <paramref name="taskPath"/>. Returns <c>true</c> with the XML
/// when the task exists; returns <c>false</c> with a populated
/// <paramref name="errorMessage"/> when it does not.
/// </summary>
bool TryQueryXml(string taskPath, out string xml, out string errorMessage);

/// <summary>
/// Unregister the task at <paramref name="taskPath"/>. Returns
/// <c>true</c> if the task was unregistered OR was not registered
/// to begin with (idempotent). Returns <c>false</c> only on a hard
/// failure (e.g., permission denied).
/// </summary>
bool TryUnregister(string taskPath, out string errorMessage);
}
}
64 changes: 64 additions & 0 deletions GVFS/GVFS.Common/LocalRepoRegistration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace GVFS.Common
{
/// <summary>
/// One entry in the user-level repo registry on disk. Field set and
/// JSON shape MUST match GVFS.Service.RepoRegistration so that the
/// user-level registry file (written by <see cref="LocalRepoRegistry"/>)
/// is wire-compatible with any registry the legacy service has written
/// in the past. If a new field is added here, the same field must also
/// be added to GVFS.Service.RepoRegistration (and vice versa) along
/// with a registry-format-version bump.
/// </summary>
public class LocalRepoRegistration
{
public LocalRepoRegistration()
{
}

public LocalRepoRegistration(string enlistmentRoot, string ownerSID)
{
this.EnlistmentRoot = enlistmentRoot;
this.OwnerSID = ownerSID;
this.IsActive = true;
}

public string EnlistmentRoot { get; set; }
public string OwnerSID { get; set; }
public bool IsActive { get; set; }

// Uses LocalRepoRegistrationJsonContext (assembly-local source generator)
// rather than GVFSJsonContext. The service-side RepoRegistration uses
// its own ServiceJsonContext for the same reason — neither type can be
// registered in GVFSJsonContext because GVFSJsonContext lives in
// GVFS.Common and the service-side type lives in GVFS.Service (wrong
// dependency direction). Keeping symmetric local contexts here means
// the on-disk JSON shape is governed by identical source-gen behavior
// on both sides.
public static LocalRepoRegistration FromJson(string json)
{
return JsonSerializer.Deserialize(json, LocalRepoRegistrationJsonContext.Default.LocalRepoRegistration);
}

public string ToJson()
{
return JsonSerializer.Serialize(this, LocalRepoRegistrationJsonContext.Default.LocalRepoRegistration);
}

public override string ToString()
{
return string.Format(
"({0} - {1}) {2}",
this.IsActive ? "Active" : "Inactive",
this.OwnerSID,
this.EnlistmentRoot);
}
}

[JsonSerializable(typeof(LocalRepoRegistration))]
internal partial class LocalRepoRegistrationJsonContext : JsonSerializerContext
{
}
}
Loading
Loading