mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
import new reparsepoint library for windows
This commit is contained in:
14
src/lib-csharp/Util/ReparsePoint/COPYRIGHT.txt
Normal file
14
src/lib-csharp/Util/ReparsePoint/COPYRIGHT.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
Copyright © 2015 NCode Group
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
60
src/lib-csharp/Util/ReparsePoint/Enums.cs
Normal file
60
src/lib-csharp/Util/ReparsePoint/Enums.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright © 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace NCode.ReparsePoints
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the type of reparse point such as a hard link, junction (aka
|
||||
/// soft link), or symbolic link.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
internal enum LinkType
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an unknown reparse point type.
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a file <c>hard link</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Technically not a reparse point.
|
||||
/// </remarks>
|
||||
HardLink,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a directory <c>junction</c> (aka soft link).
|
||||
/// </summary>
|
||||
Junction,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a <c>symbolic link</c> to either a file or folder.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In order to create symbolic links, the current user must either be an
|
||||
/// administrator running with elevated privileges or a non-admin user that
|
||||
/// has the SeCreateSymbolicLinkPrivilege right in local security policy.
|
||||
/// </remarks>
|
||||
Symbolic
|
||||
}
|
||||
}
|
||||
859
src/lib-csharp/Util/ReparsePoint/Interop/Enums.cs
Normal file
859
src/lib-csharp/Util/ReparsePoint/Interop/Enums.cs
Normal file
@@ -0,0 +1,859 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright © 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace NCode.ReparsePoints.Win32
|
||||
{
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374896(v=vs.85).aspx
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374892(v=vs.85).aspx
|
||||
/// </remarks>
|
||||
[Flags]
|
||||
[Serializable]
|
||||
internal enum AccessRights : uint
|
||||
{
|
||||
None = 0x0,
|
||||
|
||||
/// <summary>
|
||||
/// The MAXIMUM_ALLOWED access type is generally used with the AccessCheck(…)
|
||||
/// function to determine whether a security descriptor grants a specified
|
||||
/// set of access rights to the client identified by an access token.
|
||||
/// Typically, server applications use this function to check access to a
|
||||
/// private object. Note that MAXIMUM_ALLOWED cannot be used in an ACE (see
|
||||
/// access control entries).
|
||||
/// </summary>
|
||||
/// <remarks>MAXIMUM_ALLOWED</remarks>
|
||||
MaximumAllowed = 0x02000000,
|
||||
|
||||
#region Standard Access Rights
|
||||
|
||||
/// <summary>
|
||||
/// The right to delete the object.
|
||||
/// </summary>
|
||||
/// <remarks>DELETE</remarks>
|
||||
Delete = 0x00010000,
|
||||
|
||||
/// <summary>
|
||||
/// The right to read the information in the object's security descriptor,
|
||||
/// not including the information in the system access control list (SACL).
|
||||
/// </summary>
|
||||
/// <remarks>READ_CONTROL</remarks>
|
||||
ReadControl = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// The right to modify the discretionary access control list (DACL) in the
|
||||
/// object's security descriptor.
|
||||
/// </summary>
|
||||
/// <remarks>WRITE_DAC</remarks>
|
||||
WriteDac = 0x00040000,
|
||||
|
||||
/// <summary>
|
||||
/// The right to change the owner in the object's security descriptor.
|
||||
/// </summary>
|
||||
/// <remarks>WRITE_OWNER</remarks>
|
||||
WriteOwner = 0x00080000,
|
||||
|
||||
/// <summary>
|
||||
/// The right to use the object for synchronization. This enables a thread
|
||||
/// to wait until the object is in the signaled state. Some object types do not support this access right.
|
||||
/// </summary>
|
||||
/// <remarks>SYNCHRONIZE</remarks>
|
||||
Synchronize = 0x00100000,
|
||||
|
||||
/// <summary>
|
||||
/// Currently defined to equal READ_CONTROL.
|
||||
/// </summary>
|
||||
/// <remarks>STANDARD_RIGHTS_READ</remarks>
|
||||
StandardRightsRead = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Currently defined to equal READ_CONTROL.
|
||||
/// </summary>
|
||||
/// <remarks>STANDARD_RIGHTS_WRITE</remarks>
|
||||
StandardRightsWrite = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Currently defined to equal READ_CONTROL.
|
||||
/// </summary>
|
||||
/// <remarks>STANDARD_RIGHTS_EXECUTE</remarks>
|
||||
StandardRightsExecute = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access.
|
||||
/// </summary>
|
||||
/// <remarks>STANDARD_RIGHTS_REQUIRED</remarks>
|
||||
StandardRightsRequired = 0x000F0000,
|
||||
|
||||
/// <summary>
|
||||
/// Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and SYNCHRONIZE access.
|
||||
/// </summary>
|
||||
/// <remarks>STANDARD_RIGHTS_ALL</remarks>
|
||||
StandardRightsAll = 0x001F0000,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Generic Access Rights
|
||||
|
||||
/// <summary>
|
||||
/// Execute access.
|
||||
/// </summary>
|
||||
/// <remarks>GENERIC_EXECUTE</remarks>
|
||||
GenericExecute = 0x20000000,
|
||||
|
||||
/// <summary>
|
||||
/// Write access.
|
||||
/// </summary>
|
||||
/// <remarks>GENERIC_WRITE</remarks>
|
||||
GenericWrite = 0x40000000,
|
||||
|
||||
/// <summary>
|
||||
/// Read access.
|
||||
/// </summary>
|
||||
/// <remarks>GENERIC_READ</remarks>
|
||||
GenericRead = 0x80000000,
|
||||
|
||||
/// <summary>
|
||||
/// All possible access rights.
|
||||
/// </summary>
|
||||
/// <remarks>GENERIC_ALL</remarks>
|
||||
GenericAll = 0x10000000,
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Security and Access Rights
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364399(v=vs.85).aspx
|
||||
|
||||
/// <summary>
|
||||
/// For a file object, the right to read the corresponding file data. For
|
||||
/// a directory object, the right to read the corresponding directory data.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_READ_DATA</remarks>
|
||||
FileReadData = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// For a directory, the right to list the contents of the directory.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_LIST_DIRECTORY</remarks>
|
||||
FileListDirectory = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// For a file object, the right to write data to the file. For a directory
|
||||
/// object, the right to create a file in the directory (FILE_ADD_FILE).
|
||||
/// </summary>
|
||||
/// <remarks>FILE_WRITE_DATA</remarks>
|
||||
FileWriteData = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// For a directory, the right to create a file in the directory.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ADD_FILE</remarks>
|
||||
FileAddFile = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// For a file object, the right to append data to the file. (For local
|
||||
/// files, write operations will not overwrite existing data if this flag
|
||||
/// is specified without FILE_WRITE_DATA.) For a directory object, the
|
||||
/// right to create a subdirectory (FILE_ADD_SUBDIRECTORY).
|
||||
/// </summary>
|
||||
/// <remarks>FILE_APPEND_DATA</remarks>
|
||||
FileAppendData = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// For a directory, the right to create a subdirectory.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ADD_SUBDIRECTORY</remarks>
|
||||
FileAddSubdirectory = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// For a named pipe, the right to create a pipe.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_CREATE_PIPE_INSTANCE</remarks>
|
||||
FileCreatePipeInstance = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// The right to read extended file attributes.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_READ_EA</remarks>
|
||||
FileReadExtendedAttributes = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// The right to write extended file attributes.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_WRITE_EA</remarks>
|
||||
FileWriteExtendedAttributes = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// For a native code file, the right to execute the file. This access
|
||||
/// right given to scripts may cause the script to be executable,
|
||||
/// depending on the script interpreter.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_EXECUTE</remarks>
|
||||
FileExecute = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// For a directory, the right to traverse the directory. By default, users
|
||||
/// are assigned the BYPASS_TRAVERSE_CHECKING privilege, which ignores the
|
||||
/// FILE_TRAVERSE access right. See the remarks in File Security and Access
|
||||
/// Rights for more information.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_TRAVERSE</remarks>
|
||||
FileTraverse = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// For a directory, the right to delete a directory and all the files it
|
||||
/// contains, including read-only files.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_DELETE_CHILD</remarks>
|
||||
FileDeleteChild = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// The right to read file attributes.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_READ_ATTRIBUTES</remarks>
|
||||
FileReadAttributes = 0x0080,
|
||||
|
||||
/// <summary>
|
||||
/// The right to write file attributes.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_WRITE_ATTRIBUTES</remarks>
|
||||
FileWriteAttributes = 0x0100,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Thread Security and Access Rights
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686769(v=vs.85).aspx
|
||||
|
||||
/// <summary>
|
||||
/// Required to terminate a thread using TerminateThread.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_TERMINATE</remarks>
|
||||
ThreadTerminate = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Required to suspend or resume a thread (see SuspendThread and ResumeThread).
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_SUSPEND_RESUME</remarks>
|
||||
ThreadSuspendResume = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Required to read the context of a thread using GetThreadContext.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_GET_CONTEXT</remarks>
|
||||
ThreadGetContext = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// Required to write the context of a thread using SetThreadContext.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_SET_CONTEXT</remarks>
|
||||
ThreadSetContext = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// Required to set certain information in the thread object.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_SET_INFORMATION</remarks>
|
||||
ThreadSetInformation = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// Required to read certain information from the thread object, such as the exit code (see GetExitCodeThread).
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_QUERY_INFORMATION</remarks>
|
||||
ThreadQueryInformation = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// Required to set the impersonation token for a thread using SetThreadToken.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_SET_THREAD_TOKEN</remarks>
|
||||
ThreadSetThreadToken = 0x0080,
|
||||
|
||||
/// <summary>
|
||||
/// Required to use a thread's security information directly without calling it by using a communication mechanism that provides impersonation services.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_IMPERSONATE</remarks>
|
||||
ThreadImpersonate = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// Required for a server thread that impersonates a client.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_DIRECT_IMPERSONATION</remarks>
|
||||
ThreadDirectImpersonation = 0x0200,
|
||||
|
||||
/// <summary>
|
||||
/// All possible access rights for a thread object.
|
||||
/// </summary>
|
||||
/// <remarks>THREAD_ALL_ACCESS</remarks>
|
||||
ThreadAllAccess = (StandardRightsRequired | Synchronize | 0x3FF),
|
||||
|
||||
#endregion
|
||||
|
||||
#region Process Security and Access Rights
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx
|
||||
|
||||
/// <summary>
|
||||
/// Required to terminate a process using TerminateProcess.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_TERMINATE</remarks>
|
||||
ProcessTerminate = 0x00000001,
|
||||
|
||||
/// <summary>
|
||||
/// Required to create a thread.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_CREATE_THREAD</remarks>
|
||||
ProcessCreateThread = 0x00000002,
|
||||
|
||||
/// <summary>
|
||||
/// Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_VM_OPERATION</remarks>
|
||||
ProcessVmOperation = 0x00000008,
|
||||
|
||||
/// <summary>
|
||||
/// Required to read memory in a process using ReadProcessMemory.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_VM_READ</remarks>
|
||||
ProcessVmRead = 0x00000010,
|
||||
|
||||
/// <summary>
|
||||
/// Required to write to memory in a process using WriteProcessMemory.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_VM_WRITE</remarks>
|
||||
ProcessVmWrite = 0x00000020,
|
||||
|
||||
/// <summary>
|
||||
/// Required to duplicate a handle using DuplicateHandle.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_DUP_HANDLE</remarks>
|
||||
ProcessDupHandle = 0x00000040,
|
||||
|
||||
/// <summary>
|
||||
/// Required to create a process.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_CREATE_PROCESS</remarks>
|
||||
ProcessCreateProcess = 0x00000080,
|
||||
|
||||
/// <summary>
|
||||
/// Required to set memory limits using SetProcessWorkingSetSize.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_SET_QUOTA</remarks>
|
||||
ProcessSetQuota = 0x00000100,
|
||||
|
||||
/// <summary>
|
||||
/// Required to set certain information about a process, such as its priority class (see SetPriorityClass).
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_SET_INFORMATION</remarks>
|
||||
ProcessSetInformation = 0x00000200,
|
||||
|
||||
/// <summary>
|
||||
/// Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken).
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_QUERY_INFORMATION</remarks>
|
||||
ProcessQueryInformation = 0x00000400,
|
||||
|
||||
/// <summary>
|
||||
/// All possible access rights for a process object.
|
||||
/// </summary>
|
||||
/// <remarks>PROCESS_ALL_ACCESS</remarks>
|
||||
ProcessAllAccess = (StandardRightsRequired | Synchronize | 0xFFF),
|
||||
|
||||
#endregion
|
||||
|
||||
#region Token Security and Access Rights
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374905(v=vs.85).aspx
|
||||
|
||||
/// <summary>
|
||||
/// Required to attach a primary token to a process. The SE_ASSIGNPRIMARYTOKEN_NAME privilege is also required to accomplish this task.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_ASSIGN_PRIMARY</remarks>
|
||||
TokenAssignPrimary = 0x0001,
|
||||
|
||||
/// <summary>
|
||||
/// Required to duplicate an access token.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_DUPLICATE</remarks>
|
||||
TokenDuplicate = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// Required to attach an impersonation access token to a process.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_IMPERSONATE</remarks>
|
||||
TokenImpersonate = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// Required to query an access token.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_QUERY</remarks>
|
||||
TokenQuery = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// Required to query the source of an access token.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_QUERY_SOURCE</remarks>
|
||||
TokenQuerySource = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// Required to enable or disable the privileges in an access token.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_ADJUST_PRIVILEGES</remarks>
|
||||
TokenAdjustPrivileges = 0x0020,
|
||||
|
||||
/// <summary>
|
||||
/// Required to adjust the attributes of the groups in an access token.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_ADJUST_GROUPS</remarks>
|
||||
TokenAdjustGroups = 0x0040,
|
||||
|
||||
/// <summary>
|
||||
/// Required to change the default owner, primary group, or DACL of an access token.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_ADJUST_DEFAULT</remarks>
|
||||
TokenAdjustDefault = 0x0080,
|
||||
|
||||
/// <summary>
|
||||
/// Required to adjust the session ID of an access token. The SE_TCB_NAME privilege is required.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_ADJUST_SESSIONID</remarks>
|
||||
TokenAdjustSessionid = 0x0100,
|
||||
|
||||
/// <summary>
|
||||
/// Combines STANDARD_RIGHTS_READ and TOKEN_QUERY.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_READ</remarks>
|
||||
TokenRead = (StandardRightsRead | TokenQuery),
|
||||
|
||||
/// <summary>
|
||||
/// Combines STANDARD_RIGHTS_WRITE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, and TOKEN_ADJUST_DEFAULT.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_WRITE</remarks>
|
||||
TokenWrite = (StandardRightsWrite | TokenAdjustPrivileges | TokenAdjustGroups | TokenAdjustDefault),
|
||||
|
||||
/// <summary>
|
||||
/// Combines STANDARD_RIGHTS_EXECUTE and TOKEN_IMPERSONATE.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_EXECUTE</remarks>
|
||||
TokenExecute = (StandardRightsExecute | TokenImpersonate),
|
||||
|
||||
/// <summary>
|
||||
/// Combines all possible access rights for a token.
|
||||
/// </summary>
|
||||
/// <remarks>TOKEN_ALL_ACCESS</remarks>
|
||||
TokenAllAccess = (StandardRightsRequired | TokenAssignPrimary | TokenDuplicate | TokenImpersonate | TokenQuery | TokenQuerySource |
|
||||
TokenAdjustPrivileges | TokenAdjustGroups | TokenAdjustDefault | TokenAdjustSessionid),
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[Serializable]
|
||||
internal enum FileShareMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Prevents other processes from opening a file or device if they request
|
||||
/// delete, read, or write access.
|
||||
/// </summary>
|
||||
None = 0x00000000,
|
||||
|
||||
/// <summary>
|
||||
/// Enables subsequent open operations on a file or device to request read
|
||||
/// access. Otherwise, other processes cannot open the file or device if
|
||||
/// they request read access. If this flag is not specified, but the file
|
||||
/// or device has been opened for read access, the function fails.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_SHARE_READ</remarks>
|
||||
FileShareRead = 0x00000001,
|
||||
|
||||
/// <summary>
|
||||
/// Enables subsequent open operations on a file or device to request write
|
||||
/// access. Otherwise, other processes cannot open the file or device if
|
||||
/// they request write access. If this flag is not specified, but the file
|
||||
/// or device has been opened for write access or has a file mapping with
|
||||
/// write access, the function fails.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_SHARE_WRITE</remarks>
|
||||
FileShareWrite = 0x00000002,
|
||||
|
||||
/// <summary>
|
||||
/// Enables subsequent open operations on a file or device to request delete
|
||||
/// access. Otherwise, other processes cannot open the file or device if
|
||||
/// they request delete access. If this flag is not specified, but the file
|
||||
/// or device has been opened for delete access, the function fails. Note
|
||||
/// Delete access allows both delete and rename operations.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_SHARE_DELETE</remarks>
|
||||
FileShareDelete = 0x00000004,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal enum FileCreationDisposition
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new file, only if it does not already exist. If the specified
|
||||
/// file exists, the function fails and the last-error code is set to
|
||||
/// ERROR_FILE_EXISTS (80). If the specified file does not exist and is a
|
||||
/// valid path to a writable location, a new file is created.
|
||||
/// </summary>
|
||||
/// <remarks>CREATE_NEW</remarks>
|
||||
CreateNew = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new file, always. If the specified file exists and is writable,
|
||||
/// the function overwrites the file, the function succeeds, and last-error
|
||||
/// code is set to ERROR_ALREADY_EXISTS (183). If the specified file does
|
||||
/// not exist and is a valid path, a new file is created, the function
|
||||
/// succeeds, and the last-error code is set to zero. For more information,
|
||||
/// see the Remarks section of this topic.
|
||||
/// </summary>
|
||||
/// <remarks>CREATE_ALWAYS</remarks>
|
||||
CreateAlways = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file or device, only if it exists. If the specified file or
|
||||
/// device does not exist, the function fails and the last-error code is
|
||||
/// set to ERROR_FILE_NOT_FOUND (2). For more information about devices,
|
||||
/// see the Remarks section.
|
||||
/// </summary>
|
||||
/// <remarks>OPEN_EXISTING</remarks>
|
||||
OpenExisting = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file, always. If the specified file exists, the function
|
||||
/// succeeds and the last-error code is set to ERROR_ALREADY_EXISTS (183).
|
||||
/// If the specified file does not exist and is a valid path to a writable
|
||||
/// location, the function creates a file and the last-error code is set to
|
||||
/// zero.
|
||||
/// </summary>
|
||||
/// <remarks>OPEN_ALWAYS</remarks>
|
||||
OpenAlways = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file and truncates it so that its size is zero bytes, only if
|
||||
/// it exists. If the specified file does not exist, the function fails and
|
||||
/// the last-error code is set to ERROR_FILE_NOT_FOUND (2). The calling
|
||||
/// process must open the file with the GENERIC_WRITE bit set as part of
|
||||
/// the dwDesiredAccess parameter.
|
||||
/// </summary>
|
||||
/// <remarks>TRUNCATE_EXISTING</remarks>
|
||||
TruncateExisting = 5,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[Serializable]
|
||||
internal enum FileAttributeFlags : uint
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
|
||||
|
||||
#region File Attributes
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx
|
||||
|
||||
/// <summary>
|
||||
/// A file that is read-only. Applications can read the file, but cannot
|
||||
/// write to it or delete it. This attribute is not honored on directories.
|
||||
/// For more information, see You cannot view or change the Read-only or
|
||||
/// the System attributes of folders in Windows Server 2003, in Windows XP,
|
||||
/// in Windows Vista or in Windows 7.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_READONLY</remarks>
|
||||
FileAttributeReadonly = 0x1,
|
||||
|
||||
/// <summary>
|
||||
/// The file or directory is hidden. It is not included in an ordinary
|
||||
/// directory listing.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_HIDDEN</remarks>
|
||||
FileAttributeHidden = 0x2,
|
||||
|
||||
/// <summary>
|
||||
/// A file or directory that the operating system uses a part of, or uses
|
||||
/// exclusively.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_SYSTEM</remarks>
|
||||
FileAttributeSystem = 0x4,
|
||||
|
||||
/// <summary>
|
||||
/// The handle that identifies a directory.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_DIRECTORY</remarks>
|
||||
FileAttributeDirectory = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// A file or directory that is an archive file or directory. Applications
|
||||
/// typically use this attribute to mark files for backup or removal.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_ARCHIVE</remarks>
|
||||
FileAttributeArchive = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// This value is reserved for system use.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_DEVICE</remarks>
|
||||
FileAttributeDevice = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// A file that does not have other attributes set. This attribute is valid
|
||||
/// only when used alone.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_NORMAL</remarks>
|
||||
FileAttributeNormal = 0x80,
|
||||
|
||||
/// <summary>
|
||||
/// A file that is being used for temporary storage. File systems avoid
|
||||
/// writing data back to mass storage if sufficient cache memory is
|
||||
/// available, because typically, an application deletes a temporary file
|
||||
/// after the handle is closed. In that scenario, the system can entirely
|
||||
/// avoid writing the data. Otherwise, the data is written after the handle
|
||||
/// is closed.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_TEMPORARY</remarks>
|
||||
FileAttributeTemporary = 0x100,
|
||||
|
||||
/// <summary>
|
||||
/// A file that is a sparse file.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_SPARSE_FILE</remarks>
|
||||
FileAttributeSparseFile = 0x200,
|
||||
|
||||
/// <summary>
|
||||
/// A file or directory that has an associated reparse point, or a file
|
||||
/// that is a symbolic link.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_REPARSE_POINT</remarks>
|
||||
FileAttributeReparsePoint = 0x400,
|
||||
|
||||
/// <summary>
|
||||
/// A file or directory that is compressed. For a file, all of the data in
|
||||
/// the file is compressed. For a directory, compression is the default for
|
||||
/// newly created files and subdirectories.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_COMPRESSED</remarks>
|
||||
FileAttributeCompressed = 0x800,
|
||||
|
||||
/// <summary>
|
||||
/// The data of a file is not immediately available. This attribute
|
||||
/// indicates that file data is physically moved to offline storage.
|
||||
/// This attribute is used by Remote Storage, the hierarchical storage
|
||||
/// management software. Applications should not arbitrarily change this
|
||||
/// attribute.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_OFFLINE</remarks>
|
||||
FileAttributeOffline = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// The file or directory is not to be indexed by the content indexing
|
||||
/// service.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_NOT_CONTENT_INDEXED</remarks>
|
||||
FileAttributeNotContentIndexed = 0x2000,
|
||||
|
||||
/// <summary>
|
||||
/// A file or directory that is encrypted. For a file, all data streams in
|
||||
/// the file are encrypted. For a directory, encryption is the default for
|
||||
/// newly created files and subdirectories.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_ENCRYPTED</remarks>
|
||||
FileAttributeEncrypted = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// The directory or user data stream is configured with integrity (only
|
||||
/// supported on ReFS volumes). It is not included in an ordinary directory
|
||||
/// listing. The integrity setting persists with the file if it's renamed.
|
||||
/// If a file is copied the destination file will have integrity set if
|
||||
/// either the source file or destination directory have integrity set.
|
||||
/// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista,
|
||||
/// Windows Server 2003, and Windows XP: This flag is not supported until
|
||||
/// Windows Server 2012.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_INTEGRITY_STREAM</remarks>
|
||||
FileAttributeIntegrityStream = 0x8000,
|
||||
|
||||
/// <summary>
|
||||
/// This value is reserved for system use.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_VIRTUAL</remarks>
|
||||
FileAttributeVirtual = 0x10000,
|
||||
|
||||
/// <summary>
|
||||
/// The user data stream not to be read by the background data integrity
|
||||
/// scanner (AKA scrubber). When set on a directory it only provides
|
||||
/// inheritance. This flag is only supported on Storage Spaces and ReFS
|
||||
/// volumes. It is not included in an ordinary directory listing. Windows
|
||||
/// Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows
|
||||
/// Server 2003, and Windows XP: This flag is not supported until Windows
|
||||
/// 8 and Windows Server 2012.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_ATTRIBUTE_NO_SCRUB_DATA</remarks>
|
||||
FileAttributeNoScrubData = 0x20000,
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Flags
|
||||
|
||||
/// <summary>
|
||||
/// If you attempt to create multiple instances of a pipe with this flag,
|
||||
/// creation of the first instance succeeds, but creation of the next
|
||||
/// instance fails with ERROR_ACCESS_DENIED. Windows 2000: This flag is
|
||||
/// not supported until Windows 2000 SP2 and Windows XP.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_FIRST_PIPE_INSTANCE</remarks>
|
||||
FileFlagFirstPipeInstance = 0x00080000,
|
||||
|
||||
/// <summary>
|
||||
/// The file data is requested, but it should continue to be located in
|
||||
/// remote storage. It should not be transported back to local storage.
|
||||
/// This flag is for use by remote storage systems.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_OPEN_NO_RECALL</remarks>
|
||||
FileFlagOpenNoRecall = 0x00100000,
|
||||
|
||||
/// <summary>
|
||||
/// Access will occur according to POSIX rules. This includes allowing
|
||||
/// multiple files with names, differing only in case, for file systems
|
||||
/// that support that naming. Use care when using this option, because
|
||||
/// files created with this flag may not be accessible by applications
|
||||
/// that are written for MS-DOS or 16-bit Windows.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_POSIX_SEMANTICS</remarks>
|
||||
FileFlagPosixSemantics = 0x00100000,
|
||||
|
||||
/// <summary>
|
||||
/// Normal reparse point processing will not occur; CreateFile will attempt
|
||||
/// to open the reparse point. When a file is opened, a file handle is
|
||||
/// returned, whether or not the filter that controls the reparse point is
|
||||
/// operational. This flag cannot be used with the CREATE_ALWAYS flag. If
|
||||
/// the file is not a reparse point, then this flag is ignored. For more
|
||||
/// information, see the Remarks section.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_OPEN_REPARSE_POINT</remarks>
|
||||
FileFlagOpenReparsePoint = 0x00200000,
|
||||
|
||||
/// <summary>
|
||||
/// The file or device is being opened with session awareness. If this flag
|
||||
/// is not specified, then per-session devices (such as a redirected USB
|
||||
/// device) cannot be opened by processes running in session 0. This flag
|
||||
/// has no effect for callers not in session 0. This flag is supported only
|
||||
/// on server editions of Windows. Windows Server 2008 R2, Windows Server
|
||||
/// 2008, and Windows Server 2003: This flag is not supported before Windows
|
||||
/// Server 2012.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_SESSION_AWARE</remarks>
|
||||
FileFlagSessionAware = 0x00800000,
|
||||
|
||||
/// <summary>
|
||||
/// The file is being opened or created for a backup or restore operation.
|
||||
/// The system ensures that the calling process overrides file security
|
||||
/// checks when the process has SE_BACKUP_NAME and SE_RESTORE_NAME
|
||||
/// privileges. For more information, see Changing Privileges in a Token.
|
||||
/// You must set this flag to obtain a handle to a directory. A directory
|
||||
/// handle can be passed to some functions instead of a file handle. For
|
||||
/// more information, see the Remarks section.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_BACKUP_SEMANTICS</remarks>
|
||||
FileFlagBackupSemantics = 0x02000000,
|
||||
|
||||
/// <summary>
|
||||
/// The file is to be deleted immediately after all of its handles are
|
||||
/// closed, which includes the specified handle and any other open or
|
||||
/// duplicated handles. If there are existing open handles to a file, the
|
||||
/// call fails unless they were all opened with the FILE_SHARE_DELETE share
|
||||
/// mode. Subsequent open requests for the file fail, unless the
|
||||
/// FILE_SHARE_DELETE share mode is specified.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_DELETE_ON_CLOSE</remarks>
|
||||
FileFlagDeleteOnClose = 0x04000000,
|
||||
|
||||
/// <summary>
|
||||
/// Access is intended to be sequential from beginning to end. The system
|
||||
/// can use this as a hint to optimize file caching. This flag should not
|
||||
/// be used if read-behind (that is, reverse scans) will be used. This flag
|
||||
/// has no effect if the file system does not support cached I/O and
|
||||
/// FILE_FLAG_NO_BUFFERING. For more information, see the Caching Behavior
|
||||
/// section of this topic.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_SEQUENTIAL_SCAN</remarks>
|
||||
FileFlagSequentialScan = 0x08000000,
|
||||
|
||||
/// <summary>
|
||||
/// Access is intended to be random. The system can use this as a hint to
|
||||
/// optimize file caching. This flag has no effect if the file system does
|
||||
/// not support cached I/O and FILE_FLAG_NO_BUFFERING. For more information,
|
||||
/// see the Caching Behavior section of this topic.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_RANDOM_ACCESS</remarks>
|
||||
FileFlagRandomAccess = 0x10000000,
|
||||
|
||||
/// <summary>
|
||||
/// The file or device is being opened with no system caching for data
|
||||
/// reads and writes. This flag does not affect hard disk caching or memory
|
||||
/// mapped files. There are strict requirements for successfully working
|
||||
/// with files opened with CreateFile using the FILE_FLAG_NO_BUFFERING
|
||||
/// flag, for details see File Buffering.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_NO_BUFFERING</remarks>
|
||||
FileFlagNoBuffering = 0x20000000,
|
||||
|
||||
/// <summary>
|
||||
/// The file or device is being opened or created for asynchronous I/O.
|
||||
/// When subsequent I/O operations are completed on this handle, the event
|
||||
/// specified in the OVERLAPPED structure will be set to the signaled state.
|
||||
/// If this flag is specified, the file can be used for simultaneous read
|
||||
/// and write operations. If this flag is not specified, then I/O operations
|
||||
/// are serialized, even if the calls to the read and write functions
|
||||
/// specify an OVERLAPPED structure. For information about considerations
|
||||
/// when using a file handle created with this flag, see the Synchronous
|
||||
/// and Asynchronous I/O Handles section of this topic.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_OVERLAPPED</remarks>
|
||||
FileFlagOverlapped = 0x40000000,
|
||||
|
||||
/// <summary>
|
||||
/// Write operations will not go through any intermediate cache, they will
|
||||
/// go directly to disk. For additional information, see the Caching
|
||||
/// Behavior section of this topic.
|
||||
/// </summary>
|
||||
/// <remarks>FILE_FLAG_WRITE_THROUGH</remarks>
|
||||
FileFlagWriteThrough = unchecked(0x80000000),
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[Serializable]
|
||||
internal enum AllocFlags : uint
|
||||
{
|
||||
//LMEM_FIXED
|
||||
Fixed = 0x00,
|
||||
|
||||
//LMEM_MOVEABLE
|
||||
Moveable = 0x02,
|
||||
|
||||
//LMEM_ZEROINIT
|
||||
ZeroInit = 0x40,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal enum SymbolicLinkFlag : uint
|
||||
{
|
||||
File = 0,
|
||||
Directory = 1,
|
||||
}
|
||||
}
|
||||
122
src/lib-csharp/Util/ReparsePoint/Interop/NativeMethods.cs
Normal file
122
src/lib-csharp/Util/ReparsePoint/Interop/NativeMethods.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright <20> 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
#pragma warning disable SYSLIB0004
|
||||
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace NCode.ReparsePoints.Win32
|
||||
{
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
internal static class NativeMethods
|
||||
{
|
||||
private const string Kernel32 = "kernel32.dll";
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern SafeFindHandle FindFirstFile(
|
||||
[In]
|
||||
string lpFileName,
|
||||
[Out]
|
||||
out Win32FindData lpFindFileData);
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool FindClose(
|
||||
[In]
|
||||
IntPtr hFindFile);
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool DeviceIoControl(
|
||||
[In]
|
||||
SafeFileHandle hDevice,
|
||||
[In]
|
||||
uint dwIoControlCode,
|
||||
[In]
|
||||
SafeLocalAllocHandle lpInBuffer,
|
||||
[In]
|
||||
int nInBufferSize,
|
||||
[In]
|
||||
SafeLocalAllocHandle lpOutBuffer,
|
||||
[In]
|
||||
int nOutBufferSize,
|
||||
[Out]
|
||||
out int lpBytesReturned,
|
||||
[In]
|
||||
IntPtr lpOverlapped);
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern SafeFileHandle CreateFile(
|
||||
[In]
|
||||
string lpFileName,
|
||||
[In]
|
||||
AccessRights dwDesiredAccess,
|
||||
[In]
|
||||
FileShareMode dwShareMode,
|
||||
[In]
|
||||
IntPtr lpSecurityAttributes,
|
||||
[In]
|
||||
FileCreationDisposition dwCreationDisposition,
|
||||
[In]
|
||||
FileAttributeFlags dwFlagsAndAttributes,
|
||||
[In]
|
||||
IntPtr hTemplateFile);
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CreateHardLink(
|
||||
[In]
|
||||
string lpFileName,
|
||||
[In]
|
||||
string lpExistingFileName,
|
||||
[In]
|
||||
IntPtr lpSecurityAttributes);
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
public static extern bool CreateSymbolicLink(
|
||||
[In]
|
||||
string lpSymlinkFileName,
|
||||
[In]
|
||||
string lpTargetFileName,
|
||||
[In]
|
||||
SymbolicLinkFlag dwFlags);
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
public static extern SafeLocalAllocHandle LocalAlloc(
|
||||
[In]
|
||||
AllocFlags flags,
|
||||
[In]
|
||||
IntPtr cb);
|
||||
|
||||
[DllImport(Kernel32, SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public static extern IntPtr LocalFree(
|
||||
[In]
|
||||
IntPtr handle);
|
||||
}
|
||||
}
|
||||
68
src/lib-csharp/Util/ReparsePoint/Interop/ReparseData.cs
Normal file
68
src/lib-csharp/Util/ReparsePoint/Interop/ReparseData.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright <20> 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NCode.ReparsePoints.Win32
|
||||
{
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ReparseHeader
|
||||
{
|
||||
public uint ReparseTag;
|
||||
public ushort ReparseDataLength;
|
||||
|
||||
public ushort Reserved;
|
||||
// next in memory:
|
||||
// ReparseData
|
||||
// SubstituteName
|
||||
// PrintName
|
||||
}
|
||||
|
||||
internal interface IReparseData
|
||||
{
|
||||
ushort SubstituteNameOffset { get; }
|
||||
ushort SubstituteNameLength { get; }
|
||||
ushort PrintNameOffset { get; }
|
||||
ushort PrintNameLength { get; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct JunctionData : IReparseData
|
||||
{
|
||||
public ushort SubstituteNameOffset { get; set; }
|
||||
public ushort SubstituteNameLength { get; set; }
|
||||
public ushort PrintNameOffset { get; set; }
|
||||
public ushort PrintNameLength { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct SymbolicData : IReparseData
|
||||
{
|
||||
public ushort SubstituteNameOffset { get; set; }
|
||||
public ushort SubstituteNameLength { get; set; }
|
||||
public ushort PrintNameOffset { get; set; }
|
||||
public ushort PrintNameLength { get; set; }
|
||||
public uint Flags { get; set; }
|
||||
}
|
||||
}
|
||||
48
src/lib-csharp/Util/ReparsePoint/Interop/SafeFindHandle.cs
Normal file
48
src/lib-csharp/Util/ReparsePoint/Interop/SafeFindHandle.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright <20> 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Security;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace NCode.ReparsePoints.Win32
|
||||
{
|
||||
[SecurityCritical]
|
||||
internal class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
public SafeFindHandle()
|
||||
: base(true)
|
||||
{
|
||||
// do not delete this ctor
|
||||
// it is required for pinvoke
|
||||
}
|
||||
|
||||
public SafeFindHandle(IntPtr handle)
|
||||
: base(true)
|
||||
{
|
||||
SetHandle(handle);
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return NativeMethods.FindClose(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
107
src/lib-csharp/Util/ReparsePoint/Interop/SafeLocalAllocHandle.cs
Normal file
107
src/lib-csharp/Util/ReparsePoint/Interop/SafeLocalAllocHandle.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright © 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace NCode.ReparsePoints.Win32
|
||||
{
|
||||
[SecurityCritical]
|
||||
internal class SafeLocalAllocHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
#region Static Members
|
||||
|
||||
public static SafeLocalAllocHandle InvalidHandle {
|
||||
get { return new SafeLocalAllocHandle(IntPtr.Zero); }
|
||||
}
|
||||
|
||||
public static SafeLocalAllocHandle Allocate(int cb)
|
||||
{
|
||||
return Allocate(new IntPtr(cb));
|
||||
}
|
||||
|
||||
public static SafeLocalAllocHandle Allocate(IntPtr cb)
|
||||
{
|
||||
return NativeMethods.LocalAlloc(AllocFlags.Fixed, cb);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected SafeLocalAllocHandle()
|
||||
: base(true)
|
||||
{
|
||||
// do not delete this ctor
|
||||
// it is required for pinvoke
|
||||
}
|
||||
|
||||
public SafeLocalAllocHandle(IntPtr handle)
|
||||
: base(true)
|
||||
{
|
||||
SetHandle(handle);
|
||||
}
|
||||
|
||||
public virtual int Write(int position, byte[] buffer, int offset, int count)
|
||||
{
|
||||
Marshal.Copy(buffer, offset, handle + position, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
public virtual int Write<T>(int position, T value) where T : notnull
|
||||
{
|
||||
var count = Marshal.SizeOf(value);
|
||||
Marshal.StructureToPtr(value, handle + position, false);
|
||||
return count;
|
||||
}
|
||||
|
||||
public virtual T Read<
|
||||
#if NET7_0_OR_GREATER
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
|
||||
#endif
|
||||
T>(
|
||||
int position) where T : notnull
|
||||
{
|
||||
var value = Marshal.PtrToStructure<T>(handle + position);
|
||||
return value!;
|
||||
}
|
||||
|
||||
public virtual void Read(int position, byte[] buffer, int offset, int count)
|
||||
{
|
||||
Marshal.Copy(handle + position, buffer, offset, count);
|
||||
}
|
||||
|
||||
public virtual string ReadString(int position, int byteCount, Encoding encoding)
|
||||
{
|
||||
var bytes = new byte[byteCount];
|
||||
Read(position, bytes, 0, byteCount);
|
||||
var str = encoding.GetString(bytes);
|
||||
return str;
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return NativeMethods.LocalFree(handle) == IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/lib-csharp/Util/ReparsePoint/Interop/Win32Constants.cs
Normal file
44
src/lib-csharp/Util/ReparsePoint/Interop/Win32Constants.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright © 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
namespace NCode.ReparsePoints.Win32
|
||||
{
|
||||
internal static class Win32Constants
|
||||
{
|
||||
public const int MaxPath = 260;
|
||||
|
||||
public const int ERROR_INSUFFICIENT_BUFFER = 122;
|
||||
public const int ERROR_NOT_A_REPARSE_POINT = 4390;
|
||||
|
||||
public const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003;
|
||||
public const uint IO_REPARSE_TAG_SYMLINK = 0xA000000C;
|
||||
|
||||
public const uint FSCTL_SET_REPARSE_POINT = 0x000900A4;
|
||||
public const uint FSCTL_GET_REPARSE_POINT = 0x000900A8;
|
||||
|
||||
public const string NonInterpretedPathPrefix = "\\??\\";
|
||||
|
||||
public static readonly string[] DosDevicePrefixes = {
|
||||
"\\??\\",
|
||||
"\\DosDevices\\",
|
||||
"\\Global??\\"
|
||||
};
|
||||
}
|
||||
}
|
||||
45
src/lib-csharp/Util/ReparsePoint/Interop/Win32FindData.cs
Normal file
45
src/lib-csharp/Util/ReparsePoint/Interop/Win32FindData.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright <20> 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
|
||||
|
||||
namespace NCode.ReparsePoints.Win32
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct Win32FindData
|
||||
{
|
||||
public FileAttributes FileAttributes;
|
||||
public FILETIME CreationTime;
|
||||
public FILETIME LastAccessTime;
|
||||
public FILETIME LastWriteTime;
|
||||
public int FileSizeHigh;
|
||||
public int FileSizeLow;
|
||||
public uint Reserved0;
|
||||
public uint Reserved1;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = Win32Constants.MaxPath)]
|
||||
public string FileName;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
|
||||
public string AlternateFileName;
|
||||
}
|
||||
}
|
||||
177
src/lib-csharp/Util/ReparsePoint/LICENSE.txt
Normal file
177
src/lib-csharp/Util/ReparsePoint/LICENSE.txt
Normal file
@@ -0,0 +1,177 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
49
src/lib-csharp/Util/ReparsePoint/ReparseLink.cs
Normal file
49
src/lib-csharp/Util/ReparsePoint/ReparseLink.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright <20> 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace NCode.ReparsePoints
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the information about a reparse point.
|
||||
/// </summary>
|
||||
internal struct ReparseLink
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains the <see cref="FileAttributes"/> of a reparse point.
|
||||
/// </summary>
|
||||
public FileAttributes Attributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the <see cref="LinkType"/> of a reparse point.
|
||||
/// </summary>
|
||||
public LinkType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains the target of a reparse point.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The target for a hard link cannot be determined so this member will
|
||||
/// always be <c>null</c> for hard links.
|
||||
/// </remarks>
|
||||
public string Target { get; set; }
|
||||
}
|
||||
}
|
||||
282
src/lib-csharp/Util/ReparsePoint/ReparsePointProvider.cs
Normal file
282
src/lib-csharp/Util/ReparsePoint/ReparsePointProvider.cs
Normal file
@@ -0,0 +1,282 @@
|
||||
#region Copyright Preamble
|
||||
|
||||
//
|
||||
// Copyright © 2015 NCode Group
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using NCode.ReparsePoints.Win32;
|
||||
|
||||
namespace NCode.ReparsePoints
|
||||
{
|
||||
internal class ReparsePointProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Given a path, determines the type of reparse point.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to inspect.</param>
|
||||
/// <returns>A <see cref="LinkType"/> enumeration.</returns>
|
||||
public virtual LinkType GetLinkType(string path)
|
||||
{
|
||||
Win32FindData data;
|
||||
using (var handle = NativeMethods.FindFirstFile(path, out data)) {
|
||||
if (handle.IsInvalid)
|
||||
return LinkType.Unknown;
|
||||
|
||||
if (!data.FileAttributes.HasFlag(FileAttributes.ReparsePoint)) {
|
||||
return data.FileAttributes.HasFlag(FileAttributes.Directory)
|
||||
? LinkType.Unknown
|
||||
: LinkType.HardLink;
|
||||
}
|
||||
|
||||
switch (data.Reserved0) {
|
||||
case Win32Constants.IO_REPARSE_TAG_SYMLINK:
|
||||
return LinkType.Symbolic;
|
||||
|
||||
case Win32Constants.IO_REPARSE_TAG_MOUNT_POINT:
|
||||
return LinkType.Junction;
|
||||
}
|
||||
}
|
||||
|
||||
return LinkType.Unknown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a path, returns the information about a reparse point.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to inspect.</param>
|
||||
/// <returns>A <see cref="ReparseLink"/> that contains the information
|
||||
/// about a reparse point.</returns>
|
||||
public virtual ReparseLink GetLink(string path)
|
||||
{
|
||||
FileAttributes attributes;
|
||||
try {
|
||||
attributes = File.GetAttributes(path);
|
||||
} catch (DirectoryNotFoundException) {
|
||||
return new ReparseLink();
|
||||
} catch (FileNotFoundException) {
|
||||
return new ReparseLink();
|
||||
}
|
||||
|
||||
var link = new ReparseLink {
|
||||
Attributes = attributes
|
||||
};
|
||||
|
||||
if (!attributes.HasFlag(FileAttributes.ReparsePoint)) {
|
||||
link.Type = attributes.HasFlag(FileAttributes.Directory)
|
||||
? LinkType.Unknown
|
||||
: LinkType.HardLink;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
var encoding = Encoding.Unicode;
|
||||
var reparseHeaderSize = Marshal.SizeOf<ReparseHeader>();
|
||||
var bufferLength = reparseHeaderSize + 2048;
|
||||
|
||||
using (var hReparsePoint = OpenReparsePoint(path, AccessRights.GenericRead)) {
|
||||
int error;
|
||||
do {
|
||||
using (var buffer = SafeLocalAllocHandle.Allocate(bufferLength)) {
|
||||
int bytesReturned;
|
||||
var b = NativeMethods.DeviceIoControl(
|
||||
hReparsePoint,
|
||||
Win32Constants.FSCTL_GET_REPARSE_POINT,
|
||||
SafeLocalAllocHandle.InvalidHandle,
|
||||
0,
|
||||
buffer,
|
||||
bufferLength,
|
||||
out bytesReturned,
|
||||
IntPtr.Zero);
|
||||
error = Marshal.GetLastWin32Error();
|
||||
|
||||
if (b) {
|
||||
var reparseHeader = buffer.Read<ReparseHeader>(0);
|
||||
|
||||
IReparseData data;
|
||||
switch (reparseHeader.ReparseTag) {
|
||||
case Win32Constants.IO_REPARSE_TAG_MOUNT_POINT:
|
||||
data = buffer.Read<JunctionData>(reparseHeaderSize);
|
||||
link.Type = LinkType.Junction;
|
||||
break;
|
||||
|
||||
case Win32Constants.IO_REPARSE_TAG_SYMLINK:
|
||||
data = buffer.Read<SymbolicData>(reparseHeaderSize);
|
||||
link.Type = LinkType.Symbolic;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
String.Format(
|
||||
"An unknown reparse tag {0:X} was encountered.",
|
||||
reparseHeader.ReparseTag));
|
||||
}
|
||||
|
||||
var offset = Marshal.SizeOf(data) + reparseHeaderSize;
|
||||
var target = buffer.ReadString(offset + data.SubstituteNameOffset, data.SubstituteNameLength, encoding);
|
||||
|
||||
link.Target = ParseDosDevicePath(target);
|
||||
return link;
|
||||
}
|
||||
|
||||
if (error == Win32Constants.ERROR_INSUFFICIENT_BUFFER) {
|
||||
var reparseHeader = buffer.Read<ReparseHeader>(0);
|
||||
bufferLength = reparseHeader.ReparseDataLength;
|
||||
} else {
|
||||
throw new Win32Exception(error);
|
||||
}
|
||||
}
|
||||
} while (error == Win32Constants.ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
public virtual void CreateHardLink(string file, string target)
|
||||
{
|
||||
if (!NativeMethods.CreateHardLink(file, target, IntPtr.Zero))
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
public virtual void CreateSymbolicLink(string path, string target, bool isDirectory)
|
||||
{
|
||||
var flags = isDirectory
|
||||
? SymbolicLinkFlag.Directory
|
||||
: SymbolicLinkFlag.File;
|
||||
|
||||
if (!NativeMethods.CreateSymbolicLink(path, target, flags))
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to create a junction.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the junction to create.</param>
|
||||
/// <param name="target">The target for the junction.</param>
|
||||
public virtual void CreateJunction(string path, string target)
|
||||
{
|
||||
path = Path.GetFullPath(path);
|
||||
target = Path.GetFullPath(target);
|
||||
|
||||
Win32FindData data;
|
||||
using (var handle = NativeMethods.FindFirstFile(path, out data)) {
|
||||
if (!handle.IsInvalid)
|
||||
throw new InvalidOperationException("A file or folder already exists with the same name as the junction.");
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
var encoding = Encoding.Unicode;
|
||||
var nullChar = new byte[] { 0, 0 };
|
||||
|
||||
var printName = ParseDosDevicePath(target);
|
||||
var printNameBytes = encoding.GetBytes(printName);
|
||||
var printNameLength = printNameBytes.Length;
|
||||
|
||||
var substituteName = FormatDosDevicePath(printName, false);
|
||||
var substituteNameBytes = encoding.GetBytes(substituteName);
|
||||
var substituteNameLength = substituteNameBytes.Length;
|
||||
|
||||
var junction = new JunctionData {
|
||||
SubstituteNameOffset = 0,
|
||||
SubstituteNameLength = checked((ushort) substituteNameLength),
|
||||
PrintNameOffset = checked((ushort) (substituteNameLength + nullChar.Length)),
|
||||
PrintNameLength = checked((ushort) printNameLength)
|
||||
};
|
||||
|
||||
var junctionLength = Marshal.SizeOf(junction) + nullChar.Length * 2;
|
||||
var reparseLength = junctionLength + junction.SubstituteNameLength + junction.PrintNameLength;
|
||||
|
||||
var reparse = new ReparseHeader {
|
||||
ReparseTag = Win32Constants.IO_REPARSE_TAG_MOUNT_POINT,
|
||||
ReparseDataLength = checked((ushort) (reparseLength)),
|
||||
Reserved = 0,
|
||||
};
|
||||
|
||||
var bufferLength = Marshal.SizeOf(reparse) + reparse.ReparseDataLength;
|
||||
|
||||
using (var hReparsePoint = OpenReparsePoint(path, AccessRights.GenericWrite))
|
||||
using (var buffer = SafeLocalAllocHandle.Allocate(bufferLength)) {
|
||||
var offset = buffer.Write(0, reparse);
|
||||
offset += buffer.Write(offset, junction);
|
||||
offset += buffer.Write(offset, substituteNameBytes, 0, substituteNameBytes.Length);
|
||||
offset += buffer.Write(offset, nullChar, 0, nullChar.Length);
|
||||
offset += buffer.Write(offset, printNameBytes, 0, printNameBytes.Length);
|
||||
offset += buffer.Write(offset, nullChar, 0, nullChar.Length);
|
||||
Debug.Assert(offset == bufferLength);
|
||||
|
||||
int bytesReturned;
|
||||
var b = NativeMethods.DeviceIoControl(
|
||||
hReparsePoint,
|
||||
Win32Constants.FSCTL_SET_REPARSE_POINT,
|
||||
buffer,
|
||||
bufferLength,
|
||||
SafeLocalAllocHandle.InvalidHandle,
|
||||
0,
|
||||
out bytesReturned,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (!b) throw new Win32Exception();
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatDosDevicePath(string path, bool sanitize)
|
||||
{
|
||||
if (sanitize)
|
||||
path = ParseDosDevicePath(path);
|
||||
|
||||
return Win32Constants.NonInterpretedPathPrefix + path + "\\";
|
||||
}
|
||||
|
||||
private static string ParseDosDevicePath(string path)
|
||||
{
|
||||
var result = Win32Constants
|
||||
.DosDevicePrefixes
|
||||
.Where(prefix => path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
|
||||
.Aggregate(path, (current, prefix) => current.Remove(0, prefix.Length));
|
||||
|
||||
while (result.EndsWith("\\"))
|
||||
result = result.Remove(result.Length - 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static SafeFileHandle OpenReparsePoint(string reparsePoint, AccessRights accessRights)
|
||||
{
|
||||
var hFile = NativeMethods.CreateFile(
|
||||
reparsePoint,
|
||||
accessRights,
|
||||
FileShareMode.FileShareRead | FileShareMode.FileShareWrite,
|
||||
IntPtr.Zero,
|
||||
FileCreationDisposition.OpenExisting,
|
||||
FileAttributeFlags.FileFlagBackupSemantics | FileAttributeFlags.FileFlagOpenReparsePoint,
|
||||
IntPtr.Zero);
|
||||
|
||||
if (hFile.IsInvalid)
|
||||
throw new Win32Exception();
|
||||
|
||||
return hFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using NCode.ReparsePoints;
|
||||
|
||||
namespace Velopack.Util
|
||||
{
|
||||
@@ -38,35 +39,9 @@ namespace Velopack.Util
|
||||
: targetPath;
|
||||
|
||||
if (Directory.Exists(targetPath)) {
|
||||
#if NETSTANDARD
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
if (!CreateSymbolicLink(linkPath, finalTarget, SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
|
||||
ThrowLastWin32Error("Unable to create junction point / symlink.");
|
||||
} else {
|
||||
var linkInfo = new Mono.Unix.UnixSymbolicLinkInfo(linkPath);
|
||||
linkInfo.CreateSymbolicLinkTo(targetPath);
|
||||
}
|
||||
#elif NETFRAMEWORK
|
||||
if (!CreateSymbolicLink(linkPath, finalTarget, SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
|
||||
ThrowLastWin32Error("Unable to create junction point / symlink.");
|
||||
#else
|
||||
Directory.CreateSymbolicLink(linkPath, finalTarget);
|
||||
#endif
|
||||
CreateDirectoryLink(linkPath, finalTarget, targetPath);
|
||||
} else if (File.Exists(targetPath)) {
|
||||
#if NETSTANDARD
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
if (!CreateSymbolicLink(linkPath, finalTarget, SYMBOLIC_LINK_FLAG_FILE | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
|
||||
ThrowLastWin32Error("Unable to create junction point / symlink.");
|
||||
} else {
|
||||
var fileInfo = new Mono.Unix.UnixFileInfo(targetPath);
|
||||
fileInfo.CreateSymbolicLink(linkPath);
|
||||
}
|
||||
#elif NETFRAMEWORK
|
||||
if (!CreateSymbolicLink(linkPath, finalTarget, SYMBOLIC_LINK_FLAG_FILE | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
|
||||
ThrowLastWin32Error("Unable to create junction point / symlink.");
|
||||
#else
|
||||
File.CreateSymbolicLink(linkPath, finalTarget);
|
||||
#endif
|
||||
CreateFileLink(linkPath, finalTarget);
|
||||
} else {
|
||||
throw new IOException("Target path does not exist.");
|
||||
}
|
||||
@@ -118,181 +93,81 @@ namespace Velopack.Util
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetUnresolvedTarget(string linkPath)
|
||||
private static void CreateFileLink(string linkPath, string targetPath)
|
||||
{
|
||||
if (TryGetLinkFsi(linkPath, out var fsi)) {
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
var rp = new ReparsePointProvider();
|
||||
rp.CreateSymbolicLink(linkPath, targetPath, false);
|
||||
} else {
|
||||
#if NETSTANDARD
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
return GetTargetWin32(linkPath);
|
||||
} else {
|
||||
return Mono.Unix.UnixPath.ReadLink(linkPath);
|
||||
}
|
||||
#elif NETFRAMEWORK
|
||||
return GetTargetWin32(linkPath);
|
||||
var fileInfo = new Mono.Unix.UnixFileInfo(targetPath);
|
||||
fileInfo.CreateSymbolicLink(linkPath);
|
||||
#elif NET6_0_OR_GREATER
|
||||
File.CreateSymbolicLink(linkPath, targetPath);
|
||||
#else
|
||||
return fsi.LinkTarget!;
|
||||
throw new NotSupportedException();
|
||||
#endif
|
||||
}
|
||||
|
||||
throw new IOException("Path does not exist or is not a junction point / symlink.");
|
||||
}
|
||||
|
||||
private static bool TryGetLinkFsi(string path, out FileSystemInfo fsi)
|
||||
private static void CreateDirectoryLink(string linkPath, string targetPath, string absoluteTargetPath)
|
||||
{
|
||||
fsi = null!;
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
var rp = new ReparsePointProvider();
|
||||
try {
|
||||
rp.CreateSymbolicLink(linkPath, targetPath, true);
|
||||
} catch (Win32Exception ex) when (ex.NativeErrorCode == 1314) {
|
||||
// on windows 10 and below, symbolic links can only be created by an administrator
|
||||
// junctions also do not support relative target path's
|
||||
rp.CreateJunction(linkPath, absoluteTargetPath);
|
||||
}
|
||||
} else {
|
||||
#if NETSTANDARD
|
||||
var linkInfo = new Mono.Unix.UnixSymbolicLinkInfo(linkPath);
|
||||
linkInfo.CreateSymbolicLinkTo(targetPath);
|
||||
#elif NET6_0_OR_GREATER
|
||||
Directory.CreateSymbolicLink(linkPath, targetPath);
|
||||
#else
|
||||
throw new NotSupportedException();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetUnresolvedTarget(string linkPath)
|
||||
{
|
||||
if (!TryGetLinkFsi(linkPath, out var fsi)) {
|
||||
throw new IOException("Path does not exist or is not a junction point / symlink.");
|
||||
}
|
||||
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
var rp = new ReparsePointProvider();
|
||||
var link = rp.GetLink(linkPath);
|
||||
return link.Target;
|
||||
} else {
|
||||
#if NETSTANDARD
|
||||
return Mono.Unix.UnixPath.ReadLink(linkPath);;
|
||||
#elif NET6_0_OR_GREATER
|
||||
return fsi!.LinkTarget!;
|
||||
#else
|
||||
throw new NotSupportedException();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetLinkFsi(string path, out FileSystemInfo? fsi)
|
||||
{
|
||||
fsi = null;
|
||||
if (Directory.Exists(path)) {
|
||||
fsi = new DirectoryInfo(path);
|
||||
} else if (File.Exists(path)) {
|
||||
fsi = new FileInfo(path);
|
||||
}
|
||||
|
||||
return fsi != null && (fsi.Attributes & FileAttributes.ReparsePoint) != 0;
|
||||
}
|
||||
|
||||
|
||||
#if NETFRAMEWORK || NETSTANDARD
|
||||
[Flags]
|
||||
private enum EFileAttributes : uint
|
||||
{
|
||||
Readonly = 0x00000001,
|
||||
Hidden = 0x00000002,
|
||||
System = 0x00000004,
|
||||
Directory = 0x00000010,
|
||||
Archive = 0x00000020,
|
||||
Device = 0x00000040,
|
||||
Normal = 0x00000080,
|
||||
Temporary = 0x00000100,
|
||||
SparseFile = 0x00000200,
|
||||
ReparsePoint = 0x00000400,
|
||||
Compressed = 0x00000800,
|
||||
Offline = 0x00001000,
|
||||
NotContentIndexed = 0x00002000,
|
||||
Encrypted = 0x00004000,
|
||||
Write_Through = 0x80000000,
|
||||
Overlapped = 0x40000000,
|
||||
NoBuffering = 0x20000000,
|
||||
RandomAccess = 0x10000000,
|
||||
SequentialScan = 0x08000000,
|
||||
DeleteOnClose = 0x04000000,
|
||||
BackupSemantics = 0x02000000,
|
||||
PosixSemantics = 0x01000000,
|
||||
OpenReparsePoint = 0x00200000,
|
||||
OpenNoRecall = 0x00100000,
|
||||
FirstPipeInstance = 0x00080000
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern SafeFileHandle CreateFile(
|
||||
string lpFileName,
|
||||
FileAccess dwDesiredAccess,
|
||||
FileShare dwShareMode,
|
||||
IntPtr lpSecurityAttributes,
|
||||
FileMode dwCreationDisposition,
|
||||
EFileAttributes dwFlagsAndAttributes,
|
||||
IntPtr hTemplateFile);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);
|
||||
|
||||
private const int SYMBOLIC_LINK_FLAG_FILE = 0x0;
|
||||
private const int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1;
|
||||
private const int SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2;
|
||||
private const int INITIAL_REPARSE_DATA_BUFFER_SIZE = 1024;
|
||||
private const int FSCTL_GET_REPARSE_POINT = 0x000900a8;
|
||||
private const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
|
||||
private const int ERROR_MORE_DATA = 0xEA;
|
||||
private const uint IO_REPARSE_TAG_SYMLINK = 0xA000000C;
|
||||
private const uint IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003;
|
||||
|
||||
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
private static extern uint GetFinalPathNameByHandle(IntPtr hFile, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpszFilePath, uint cchFilePath,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool DeviceIoControl(
|
||||
SafeFileHandle deviceHandle,
|
||||
uint ioControlCode,
|
||||
IntPtr inputBuffer,
|
||||
int inputBufferSize,
|
||||
byte[] outputBuffer,
|
||||
int outputBufferSize,
|
||||
out int bytesReturned,
|
||||
IntPtr overlapped);
|
||||
|
||||
private static string GetTargetWin32(string linkPath)
|
||||
{
|
||||
// https://github.com/microsoft/BuildXL/blob/main/Public/Src/Utilities/Native/IO/Windows/FileSystem.Win.cs#L2711
|
||||
// http://blog.kalmbach-software.de/2008/02/28/howto-correctly-read-reparse-data-in-vista/
|
||||
// https://github.com/dotnet/runtime/blob/e5f0c361f5baea5e2b56e1776143d841b0cc6e6c/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs#L544
|
||||
SafeFileHandle handle = CreateFile(
|
||||
linkPath,
|
||||
dwDesiredAccess: 0,
|
||||
FileShare.ReadWrite | FileShare.Delete,
|
||||
lpSecurityAttributes: IntPtr.Zero,
|
||||
FileMode.Open,
|
||||
dwFlagsAndAttributes: EFileAttributes.BackupSemantics | EFileAttributes.OpenReparsePoint,
|
||||
hTemplateFile: IntPtr.Zero);
|
||||
|
||||
if (Marshal.GetLastWin32Error() != 0)
|
||||
ThrowLastWin32Error("Unable to open reparse point.");
|
||||
|
||||
int bufferSize = INITIAL_REPARSE_DATA_BUFFER_SIZE;
|
||||
int errorCode = ERROR_INSUFFICIENT_BUFFER;
|
||||
|
||||
byte[] buffer = null!;
|
||||
while (errorCode == ERROR_MORE_DATA || errorCode == ERROR_INSUFFICIENT_BUFFER) {
|
||||
buffer = new byte[bufferSize];
|
||||
bool success = false;
|
||||
|
||||
int bufferReturnedSize;
|
||||
success = DeviceIoControl(
|
||||
handle,
|
||||
FSCTL_GET_REPARSE_POINT,
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
buffer,
|
||||
bufferSize,
|
||||
out bufferReturnedSize,
|
||||
IntPtr.Zero);
|
||||
|
||||
bufferSize *= 2;
|
||||
errorCode = success ? 0 : Marshal.GetLastWin32Error();
|
||||
if (fsi == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (errorCode != 0) {
|
||||
throw new Win32Exception(errorCode);
|
||||
}
|
||||
|
||||
const uint PrintNameOffsetIndex = 12;
|
||||
const uint PrintNameLengthIndex = 14;
|
||||
const uint SubsNameOffsetIndex = 8;
|
||||
const uint SubsNameLengthIndex = 10;
|
||||
|
||||
uint reparsePointTag = BitConverter.ToUInt32(buffer, 0);
|
||||
if (reparsePointTag != IO_REPARSE_TAG_SYMLINK && reparsePointTag != IO_REPARSE_TAG_MOUNT_POINT) {
|
||||
throw new NotSupportedException($"Reparse point tag {reparsePointTag:X} not supported");
|
||||
}
|
||||
|
||||
uint pathBufferOffsetIndex = (uint) ((reparsePointTag == IO_REPARSE_TAG_SYMLINK) ? 20 : 16);
|
||||
|
||||
int nameOffset = BitConverter.ToInt16(buffer, (int) PrintNameOffsetIndex);
|
||||
int nameLength = BitConverter.ToInt16(buffer, (int) PrintNameLengthIndex);
|
||||
string targetPath = Encoding.Unicode.GetString(buffer, (int) pathBufferOffsetIndex + nameOffset, nameLength);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(targetPath)) {
|
||||
nameOffset = BitConverter.ToInt16(buffer, (int) SubsNameOffsetIndex);
|
||||
nameLength = BitConverter.ToInt16(buffer, (int) SubsNameLengthIndex);
|
||||
targetPath = Encoding.Unicode.GetString(buffer, (int) pathBufferOffsetIndex + nameOffset, nameLength);
|
||||
}
|
||||
|
||||
return targetPath;
|
||||
return (fsi.Attributes & FileAttributes.ReparsePoint) != 0;
|
||||
}
|
||||
|
||||
private static void ThrowLastWin32Error(string message)
|
||||
{
|
||||
throw new IOException(message, Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.IO.Compression;
|
||||
using System.ComponentModel;
|
||||
using System.IO.Compression;
|
||||
using NCode.ReparsePoints;
|
||||
using Velopack.Compression;
|
||||
using Velopack.Util;
|
||||
|
||||
@@ -33,7 +35,8 @@ public class SymbolicLinkTests
|
||||
File.Create(Path.Combine(targetFolder, "AFile")).Close();
|
||||
|
||||
// Verify behavior before junction point created.
|
||||
Assert.False(File.Exists(Path.Combine(junctionPoint, "AFile")),
|
||||
Assert.False(
|
||||
File.Exists(Path.Combine(junctionPoint, "AFile")),
|
||||
"File should not be located until junction point created.");
|
||||
|
||||
Assert.False(SymbolicLink.Exists(junctionPoint), "Junction point not created yet.");
|
||||
@@ -45,7 +48,8 @@ public class SymbolicLinkTests
|
||||
|
||||
Assert.Equal(targetFolder, SymbolicLink.GetTarget(junctionPoint));
|
||||
|
||||
Assert.True(File.Exists(Path.Combine(junctionPoint, "AFile")),
|
||||
Assert.True(
|
||||
File.Exists(Path.Combine(junctionPoint, "AFile")),
|
||||
"File should be accessible via the junction point.");
|
||||
|
||||
// Delete junction point.
|
||||
@@ -53,7 +57,8 @@ public class SymbolicLinkTests
|
||||
|
||||
Assert.False(SymbolicLink.Exists(junctionPoint), "Junction point should not exist now.");
|
||||
|
||||
Assert.False(File.Exists(Path.Combine(junctionPoint, "AFile")),
|
||||
Assert.False(
|
||||
File.Exists(Path.Combine(junctionPoint, "AFile")),
|
||||
"File should not be located after junction point deleted.");
|
||||
|
||||
Assert.False(Directory.Exists(junctionPoint), "Ensure directory was deleted too.");
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Packaging" Version="8.0.0" />
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" $(TargetFramework.StartsWith('net4')) ">
|
||||
|
||||
Reference in New Issue
Block a user