System.UnauthorizedAccessException: Access to the path "..." is denied - c#

I have C# wpf installation done with .net using click once installation. All works fine. Then I have the following code which is part of the installed program:
String destinationPath = System.Windows.Forms.Application.StartupPath + "\\" + fileName;
File.Copy(path, destinationPath, true);
this.DialogResult = true;
this.Close();
But I get this error:
System.UnauthorizedAccessException: Access to the path C:\user\pc\appdata\local\apps\2.0....... is denied.
at System.IO.File.InternalCopy(String sourceFileName, String destFileName, Boolean overwrite, Boolean checkHost)
at System.IO.File.Copy(String sourceFileName, String destFileName, Boolean overwrite)
Is it a permission error or do I need to tweak something in my code?
What puzzles me is why the user is able to install the program using click once into that directory without any issues, but uploading a file to it doesn't work?

When installing an application the installer usually asks for administrative privileges. If the user chooses "Yes" the program will run and have read and write access to a larger variety of paths than what a normal user has. If the case is such that the installer did not ask for administrative privileges, it might just be that ClickOnce automatically runs under some sort of elevated privileges.
I'd suggest you write to the local appdata folder instead, but if you feel you really want to write to the very same directory as your application you must first run your app with administrator privileges.
To make your application always ask for administrator privileges you can modify your app's manifest file and set the requestedExecutionLevel tag's level attribute to requireAdministrator:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
You can read a bit more in How do I force my .NET application to run as administrator?

I was running a program that would generate file. The destination folder was read only. And it would crash with the error. Removing the read-only attribute using folder properties resolved the error.

First, if you need to write any data you should use the Environment.SpecialFolder enumeration.
Second, do not write to any folder where the application is deployed because it is usually read only for applications. You probably want to write to the ApplicationData or LocalApplicationData enumerations.

I think that access to %appdata% is restricted by default on windows 8 (or 7) onwards.
When the app installed via ClickOnce you are probably prompted to give it permission to alter this computer - is that right?
You can try running the app with admin permissions as a test (hold shift, right click the .exe, run as administrator) which will probably solve it, but it's not an ideal way to do it.
Instead try another folder, something like:
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
or
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments )
which should give you better luck.
As a side note - if you are building paths in code, rather than using
path + "\\" + path + "\\" + filename
which is prone to failure (path may already have a \ on the end) it is usually better to use Path.Combine(..)
String destinationPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), fileName);

In my case, the remote server was returning "." and ".." when I was trying to download (SFTP) files and write to our local/network folder. I'd to explicitly discard the "." and ".." file names.

Related

C# ClickOnce Deployment Mapping Back to My Desktop Drive

I created a WinForms application that includes code to find the user's desktop and perform 3 tasks:
1. Create a folder
2. Read a .csv file
3. Output some data to a .csv file on the desktop.
I'm using the code below to find the user's desktop
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
I used the ClickOnce deployment to install the program to our network drive. The program installs successfully, but Whenever I have someone attempt to run the program from their terminal, they get an error message that states "The directory name is invalid" and it references my desktop and not the user's.
How should I change my code or the deployment method so it references the user's desktop?
If directory invalid try creating it
Try with this code
string filePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string extension = ".log"; filePath += #"\Error Log\" + extension;
if (!Directory.Exists(filePath)) {
Directory.CreateDirectory(filePath);
}
I made the following change to my code and it worked as needed:
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

C# File.Exists returns false, file does exist

Using VS 15, C# with .Net 4.5.2
The computer is on an AD network, with the ad name "AD".
This problem happens with AD normal-user rights, AD admin rights, and local admin rights. It doesn't matter what rights the program gets, the same problem occurs.
Our test file is "C:/windows/system32/conhost.exe".
The file above exists, it is very much existing. I can see it with explorer.
This is the file in explorer:
This is the file properties:
You can see that it is there, right?
The following cmd command checks if the file exists:
IF EXIST "C:\windows\system32\conhost.exe" (echo does exist) ELSE (echo doesnt exist)
It returns "does exist" as promised.
The following C# code checks if the file exists:
FileInfo file = new FileInfo("C:/windows/system32/conhost.exe");
MessageBox.Show(file.Exists + "");
This returns "False".
This code also returns "False":
MessageBox.Show(File.Exists("C:/windows/system32/conhost.exe") + "");
This code also doesn't find it:
foreach (string file in Directory.GetFiles("C:/windows/system32/"))
{
//conhost is NEVER mentioned, like it doesn't exist
}
This code also doesn't find it:
foreach (string file in Directory.EnumerateFiles("C:/windows/system32/"))
{
//conhost is NEVER mentioned, like it doesn't exist
}
False, False, False:
MessageBox.Show(File.Exists("C:/windows/system32/conhost.exe") + "");
MessageBox.Show(File.Exists("C:\\windows\\system32\\conhost.exe") + "");
MessageBox.Show(File.Exists(#"C:\windows\system32\conhost.exe") + "");
What am I doing wrong?
Extra note: I copied conhost to C:\conhost.exe, and my program can find that without problem. My program also finds other files in system32, just not conhost and a few others. For example, it finds "connect.dll" which is in system32, so it's not the directory's read permission.
More extra notes: conhost.exe and connect.dll has the same security attributes (Security tab in the file properties).
If you are using x64 system, you will have different content of the c:\Windows\System32 directory for x86 and x64 applications. Please be sure that you are using same architecture running batch file and your C# app.
In the MSDN documentation for System.IO.File.Exists(path), it states:
If the caller does
not have sufficient permissions to read the specified file, no
exception is thrown and the method returns false regardless of the
existence of path.
For this reason, we can safely assume that your application does not have read access to that specific file. Check the security settings and grant read access if not already done so.
Build your application (in release mode) and run as administrator.
This is the problem that come over 64-bit operating system... here is a work around,
go to the project's properties > click on build tab > untick Prefer 32-bit
after that, it should work correctly over 64-bit os.

File already exists exception file.copy

I am trying to copy a driver file from my application folder to driver folder in windows 7. But as I run this program File already exists exception has been occurred if I check at driver folder manually the file does not exists at all.
Program.sDriverPath = Path.Combine(Program.sStartUpPath, #"windows7\amd64\MyDriver.sys");
string sPath = sDriverPath;
string sDestPath = Path.Combine(Environment.ExpandEnvironmentVariables(#"%windir%\system32"), #"drivers\MyDriver.sys");
MessageBox.Show("Source " + sDriverPath);
File.Copy(sDriverPath, sDestPath);
If you want to overwrite an existing file you need to use the overload which has a boolean parameter:
public static void Copy(
string sourceFileName,
string destFileName,
bool overwrite)
and specify true for overwrite.
Now it is odd that you say the file doesn't exist in the destination at all - I think it must do, and you're not looking in the right place.
Try setting a breakpoint in your code immediately before you call File.Copy() and check the sDestPath parameter.
I suspect that what is happening is that the File System Redirector is silently redirecting your application to a different folder.
Try checking the folder %windir%\SysWOW64 instead.
Finally, note that the process's user must be running as an administrator to write files into that location.
Thanks #Matthew Watson I found the solution. FSRedirector is redirecting system32 folder to SysWow64 folder.Go to syswow64 folder then go to drives folder you will find your file there.

C# application using database from wrong location

I have setup my sqlite database path as
string AppPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
dbName = AppPath + "\\data\\rbssystems.sqlite";
But when application is packed and installed using setup, my application uses
C:\Users\<username>\AppData\Local\VirtualStore\Program Files\RBS\data
it should be using
C:\Program Files\RBS\data
Can anyone tell whats going around and how to make it read database from
C:\Program Files\RBS\data
Thanks
Your app can't write to C:\Program Files unless it has administrative privileges. Windows automatically redirects you to C:\Users\<username>\AppData\Local\VirtualStore\Program Files instead. See this article for the explanation: http://blogs.windows.com/windows/archive/b/developers/archive/2009/08/04/user-account-control-data-redirection.aspx
Application data should always be in the AppData folder, never in Program Files.

How to change permissions of a folder inside System32 in C#?

I need to programmatically remove "create file" and "create directory" permissions on a directory inside System32 directory for a group "NT AUTHORITY\\INTERACTIVE".
To do this, I wrote following code:
string windir = Environment.GetEnvironmentVariable("systemroot");
string redirectionFolder = (windir + "\\System32\\Tasks2");
MessageBox.Show(redirectionFolder);
FileSystemAccessRule Tasks = new FileSystemAccessRule("NT AUTHORITY\\INTERACTIVE", FileSystemRights.CreateDirectories | FileSystemRights.CreateFiles, AccessControlType.Deny );
DirectorySecurity dirSecurity = new DirectorySecurity(redirectionFolder, AccessControlSections.Group);
dirSecurity.AddAccessRule(Tasks);
Directory.SetAccessControl(redirectionFolder, dirSecurity);
When I run this code on a folder C:\Tasks2, it works.
But when I run it on C:\Windows\System32\Tasks2, I get the System.IO.DirectoryNotFoundException exception. Running the app as administrator doesn't help.
What can I do in order to change permissions of a directory inside System32 directory in C#?
Assuming that C:\Windows\System32\Tasks2 really does exist, the most likely explanation is that you are being caught out by the file system redirector. You have a 32 bit process and the file system redirector converts system32 into SysWOW64. And so whilst you think you are looking for C:\Windows\System32\Tasks2, you are actually looking in C:\Windows\SysWOW64\Tasks2.
Compile your program as 64 bit. Or use C:\WINDOWS\SysNative.

Categories