Update Telegram SharpAESCrypt dep Update SystemIOWindows to split the difference # Conflicts: # BuildTools/AutoUpdateBuilder/AutoUpdateBuilder.csproj # BuildTools/AutoUpdateBuilder/packages.config # BuildTools/DependencyFinder/DependencyFinder.csproj # BuildTools/DependencyFinder/packages.config # BuildTools/GnupgSigningTool/GnupgSigningTool.csproj # BuildTools/UpdateVersionStamp/UpdateVersionStamp.csproj # BuildTools/UpdateVersionStamp/app.config # Duplicati/CommandLine/BackendTester/Duplicati.CommandLine.BackendTester.csproj # Duplicati/CommandLine/BackendTester/app.config # Duplicati/CommandLine/BackendTool/Duplicati.CommandLine.BackendTool.csproj # Duplicati/CommandLine/BackendTool/app.config # Duplicati/CommandLine/ConfigurationImporter/Duplicati.CommandLine.ConfigurationImporter.csproj # Duplicati/CommandLine/Duplicati.CommandLine.csproj # Duplicati/CommandLine/RecoveryTool/Duplicati.CommandLine.RecoveryTool.csproj # Duplicati/CommandLine/RecoveryTool/packages.config # Duplicati/CommandLine/app.config # Duplicati/GUI/Duplicati.GUI.TrayIcon/Duplicati.GUI.TrayIcon.csproj # Duplicati/GUI/Duplicati.GUI.TrayIcon/app.config # Duplicati/GUI/Duplicati.GUI.TrayIcon/packages.config # Duplicati/Library/AutoUpdater/Duplicati.Library.AutoUpdater.csproj # Duplicati/Library/AutoUpdater/app.config # Duplicati/Library/AutoUpdater/packages.config # Duplicati/Library/Backend/AlternativeFTP/Duplicati.Library.Backend.AlternativeFTP.csproj # Duplicati/Library/Backend/AlternativeFTP/app.config # Duplicati/Library/Backend/AlternativeFTP/packages.config # Duplicati/Library/Backend/AzureBlob/Duplicati.Library.Backend.AzureBlob.csproj # Duplicati/Library/Backend/AzureBlob/packages.config # Duplicati/Library/Backend/Backblaze/Duplicati.Library.Backend.Backblaze.csproj # Duplicati/Library/Backend/Backblaze/packages.config # Duplicati/Library/Backend/Box/Duplicati.Library.Backend.Box.csproj # Duplicati/Library/Backend/Box/packages.config # Duplicati/Library/Backend/CloudFiles/Duplicati.Library.Backend.CloudFiles.csproj # Duplicati/Library/Backend/CloudFiles/app.config # Duplicati/Library/Backend/Dropbox/Duplicati.Library.Backend.Dropbox.csproj # Duplicati/Library/Backend/Dropbox/packages.config # Duplicati/Library/Backend/FTP/Duplicati.Library.Backend.FTP.csproj # Duplicati/Library/Backend/FTP/app.config # Duplicati/Library/Backend/File/Duplicati.Library.Backend.File.csproj # Duplicati/Library/Backend/File/app.config # Duplicati/Library/Backend/GoogleServices/Duplicati.Library.Backend.GoogleServices.csproj # Duplicati/Library/Backend/GoogleServices/packages.config # Duplicati/Library/Backend/HubiC/Duplicati.Library.Backend.HubiC.csproj # Duplicati/Library/Backend/Jottacloud/Duplicati.Library.Backend.Jottacloud.csproj # Duplicati/Library/Backend/Mega/Duplicati.Library.Backend.Mega.csproj # Duplicati/Library/Backend/Mega/packages.config # Duplicati/Library/Backend/OAuthHelper/Duplicati.Library.OAuthHelper.csproj # Duplicati/Library/Backend/OAuthHelper/packages.config # Duplicati/Library/Backend/OneDrive/Duplicati.Library.Backend.OneDrive.csproj # Duplicati/Library/Backend/OneDrive/packages.config # Duplicati/Library/Backend/OpenStack/Duplicati.Library.Backend.OpenStack.csproj # Duplicati/Library/Backend/OpenStack/packages.config # Duplicati/Library/Backend/Rclone/Duplicati.Library.Backend.Rclone.csproj # Duplicati/Library/Backend/Rclone/packages.config # Duplicati/Library/Backend/S3/Duplicati.Library.Backend.S3.csproj # Duplicati/Library/Backend/S3/app.config # Duplicati/Library/Backend/S3/packages.config # Duplicati/Library/Backend/SSHv2/Duplicati.Library.Backend.SSHv2.csproj # Duplicati/Library/Backend/SSHv2/packages.config # Duplicati/Library/Backend/SharePoint/Duplicati.Library.Backend.SharePoint.csproj # Duplicati/Library/Backend/SharePoint/app.config # Duplicati/Library/Backend/Sia/Duplicati.Library.Backend.Sia.csproj # Duplicati/Library/Backend/Sia/packages.config # Duplicati/Library/Backend/TahoeLAFS/Duplicati.Library.Backend.TahoeLAFS.csproj # Duplicati/Library/Backend/TahoeLAFS/packages.config # Duplicati/Library/Backend/Tardigrade/Duplicati.Library.Backend.Tardigrade.csproj # Duplicati/Library/Backend/Tardigrade/packages.config # Duplicati/Library/Backend/WEBDAV/Duplicati.Library.Backend.WEBDAV.csproj # Duplicati/Library/Backend/WEBDAV/app.config # Duplicati/Library/Common/Duplicati.Library.Common.csproj # Duplicati/Library/Common/IO/SystemIOWindows.cs # Duplicati/Library/Common/app.config # Duplicati/Library/Common/packages.config # Duplicati/Library/Compression/Duplicati.Library.Compression.csproj # Duplicati/Library/Compression/app.config # Duplicati/Library/Compression/packages.config # Duplicati/Library/DynamicLoader/Duplicati.Library.DynamicLoader.csproj # Duplicati/Library/DynamicLoader/app.config # Duplicati/Library/Encryption/Duplicati.Library.Encryption.csproj # Duplicati/Library/Encryption/packages.config # Duplicati/Library/Interface/Duplicati.Library.Interface.csproj # Duplicati/Library/Localization/Duplicati.Library.Localization.csproj # Duplicati/Library/Localization/packages.config # Duplicati/Library/Logging/Duplicati.Library.Logging.csproj # Duplicati/Library/Logging/app.config # Duplicati/Library/Main/Duplicati.Library.Main.csproj # Duplicati/Library/Main/app.config # Duplicati/Library/Main/packages.config # Duplicati/Library/Modules/Builtin/Duplicati.Library.Modules.Builtin.csproj # Duplicati/Library/Modules/Builtin/packages.config # Duplicati/Library/SQLiteHelper/Duplicati.Library.SQLiteHelper.csproj # Duplicati/Library/Snapshots/Duplicati.Library.Snapshots.csproj # Duplicati/Library/Snapshots/app.config # Duplicati/Library/Snapshots/packages.config # Duplicati/Library/UsageReporter/Duplicati.Library.UsageReporter.csproj # Duplicati/Library/UsageReporter/packages.config # Duplicati/Library/Utility/Duplicati.Library.Utility.csproj # Duplicati/Library/Utility/app.config # Duplicati/Library/Utility/packages.config # Duplicati/License/Duplicati.License.csproj # Duplicati/Server/Duplicati.Server.Serialization/Duplicati.Server.Serialization.csproj # Duplicati/Server/Duplicati.Server.Serialization/packages.config # Duplicati/Server/Duplicati.Server.csproj # Duplicati/Server/app.config # Duplicati/Server/packages.config # Duplicati/Service/Duplicati.Service.csproj # Duplicati/Service/app.config # Duplicati/Tools/Duplicati.Tools.csproj # Duplicati/UnitTest/Duplicati.UnitTest.csproj # Duplicati/UnitTest/RestoreHandlerTests.cs # Duplicati/UnitTest/app.config # Duplicati/UnitTest/packages.config # Duplicati/WindowsService/App.config # Duplicati/WindowsService/WindowsService.csproj # Tools/SQLiteTool/App.config # Tools/SQLiteTool/SQLiteTool.csproj # thirdparty/TlsTest/TlsTest.csproj # thirdparty/UnixSupport/UnixSupport.csproj # thirdparty/mozroots/mozroots.csproj
543 lines
20 KiB
C#
543 lines
20 KiB
C#
// Copyright (C) 2015, The Duplicati Team
|
|
|
|
// http://www.duplicati.com, info@duplicati.com
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Security.AccessControl;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
using AlphaFS = Alphaleonis.Win32.Filesystem;
|
|
using Duplicati.Library.Interface;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace Duplicati.Library.Common.IO
|
|
{
|
|
public struct SystemIOWindows : ISystemIO
|
|
{
|
|
private const string UNCPREFIX = @"\\?\";
|
|
private const string UNCPREFIX_SERVER = @"\\?\UNC\";
|
|
private const string PATHPREFIX_SERVER = @"\\";
|
|
private static readonly string DIRSEP = Util.DirectorySeparatorString;
|
|
|
|
public static string PrefixWithUNC(string path)
|
|
{
|
|
if (IsPrefixedWithUNC(path))
|
|
{
|
|
return path;
|
|
}
|
|
return path.StartsWith(PATHPREFIX_SERVER, StringComparison.Ordinal)
|
|
? UNCPREFIX_SERVER + path.Substring(PATHPREFIX_SERVER.Length)
|
|
: UNCPREFIX + path;
|
|
}
|
|
|
|
private static bool IsPrefixedWithUNC(string path)
|
|
{
|
|
return path.StartsWith(UNCPREFIX_SERVER, StringComparison.Ordinal) ||
|
|
path.StartsWith(UNCPREFIX, StringComparison.Ordinal);
|
|
}
|
|
|
|
public static string StripUNCPrefix(string path)
|
|
{
|
|
if (path.StartsWith(UNCPREFIX_SERVER, StringComparison.Ordinal))
|
|
{
|
|
// @"\\?\UNC\example.com\share\file.txt" to @"\\example.com\share\file.txt"
|
|
return PATHPREFIX_SERVER + path.Substring(UNCPREFIX_SERVER.Length);
|
|
}
|
|
else if (path.StartsWith(UNCPREFIX, StringComparison.Ordinal))
|
|
{
|
|
// @"\\?\C:\file.txt" to @"C:\file.txt"
|
|
return path.Substring(UNCPREFIX.Length);
|
|
}
|
|
else
|
|
{
|
|
return path;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert forward slashes to backslashes.
|
|
/// </summary>
|
|
/// <returns>Path with forward slashes replaced by backslashes.</returns>
|
|
private static string ConvertSlashes(string path)
|
|
{
|
|
return path.Replace("/", Util.DirectorySeparatorString);
|
|
}
|
|
|
|
private class FileSystemAccess
|
|
{
|
|
// Use JsonProperty Attribute to allow readonly fields to be set by deserializer
|
|
// https://github.com/duplicati/duplicati/issues/4028
|
|
[JsonProperty]
|
|
public readonly FileSystemRights Rights;
|
|
[JsonProperty]
|
|
public readonly AccessControlType ControlType;
|
|
[JsonProperty]
|
|
public readonly string SID;
|
|
[JsonProperty]
|
|
public readonly bool Inherited;
|
|
[JsonProperty]
|
|
public readonly InheritanceFlags Inheritance;
|
|
[JsonProperty]
|
|
public readonly PropagationFlags Propagation;
|
|
|
|
public FileSystemAccess()
|
|
{
|
|
}
|
|
|
|
public FileSystemAccess(FileSystemAccessRule rule)
|
|
{
|
|
Rights = rule.FileSystemRights;
|
|
ControlType = rule.AccessControlType;
|
|
SID = rule.IdentityReference.Value;
|
|
Inherited = rule.IsInherited;
|
|
Inheritance = rule.InheritanceFlags;
|
|
Propagation = rule.PropagationFlags;
|
|
}
|
|
|
|
public FileSystemAccessRule Create(System.Security.AccessControl.FileSystemSecurity owner)
|
|
{
|
|
return (FileSystemAccessRule)owner.AccessRuleFactory(
|
|
new System.Security.Principal.SecurityIdentifier(SID),
|
|
(int)Rights,
|
|
Inherited,
|
|
Inheritance,
|
|
Propagation,
|
|
ControlType);
|
|
}
|
|
}
|
|
|
|
private static Newtonsoft.Json.JsonSerializer _cachedSerializer;
|
|
|
|
private Newtonsoft.Json.JsonSerializer Serializer
|
|
{
|
|
get
|
|
{
|
|
if (_cachedSerializer != null)
|
|
{
|
|
return _cachedSerializer;
|
|
}
|
|
|
|
_cachedSerializer = Newtonsoft.Json.JsonSerializer.Create(
|
|
new Newtonsoft.Json.JsonSerializerSettings { Culture = System.Globalization.CultureInfo.InvariantCulture });
|
|
|
|
return _cachedSerializer;
|
|
}
|
|
}
|
|
|
|
private string SerializeObject<T>(T o)
|
|
{
|
|
using (var tw = new System.IO.StringWriter())
|
|
{
|
|
Serializer.Serialize(tw, o);
|
|
tw.Flush();
|
|
return tw.ToString();
|
|
}
|
|
}
|
|
|
|
private T DeserializeObject<T>(string data)
|
|
{
|
|
using (var tr = new System.IO.StringReader(data))
|
|
{
|
|
return (T)Serializer.Deserialize(tr, typeof(T));
|
|
}
|
|
}
|
|
|
|
private System.Security.AccessControl.FileSystemSecurity GetAccessControlDir(string path)
|
|
{
|
|
return new DirectoryInfo(PrefixWithUNC(path)).GetAccessControl();
|
|
}
|
|
|
|
private System.Security.AccessControl.FileSystemSecurity GetAccessControlFile(string path)
|
|
{
|
|
return new FileInfo(PrefixWithUNC(path)).GetAccessControl();
|
|
}
|
|
|
|
private void SetAccessControlFile(string path, FileSecurity rules)
|
|
{
|
|
new FileInfo(PrefixWithUNC(path)).SetAccessControl(rules);
|
|
}
|
|
|
|
private void SetAccessControlDir(string path, DirectorySecurity rules)
|
|
{
|
|
new DirectoryInfo(PrefixWithUNC(path)).SetAccessControl(rules);
|
|
}
|
|
|
|
#region ISystemIO implementation
|
|
public void DirectoryCreate(string path)
|
|
{
|
|
System.IO.Directory.CreateDirectory(PrefixWithUNC(path));
|
|
}
|
|
|
|
public void DirectoryDelete(string path, bool recursive)
|
|
{
|
|
System.IO.Directory.Delete(PrefixWithUNC(path), recursive);
|
|
}
|
|
|
|
public bool DirectoryExists(string path)
|
|
{
|
|
return System.IO.Directory.Exists(PrefixWithUNC(path));
|
|
}
|
|
|
|
public void DirectoryMove(string sourceDirName, string destDirName)
|
|
{
|
|
System.IO.Directory.Move(PrefixWithUNC(sourceDirName), PrefixWithUNC(destDirName));
|
|
}
|
|
|
|
public void FileDelete(string path)
|
|
{
|
|
System.IO.File.Delete(PrefixWithUNC(path));
|
|
}
|
|
|
|
public void FileSetLastWriteTimeUtc(string path, DateTime time)
|
|
{
|
|
System.IO.File.SetLastWriteTimeUtc(PrefixWithUNC(path), time);
|
|
}
|
|
|
|
public void FileSetCreationTimeUtc(string path, DateTime time)
|
|
{
|
|
System.IO.File.SetCreationTimeUtc(PrefixWithUNC(path), time);
|
|
}
|
|
|
|
public DateTime FileGetLastWriteTimeUtc(string path)
|
|
{
|
|
return System.IO.File.GetLastWriteTimeUtc(PrefixWithUNC(path));
|
|
}
|
|
|
|
public DateTime FileGetCreationTimeUtc(string path)
|
|
{
|
|
return System.IO.File.GetCreationTimeUtc(PrefixWithUNC(path));
|
|
}
|
|
|
|
public bool FileExists(string path)
|
|
{
|
|
return System.IO.File.Exists(PrefixWithUNC(path));
|
|
}
|
|
|
|
public System.IO.FileStream FileOpenRead(string path)
|
|
{
|
|
return System.IO.File.Open(PrefixWithUNC(path), System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite);
|
|
}
|
|
|
|
public System.IO.FileStream FileOpenWrite(string path)
|
|
{
|
|
return !FileExists(path)
|
|
? FileCreate(path)
|
|
: System.IO.File.OpenWrite(PrefixWithUNC(path));
|
|
}
|
|
|
|
public System.IO.FileStream FileCreate(string path)
|
|
{
|
|
return System.IO.File.Create(PrefixWithUNC(path));
|
|
}
|
|
|
|
public System.IO.FileAttributes GetFileAttributes(string path)
|
|
{
|
|
return System.IO.File.GetAttributes(PrefixWithUNC(path));
|
|
}
|
|
|
|
public void SetFileAttributes(string path, System.IO.FileAttributes attributes)
|
|
{
|
|
System.IO.File.SetAttributes(PrefixWithUNC(path), attributes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the symlink target if the entry is a symlink, and null otherwise
|
|
/// </summary>
|
|
/// <param name="file">The file or folder to examine</param>
|
|
/// <returns>The symlink target</returns>
|
|
public string GetSymlinkTarget(string file)
|
|
{
|
|
try
|
|
{
|
|
return AlphaFS.File.GetLinkTargetInfo(PrefixWithUNC(file)).PrintName;
|
|
}
|
|
catch (AlphaFS.NotAReparsePointException) { }
|
|
catch (AlphaFS.UnrecognizedReparsePointException) { }
|
|
|
|
// This path looks like it isn't actually a symlink
|
|
// (Note that some reparse points aren't actually symlinks -
|
|
// things like the OneDrive folder in the Windows 10 Fall Creator's Update for example)
|
|
return null;
|
|
}
|
|
|
|
public IEnumerable<string> EnumerateFileSystemEntries(string path)
|
|
{
|
|
return System.IO.Directory.EnumerateFileSystemEntries(PrefixWithUNC(path)).Select(StripUNCPrefix);
|
|
}
|
|
|
|
public IEnumerable<string> EnumerateFiles(string path)
|
|
{
|
|
return System.IO.Directory.EnumerateFiles(PrefixWithUNC(path)).Select(StripUNCPrefix);
|
|
}
|
|
|
|
public IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOption)
|
|
{
|
|
return System.IO.Directory.EnumerateFiles(PrefixWithUNC(path), searchPattern, searchOption).Select(StripUNCPrefix);
|
|
}
|
|
|
|
public string PathGetFileName(string path)
|
|
{
|
|
return StripUNCPrefix(System.IO.Path.GetFileName(PrefixWithUNC(path)));
|
|
}
|
|
|
|
public string PathGetDirectoryName(string path)
|
|
{
|
|
return StripUNCPrefix(System.IO.Path.GetDirectoryName(PrefixWithUNC(path)));
|
|
}
|
|
|
|
public string PathGetExtension(string path)
|
|
{
|
|
return StripUNCPrefix(System.IO.Path.GetExtension(PrefixWithUNC(path)));
|
|
}
|
|
|
|
public string PathChangeExtension(string path, string extension)
|
|
{
|
|
return StripUNCPrefix(System.IO.Path.ChangeExtension(PrefixWithUNC(path), extension));
|
|
}
|
|
|
|
public void DirectorySetLastWriteTimeUtc(string path, DateTime time)
|
|
{
|
|
System.IO.Directory.SetLastWriteTimeUtc(PrefixWithUNC(path), time);
|
|
}
|
|
|
|
public void DirectorySetCreationTimeUtc(string path, DateTime time)
|
|
{
|
|
System.IO.Directory.SetCreationTimeUtc(PrefixWithUNC(path), time);
|
|
}
|
|
|
|
public void FileMove(string source, string target)
|
|
{
|
|
System.IO.File.Move(PrefixWithUNC(source), PrefixWithUNC(target));
|
|
}
|
|
|
|
public long FileLength(string path)
|
|
{
|
|
return new System.IO.FileInfo(PrefixWithUNC(path)).Length;
|
|
}
|
|
|
|
public string GetPathRoot(string path)
|
|
{
|
|
if (IsPrefixedWithUNC(path))
|
|
{
|
|
return Path.GetPathRoot(path);
|
|
}
|
|
else
|
|
{
|
|
return StripUNCPrefix(Path.GetPathRoot(PrefixWithUNC(path)));
|
|
}
|
|
}
|
|
|
|
public string[] GetDirectories(string path)
|
|
{
|
|
if (IsPrefixedWithUNC(path))
|
|
{
|
|
return Directory.GetDirectories(path);
|
|
}
|
|
else
|
|
{
|
|
return Directory.GetDirectories(PrefixWithUNC(path)).Select(StripUNCPrefix).ToArray();
|
|
}
|
|
}
|
|
|
|
public string[] GetFiles(string path)
|
|
{
|
|
if (IsPrefixedWithUNC(path))
|
|
{
|
|
return Directory.GetFiles(path);
|
|
}
|
|
else
|
|
{
|
|
return Directory.GetFiles(PrefixWithUNC(path)).Select(StripUNCPrefix).ToArray();
|
|
}
|
|
}
|
|
|
|
public string[] GetFiles(string path, string searchPattern)
|
|
{
|
|
if (IsPrefixedWithUNC(path))
|
|
{
|
|
return Directory.GetFiles(path, searchPattern);
|
|
}
|
|
else
|
|
{
|
|
return Directory.GetFiles(PrefixWithUNC(path), searchPattern).Select(StripUNCPrefix).ToArray();
|
|
}
|
|
}
|
|
|
|
public DateTime GetCreationTimeUtc(string path)
|
|
{
|
|
return Directory.GetCreationTimeUtc(PrefixWithUNC(path));
|
|
}
|
|
|
|
public DateTime GetLastWriteTimeUtc(string path)
|
|
{
|
|
return Directory.GetLastWriteTimeUtc(PrefixWithUNC(path));
|
|
}
|
|
|
|
public IEnumerable<string> EnumerateDirectories(string path)
|
|
{
|
|
if (IsPrefixedWithUNC(path))
|
|
{
|
|
return Directory.EnumerateDirectories(path);
|
|
}
|
|
else
|
|
{
|
|
return Directory.EnumerateDirectories(PrefixWithUNC(path)).Select(StripUNCPrefix);
|
|
}
|
|
}
|
|
|
|
public void FileCopy(string source, string target, bool overwrite)
|
|
{
|
|
File.Copy(PrefixWithUNC(source), PrefixWithUNC(target), overwrite);
|
|
}
|
|
|
|
public string PathGetFullPath(string path)
|
|
{
|
|
if (IsPrefixedWithUNC(path))
|
|
{
|
|
return System.IO.Path.GetFullPath(ConvertSlashes(path));
|
|
}
|
|
else
|
|
{
|
|
return StripUNCPrefix(System.IO.Path.GetFullPath(PrefixWithUNC(ConvertSlashes(path))));
|
|
}
|
|
}
|
|
|
|
public IFileEntry DirectoryEntry(string path)
|
|
{
|
|
var dInfo = new DirectoryInfo(PrefixWithUNC(path));
|
|
return new FileEntry(dInfo.Name, 0, dInfo.LastAccessTime, dInfo.LastWriteTime)
|
|
{
|
|
IsFolder = true
|
|
};
|
|
}
|
|
|
|
public IFileEntry FileEntry(string path)
|
|
{
|
|
var fileInfo = new FileInfo(PrefixWithUNC(path));
|
|
return new FileEntry(fileInfo.Name, fileInfo.Length, fileInfo.LastAccessTime, fileInfo.LastWriteTime);
|
|
}
|
|
|
|
public Dictionary<string, string> GetMetadata(string path, bool isSymlink, bool followSymlink)
|
|
{
|
|
var isDirTarget = path.EndsWith(DIRSEP, StringComparison.Ordinal);
|
|
var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path;
|
|
var dict = new Dictionary<string, string>();
|
|
|
|
FileSystemSecurity rules = isDirTarget ? GetAccessControlDir(targetpath) : GetAccessControlFile(targetpath);
|
|
var objs = new List<FileSystemAccess>();
|
|
foreach (var f in rules.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier)))
|
|
objs.Add(new FileSystemAccess((FileSystemAccessRule)f));
|
|
|
|
dict["win-ext:accessrules"] = SerializeObject(objs);
|
|
|
|
// Only include the following key when its value is True.
|
|
// This prevents unnecessary 'metadata change' detections when upgrading from
|
|
// older versions (pre-2.0.5.101) that didn't store this value at all.
|
|
// When key is not present, its value is presumed False by the restore code.
|
|
if (rules.AreAccessRulesProtected)
|
|
{
|
|
dict["win-ext:accessrulesprotected"] = "True";
|
|
}
|
|
|
|
return dict;
|
|
}
|
|
|
|
public void SetMetadata(string path, Dictionary<string, string> data, bool restorePermissions)
|
|
{
|
|
var isDirTarget = path.EndsWith(DIRSEP, StringComparison.Ordinal);
|
|
var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path;
|
|
|
|
if (restorePermissions)
|
|
{
|
|
FileSystemSecurity rules = isDirTarget ? GetAccessControlDir(targetpath) : GetAccessControlFile(targetpath);
|
|
|
|
if (data.ContainsKey("win-ext:accessrulesprotected"))
|
|
{
|
|
bool isProtected = bool.Parse(data["win-ext:accessrulesprotected"]);
|
|
if (rules.AreAccessRulesProtected != isProtected)
|
|
{
|
|
rules.SetAccessRuleProtection(isProtected, false);
|
|
}
|
|
}
|
|
|
|
if (data.ContainsKey("win-ext:accessrules"))
|
|
{
|
|
var content = DeserializeObject<FileSystemAccess[]>(data["win-ext:accessrules"]);
|
|
var c = rules.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier));
|
|
for (var i = c.Count - 1; i >= 0; i--)
|
|
rules.RemoveAccessRule((System.Security.AccessControl.FileSystemAccessRule)c[i]);
|
|
|
|
Exception ex = null;
|
|
|
|
foreach (var r in content)
|
|
{
|
|
// Attempt to apply as many rules as we can
|
|
try
|
|
{
|
|
rules.AddAccessRule(r.Create(rules));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ex = e;
|
|
}
|
|
}
|
|
|
|
if (ex != null)
|
|
throw ex;
|
|
}
|
|
|
|
if (isDirTarget)
|
|
SetAccessControlDir(targetpath, (DirectorySecurity)rules);
|
|
else
|
|
SetAccessControlFile(targetpath, (FileSecurity)rules);
|
|
}
|
|
}
|
|
|
|
public string PathCombine(params string[] paths)
|
|
{
|
|
return Path.Combine(paths);
|
|
}
|
|
|
|
public void CreateSymlink(string symlinkfile, string target, bool asDir)
|
|
{
|
|
if (FileExists(symlinkfile) || DirectoryExists(symlinkfile))
|
|
throw new System.IO.IOException(string.Format("File already exists: {0}", symlinkfile));
|
|
|
|
if (asDir)
|
|
{
|
|
Alphaleonis.Win32.Filesystem.Directory.CreateSymbolicLink(PrefixWithUNC(symlinkfile), target, AlphaFS.PathFormat.LongFullPath);
|
|
}
|
|
else
|
|
{
|
|
Alphaleonis.Win32.Filesystem.File.CreateSymbolicLink(PrefixWithUNC(symlinkfile), target, AlphaFS.PathFormat.LongFullPath);
|
|
}
|
|
|
|
//Sadly we do not get a notification if the creation fails :(
|
|
System.IO.FileAttributes attr = 0;
|
|
if ((!asDir && FileExists(symlinkfile)) || (asDir && DirectoryExists(symlinkfile)))
|
|
try { attr = GetFileAttributes(symlinkfile); }
|
|
catch { }
|
|
|
|
if ((attr & System.IO.FileAttributes.ReparsePoint) == 0)
|
|
throw new System.IO.IOException(string.Format("Unable to create symlink, check account permissions: {0}", symlinkfile));
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
|