Win32 Exception: Access is denied while attempting to use OpenProcess - c#

this error is appearing while I am attempting to do two things.
while attempting this (Code block 1):
_class = new Proc(Process.GetProcessesByName("procname")[0]);
then in the class Proc whats happening is
public Proc(Process _SelectedProcess)
{
Process = _SelectedProcess;
}
public Process Process
{
get
{
return SelectedProcess;
}
set
{
SelectedProcess = value;
if (SelectedProcess != null)
{
Process.EnterDebugMode();
_Reader = new Win32_Memory(value.Handle, value.MainModule.BaseAddress.ToInt32(), value.Id);
}
}
}
That's some of the ways I get the exception, sometimes this passes without any exception for no apparent reason as far as I see.
Note: it never passes in windows 7, I'm using windows 10 and sometimes it happens that the function works
but if it does pass, the next time I need to use OpenProcess() outside of the Process class, I almost always get the exception, and if i do, then afterwards it fails executing code block 1 if I try to do so again.
this (code block 2) also gets the same access denied error, and sometimes doesnt...
if (_Reader.ReadInt(_addr) == 1) _Reader.Write(_addr, 0);
public bool Write(int address, long value)
{
hProc = OpenProcess(ProcessAccessFlags.VMWrite, false, ID);
byte[] val = BitConverter.GetBytes(value);
bool worked = WriteProcessMemory(hProc, new IntPtr(address), val, (uint)val.LongLength, 0);
CloseHandle(hProc);
return worked;
}
the access flags:
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
the imports:
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, int unused);
also worth noting that sometimes all of this code gets executed without ANY error and will work for as long as I do not reopen this application or if i do not restart the targeted application.
please help me out on this one, if I wasn't clear on some things - this is my first question and I haven't really ever needed to ask one before this one... so I will explain anything necessary afterwards

If, as your last comment indicates, the processes truly have nothing to do with each other, then that exactly explains the AccessDeniedException. You aren't allowed to just modify memory of any random process. That would be a security hole.
Both processes have to be setup and agree to share memory with each other. There are many ways to do inter-process communication between cooperating processes: here's a start: Shared memory between 2 processes (applications)

Related

C# OpenProcess returns error 1150

Here is the code I wrote to open a process:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern UIntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(UIntPtr hObject);
private const uint PROCESS_QUERY_INFORMATION = 0x0400;
public static void processInfo() {
uint PID = 3144;
UIntPtr handle = UIntPtr.Zero;
handle = OpenProcess(PROCESS_QUERY_INFORMATION, false, PID);
Console.WriteLine(Marshal.GetLastWin32Error());
Console.WriteLine(handle);
if (!handle.Equals(UIntPtr.Zero)) {
CloseHandle(handle);
}
}
Marshal.GetLastWin32Error() returns error 1150 for any process. From MSDN:
"ERROR_OLD_WIN_VERSION: The specified program requires a newer version
of Windows."
I'm running this code in Windows 2008 R2 in Visual Studio 2015 Community Edition. Target Framework is set to ".NET Framework 4.5.2" in project settings.
Also, it seems that OpenProcess is still able to do its job because the returned handle is not zero. Should I be concerned about this error?
From the documentation:
If the function succeeds, the return value is an open handle to the
specified process.
If the function fails, the return value is NULL. To get extended error
information, call GetLastError.
Note that the only mention of calling GetLastError is if the function fails. That is indicated by the return value. Only check the error code when the function fails, it only has a meaningful value in that situation. Your mistake is that you check the error code unconditionally.
handle = OpenProcess(...);
if (handle == UIntPtr.Zero)
// only now call Marshal.GetLastWin32Error
Note also that it is pointless to assign handle twice. You wrote:
UIntPtr handle = UIntPtr.Zero;
handle = OpenProcess(...);
Surely the compiler warned that this was pointless, that the value assigned to handle was not used. Your code is somewhat akin to:
int i = 1;
i = 2;
I'm sure you'd never do this. Your code should be:
UIntPtr handle = OpenProcess(...);
I do not know what the problem with your code is, but here is a very simple implementation which I have tested working. Keep in mind you must run as administrator.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApp3
{
class Program
{
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
static void Main(string[] args)
{
Process proc = Process.GetProcessesByName("ac_client")[0];
var hProc = OpenProcess(ProcessAccessFlags.All, false, proc.Id);
}
}
}

C# Monitor ECX register every time breakpoint is fired

How do I monitor current ECX register in C# at given ASM opcode?
Say, I have a:
FF8.exe+69DD8 - push ecx
Using any ready debugger I can do a breakpoint at given opcode and watch registers.
But I need to make an automation software to:
Catch every time 'push ecx' is called and add it to table with the time it was called to know how often is it called.
It's something like cut-scene with different sounds being played, and we need to know what's the time the sounds are played, one after another
Why I can't use ready softwares for this?
Because when I breakpoint 'push ecx', (note: ecx register) and then step over I lose whole timing. I need to do a table with detailed times in which this opcode is accesed.
After four years I am getting back to respond to my own question- Yes, we have to create our own debugger.
It's as simple as calling P/Invoke:
[DllImport("kernel32.dll")]
public static extern bool DebugActiveProcess(int dwProcessId);
Get process id (pId) and call DebugActiveProcess:
Process[] processes = Process.GetProcessesByName(args[0]);
bool bAttached = pinvokes.DebugActiveProcess(processes[0].Id);
Create new struct of DEBUG_EVENT - it would contain all the data about breakpoint
Wait for debug event in a while loop:
WaitForDebugEvent(ref debug, 0xFFFFFFFF);
The breakpoint 0xCC opcode will trigger the EXCEPTION_BREAKPOINT. You now have the threadId associated with given exception. You have to now get the thread context by GetThreadContext- the CONTEXT structure will now contain CPU registers including ECX. You just need to add p/invoke for GetThreadContext and structure for CONTEXT. Full structure and an example can be seen here: http://www.pinvoke.net/default.aspx/kernel32/GetThreadContext.html
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetThreadContext(IntPtr hThread, ref CONTEXT lpContext);
The process code will break on every debugging event even on DLL_LOAD. To set a breakpoint at given address you have to actually write an INT 3 opcode. To do that you have to open process in R/W and inject 0xCC to process memory. Use OpenProcess p/invoke and WriteProcessMemory p/invoke:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess,
bool bInheritHandle,
int processId
);
public static IntPtr OpenProcess(Process proc, ProcessAccessFlags flags)
{
return OpenProcess(flags, false, proc.Id);
}
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
Int32 nSize,
out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[MarshalAs(UnmanagedType.AsAny)] object lpBuffer,
int dwSize,
out IntPtr lpNumberOfBytesWritten);
Now we have everything required to open, write opcode and break when any thread arrive on that position:
IntPtr procHwnd = pinvokes.OpenProcess(processes[0], pinvokes.ProcessAccessFlags.All);
WriteProcessMemory(procHwnd, new IntPtr(0x469DD8), new byte[] { 0xCC }, 1, out IntPtr lpnum);
the lpAddress should be absolute virtual address- that means that in the question there's FF8.exe+69DD8, so we need to get IMAGE_BASE for selected module which in this case is "FF8.exe" and then add 0x69DD8 to that IMAGE_BASE. Naturally every 32-bit non ASLR processes have IMAGE_BASE set at 0x400000. For ASLR activated processes you have to get process modules and get the BaseAddress like this:
foreach(var mod in processes[0].Modules)
{
if ((mod as ProcessModule).ModuleName == args[3])
{
image_base = (mod as ProcessModule).BaseAddress;
break;
}
}
where args[3] == "FF8.exe"- this should return 0x400000 for non-ASLR processes on 32bit

OpenProcess failed to open existing process via id (Last Error code: 1008)?

I'm trying to use OpenProcess to open all existing processes via the process ID. But somehow it works just the first call, while the next calls show that it does not work with an error code reported as 1008 (An attempt was made to reference a token that does not exist).
Here is the code:
[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags access, bool inheritHandle, int procId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
foreach (var proc in Process.GetProcesses()) {
var procHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryOperation, false, proc.Id);
var eCode = Marshal.GetLastWin32Error();
//checking the last error code using Marshal.GetLastWin32Error()
//shows that it succeeds the first time with error code of 0
//Then all the next calls show error code of `1008`.
if(procHandle != IntPtr.Zero) CloseHandle(procHandle);
}
I've tried googling for the error but not sure what could be wrong here. It would be nice if you can let me know what's wrong. Thank you!
UPDATE:
As I said it seems to work just for the first process in the loop. BUT I highly doubt that it actually does not work even for that case because from what I see the procHandle keeping a totally different value from the proc.Handle, unless the handle returned by OpenProcess is another kind of handle and not the same to proc.Handle (if so it's really weird). So if what I'm currently doubting is true, that means OpenProcess totally does not work at all. It's simply useless in this case and still not sure in which context we can use it.
Your error checking is broken. Success is indicated by OpenProcess returning a non-zero value. The error code is only meaningful if OpenProcess fails, that is if OpenProcess returns zero.
So, you must only ask for the error code when the function call fails, as indicated by its return value. You check the error code without checking the return value, which is a mistake. Your code should be more like this:
foreach (var proc in Process.GetProcesses())
{
var procHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryOperation, false, proc.Id);
if (procHandle == IntPtr.Zero)
{
// api call failed, can read error code
var eCode = Marshal.GetLastWin32Error();
}
else
{
// api call succeeded, do stuff with handle
CloseHandle(procHandle);
}
}

Certificate Memory Leak

I'm using .NET 3.5.
I'm experiencing a memory leak when creating a reference to a X509Certificate. I'm using ANTS profiler to analyse the results and the private bytes are increasing while the bytes in the heap remain static (indicating it's a memory leak due to unmanaged code).
I'm using the CRYPT32 dll to manage the certificates. I open a reference to cert store to get a store handle which is an internal pointer (intptr). I then use this store handler to find the cert in store (saved locally). Once I have the cert I close the cert store and return the cert to the calling program. I'm using the flag 0 in the certclosestore which keeps open resources open after the close store is called. I believe this is what is causing the memory leak as it's mentioned here:
http://msdn.microsoft.com/en-us/library/ms937035.aspx
However, when I change the close flag to:
CertCloseStore(storeHandle, 2)
This is supposed to free up the allocated resources. However it just causes the service to bomb out.
The application works on the sense that it is verify the certs etc. The only problem is that the memory use is slowly creeping up and the service needs to be restarted every week or so. Any ideas or thoughts would be greatly appreciated.
public static X509Certificate CreateFromRegistry(string certificateIdent)
{
X509Certificate certificate = null;
IntPtr storeHandle = CertificateStore.CertOpenStore(CERT_STORE_PROV_SYSTEM,
0, 0,CERT_SYSTEM_STORE_LOCAL_MACHINE, "MY");;
certificate = new X509Certificate(CertificateStore.
FindCertInStore(certificateIdent, storeHandle));
CertificateStore.CertCloseStore(storeHandle, 0);
return certificate;
}
public class CertificateStore
{
const int CERT_STORE_PROV_SYSTEM = 10;
private static int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);
const uint PKCS_7_ASN_ENCODING = 0x00010000;
const uint X509_ASN_ENCODING = 0x00000001;
const uint CERT_FIND_SUBJECT_STR = 0x00080007;
const uint CERT_FIND_ISSUER_STR = 0x00080004;
static uint MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
[DllImport("CRYPT32", EntryPoint = "CertOpenStore",
CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CertOpenStore(
int storeProvider, int encodingType,
int hcryptProv, int flags, string pvPara);
[DllImport("CRYPT32", EntryPoint = "CertCloseStore",
CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CertCloseStore(
IntPtr storeProvider,
int flags);
}
public static X509Certificate FindCertInStore
(string trustedRootIssuerName, IntPtr storeHandle)
{
IntPtr hCertCntxt;
X509Certificate theActualCertificate = null;
if (storeHandle != IntPtr.Zero)
{
hCertCntxt = CertFindCertificateInStore(
storeHandle,
MY_ENCODING_TYPE,
0,
CERT_FIND_ISSUER_STR,
trustedRootIssuerName,
IntPtr.Zero);
if (hCertCntxt != IntPtr.Zero)
{
theActualCertificate = new X509Certificate(hCertCntxt);
}
}
return theActualCertificate;
}
Well, you are leaking CRYPT32 resources of course. One immediate candidate I see in your snippet is the return value of CertFindCertificateInStore(). It must be released by an explicit call to CertFreeCertificateContext(), I don't see one.
The X509Certification(IntPtr) constructor is not documented well, it doesn't describe how long the context needs to be valid. I see it calling an internal method named X509Utils._DuplicateCertContext() so very high odds that you immediately can call the release function after creating the object.
Do check the rest of your code with a fine-toothed comb and triple check that all handles and pointers you get from CRYPT32 are released.

How to move a directory in C# .NET in a single atomic operation

I need to be able to move an entire directory in a single atomic operation, guaranteeing that nothing else on the system will be able to subvert the operation by creating new files after I start, having a lock on a file, etc.
Presumably, I would use System.IO.Directory.Move() if the directories were on the same volume (if Directory.GetDirectoryRoot() is the same), otherwise I'd have to create a new target directory on the other volume and recursively copy/move all the directories and files underneath.
Nothing I've read shows how to gain an exclusive lock to an entire directory leaf in .NET so this can be done safely. Is there a recommended/supported way to do this?
Vista does support transactions in NTFS volumes:
http://msdn.microsoft.com/en-us/magazine/cc163388.aspx
Could you work around this by renaming the "root" directory temporarily (creating a directory with the same name immediately thereafter so that anyone accessing that directory doesn't encounter an error), then work on the files in the renamed directory?
I remember being able to do this at the DOS level by simply renaming the directory. There was a move command, which also seemed to work. But it makes sense. You're not really moving all of the files in the directory, you're just changing the meta data in the directory structure itself. I also remember this from hacking directory structures directly using a disk editor on my fathers Zenith Data Systems 8088. I could make directories invisible by changing the attribute bits on disk, even hiding ".." and "." and making subdirectories appear to be root (the parent directories were invisible). Hope this works for you. I haven't revisited this in hmmm too many years to count ;-). May it work for you.
By the way, you should not have to lock anything because if you're just renaming, it happens really fast, and it's just a single operation.
You can use the Transactional NTFS via PInvoke. Note that it's unclear if it works properly across different volumes, please see the documentation. You may need to use Distributed Transactions, which is significantly more complicated. It will only work on NTFS volumes, not FAT.
Caveat: this code is entirely untested.
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
bool GetVolumeInformationW(
[In, MarshalAs(UnmanagedType.LPWStr)]
string lpRootPathName,
IntPtr lpVolumeNameBuffer,
int nVolumeNameSize,
out int lpVolumeSerialNumber,
out int lpMaximumComponentLength,
out int lpFileSystemFlags,
IntPtr lpFileSystemNameBuffer,
int nFileSystemNameSize
);
[DllImport("KtmW32.dll", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern SafeFileHandle CreateTransaction(
IntPtr lpTransactionAttributes,
IntPtr UOW,
int CreateOptions,
int IsolationLevel,
int IsolationFlags,
int Timeout,
[In, MarshalAs(UnmanagedType.LPWStr)]
string Description
);
[DllImport("KtmW32.dll", SetLastError = true, BestFitMapping = false)]
private static extern bool CommitTransaction(SafeFileHandle hTransaction);
public enum ProgressResponse
{
PROGRESS_CONTINUE, // Continue the copy operation.
PROGRESS_CANCEL, // Cancel the copy operation and delete the destination file.
PROGRESS_STOP, // Stop the copy operation. It can be restarted at a later time.
PROGRESS_QUIET, // Continue the copy operation, but stop invoking CopyProgressRoutine to report progress.
}
public delegate ProgressResponse ProgressRoutine(
long TotalFileSize,
long TotalBytesTransferred,
long StreamSize,
long StreamBytesTransferred,
int dwStreamNumber,
int dwCallbackReason,
IntPtr hSourceFile,
IntPtr hDestinationFile,
IntPtr lpData
);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool MoveFileTransactedW(
[In, MarshalAs(UnmanagedType.LPWStr)]
string lpExistingFileName,
[In, MarshalAs(UnmanagedType.LPWStr)]
string lpNewFileName,
ProgressRoutine lpProgressRoutine,
IntPtr lpData,
int dwFlags,
SafeFileHandle hTransaction
);
private static bool CheckSupportsTransactions(string filePath)
{
const int FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
if(!GetVolumeInformationW(
Path.GetPathRoot(sourceFullPath),
IntPtr.Zero, 0,
out var _,
out var _,
out var flags,
IntPtr.Zero, 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
return flags & FILE_SUPPORTS_TRANSACTIONS != 0;
}
public static void MoveDirectoryTransacted(string sourceFullPath, string destFullPath, ProgressRoutine progress = null)
{
const int MOVEFILE_COPY_ALLOWED = 0x2;
const int ERROR_REQUEST_ABORTED = 0x4D3;
sourceFullPath = Path.GetFullPath(sourceFullPath);
destFullPath = Path.GetFullPath(destFullPath);
if(!CheckSupportsTransactions(sourceFullPath) ||
!CheckSupportsTransactions(destFullPath))
{
throw new InvalidOperationException("Volume does not support transactions");
}
using (var tran = CreateTransaction(IntPtr.Zero, IntPtr.Zero, 0, 0, 0, 0, null))
{
if (tran.IsInvalid)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (!MoveFileTransactedW(
sourceFullPath,
destFullPath,
progress,
IntPtr.Zero,
MOVEFILE_COPY_ALLOWED,
tran))
{
var error = Marshal.GetLastWin32Error();
if (error == ERROR_REQUEST_ABORTED)
throw new OperationCanceledException();
throw new Win32Exception(error);
}
if (!CommitTransaction(tran))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
If you have a CancellationToken, you could invoke it like this
MoveDirectoryTransacted("sourcePath", "destPath",
() => cancelToken.IsCancellationRequested ? ProgressResponse.PROGRESS_CANCEL : ProgressResponse.PROGRESS_CONTINUE);
If you have the ability to run your copy process as "service account" that is only used by the copy process, you could set the permissions of the folder to only allow that account to work with it. Then reset the permissions back to what they were after the copy process finished.
For example, something like the following:
using System;
using System.IO;
using System.Security.AccessControl;
using System.Security.Principal;
namespace ExclusiveLockFileCopy
{
public class ExclusiveLockMover
{
public DirectorySecurity LockFolder(DirectoryInfo di)
{
var originalSecurity = di.GetAccessControl(System.Security.AccessControl.AccessControlSections.All);
//make sure inherted permissions will come back when UnlockFolder is called
originalSecurity.SetAccessRuleProtection(true, true);
var tmpSecurity = di.GetAccessControl(System.Security.AccessControl.AccessControlSections.All);
// remove all rules
var currentRules = tmpSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
foreach (AccessRule rule in currentRules)
{
tmpSecurity.PurgeAccessRules(rule.IdentityReference);
tmpSecurity.ModifyAccessRule(AccessControlModification.RemoveAll, rule, out var tmpModified);
Console.WriteLine($"Removed access for {rule.IdentityReference.Value}");
}
//add back the current process' identity after the for loop - don't assume the account will show up in the current rule list (i.e. inherited access)
var _me = WindowsIdentity.GetCurrent();
var _meNT = new NTAccount(_me.Name);
tmpSecurity.AddAccessRule(new FileSystemAccessRule(_meNT, FileSystemRights.FullControl, AccessControlType.Allow));
Console.WriteLine($"Ensuring {_meNT.Value} maintains full access");
//strip out inherited permissions
tmpSecurity.SetAccessRuleProtection(true, false);
di.SetAccessControl(tmpSecurity);
//send back the original security incase it is needed later for "unlocking"
return originalSecurity;
}
public void UnlockFolder(DirectoryInfo di, DirectorySecurity originalSecurity)
=> di.SetAccessControl(originalSecurity);
public void CopyFolderExclusive(string srcFolder, string dstFolder)
{
DirectorySecurity diSourceOriginalSecurity = null;
DirectorySecurity diDestinationOriginalSecurity = null;
var diSource = new DirectoryInfo(srcFolder);
var diDestination = new DirectoryInfo(dstFolder);
try
{
diSourceOriginalSecurity = LockFolder(diSource);
if (!diDestination.Exists)
diDestination.Create();
diDestinationOriginalSecurity = LockFolder(diDestination);
// perform your folder/file copy here //
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
if (diSourceOriginalSecurity != null)
UnlockFolder(diSource, diSourceOriginalSecurity);
if (diDestinationOriginalSecurity != null)
UnlockFolder(diDestination, diDestinationOriginalSecurity);
}
}
}
}
I'd say what you really need is a transactional file system... which NTFS ain't, and while there have been MS plans for such, it was cut from Longhorn before it became Vista (and from Cairo before that).
You could try to gain exclusive locks on every file in the directory before the move, and do the moving with explicit file reading/writing, but recursively? I'm not so sure that's a good idea... and besides, that won't protect against new files being added.
What are you really trying to do? Why are you worried about concurrent activity?

Categories

Resources