I have this method
public void Copy(string sourcePath, string destPath)
{
string[] files= Directory.GetFiles(sourcePath);
for (int i = 0; i < files.Length; i++)
{
try
{
File.Copy(files[i], destPath);
}
catch
{
try
{
File.Replace(files[i], destPath, null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
when I run it I get unauthorized access exception , Access denied !
any help in this !
This exception is covered in the documentation for File.Copy:
The caller does not have the required permission.
-or-
destFileName is read-only.
Check the attributes of the file after the first copy. Are the permissions what you expect? Do you need your program to run elevated (as administrator)?
below reasons can possible :
The sourceFileName or destinationFileName parameter specifies a file that is read-only.
-or-
This operation is not supported on the current platform.
-or-
Source or destination parameters specify a directory instead of a file.
-or-
The caller does not have the required permission.
Read link :http://msdn.microsoft.com/en-us/library/9etk7xw2(v=vs.110).aspx
When the problem occurs on a Windows machine, make sure you have disabled "controlled folder access" in the App Windows-Safety or allow folder access to your program. (must have administrator privileges)
Related
I need to check if the current user has write permissions inside the path. Here an example:
string save_path = #"C:\Windows\somefolder";
string my_dir = Path.DirectorySeparatorChar + "foobar";
//check if specific path are valid
if (!Directory.Exists(save_path)) { return; }
if (Directory.Exists(save_path + my_dir)) { return; }
if (canWriteOnPath(save_path)) {
Directory.CreateDirectory(save_path + my_dir);
} else {
//You are not allowed to save here OR not are launching this application as "administrator"
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
solved in this question:
CurrentUserSecurity cus = new CurrentUserSecurity();
bool flag = cus.HasAccess(new DirectoryInfo(#"C:\Windows"), FileSystemRights.Write);
if (flag) {
//yes create that folder
Directory.CreateDirectory(Path.Combine(save_path, my_dir));
} else {
//NO YOU CANT
Directory.CreateDirectory(#"C:\Users\contoso\Documents\foobar");
}
The robust method would be to Try to create the directory and Catch any resulting exception.
The documentation for Directory.CreateDirectory lists the possible exceptions: IOException, UnauthorizedAccessException, ArgumentException, ArgumentNullException, PathTooLongException, DirectoryNotFoundException.
Although unlikely, it is possible that the permissions changed between your code checking that access is allowed and actually trying to create the directory.
I have this code to copy all files from source-directory, F:\, to destination-directory.
public void Copy(string sourceDir, string targetDir)
{
//Exception occurs at this line.
string[] files = System.IO.Directory.GetFiles(sourceDir, "*.jpg",
SearchOption.AllDirectories);
foreach (string srcPath in files)
{
File.Copy(srcPath, srcPath.Replace(sourceDir, targetDir), true);
}
}
and getting an exception.
If I omit SearchOption.AllDirectories and it works but only copies files from F:\
Use following function instead of System.IO.Directory.GetFiles:
IEnumerable<String> GetAllFiles(string path, string searchPattern)
{
return System.IO.Directory.EnumerateFiles(path, searchPattern).Union(
System.IO.Directory.EnumerateDirectories(path).SelectMany(d =>
{
try
{
return GetAllFiles(d,searchPattern);
}
catch (UnauthorizedAccessException e)
{
return Enumerable.Empty<String>();
}
}));
}
File system objects are subject to security. Some file system objects are secured in such a way that they can only be accessed by certain users. You are encountering a file to which the user executing the code does not have sufficient rights to access.
The reason that you don't have access rights for this particular folder is to protect the security of the different users on the system. The folder in question is the recycle bin on that drive. And each different user has their own private recycle bin, that only they have permission to access. If anybody could access any other user's recycle bin, then users would be able to read each other's files, a clear violation of the system's security policy.
Perhaps the simplest way around this is to skip hidden folders at the root level of the drive. That simple change would be enough to solve your problem because you surely don't want to copy recycle bins.
That folder is a secure system folder (your bin, each drive has its own bin). Just place your file.copy into a try catch statement and ignore/log all the failures. That way you will only copy actual files and skip system files/folders.
If you really want to avoid the try catch statement. Use the fileinfo and directory info classes to figure out which folders/files are of the system and will throw an exception.
This should do the trick:
private IEnumerable<string> RecursiveFileSearch(string path, string pattern, ICollection<string> filePathCollector = null)
{
try
{
filePathCollector = filePathCollector ?? new LinkedList<string>();
var matchingFilePaths = Directory.GetFiles(path, pattern);
foreach(var matchingFile in matchingFilePaths)
{
filePathCollector.Add(matchingFile);
}
var subDirectories = Directory.EnumerateDirectories(path);
foreach (var subDirectory in subDirectories)
{
RecursiveFileSearch(subDirectory, pattern, filePathCollector);
}
return filePathCollector;
}
catch (Exception error)
{
bool isIgnorableError = error is PathTooLongException ||
error is UnauthorizedAccessException;
if (isIgnorableError)
{
return Enumerable.Empty<string>();
}
throw error;
}
}
I am writing a Software that can delete Temporary files, Prefetch data, files in Recent folder and so on. My problem is I can delete files from Temp folder successfully, but when I try for Recent folder, an exception is thrown, "Access to path...is denied".
PS: According to some other questions, I have set File attributes to normal, but still no luck. Please help me on this issue. For your better understand, I put some code here:
public Boolean CleanRecentData()
{
isAllClean = true;
String SysRecentPath = System.Environment.GetEnvironmentVariable("USERPROFILE") + "\\Recent";
DirectoryInfo SysRecDir = new DirectoryInfo(SysRecentPath);
File.SetAttributes(SysRecentPath, FileAttributes.Normal);
foreach (FileInfo fi in SysRecDir.GetFiles()) //Access Denied
//Exception is thrown here
{
try
{
fi.Delete();
}
catch (Exception ex)
{
recentLogLines.AppendLine(ex.Message);
isAllClean = false;
}
}
foreach (DirectoryInfo dir in SysRecDir.GetDirectories())
{
try
{
dir.Delete(true);
}
catch (Exception ex)
{
recentLogLines.AppendLine(ex.Message);
isAllClean = false;
}
}
return isAllClean;
}
Are you able to access the Recent folder via Windows Explorer?
You could go ahead and change the permissions in your system, but NOT in your users systems.
Therefore you could handle this exception condition in two ways.
You need to check if you have file access before accessing, using FileIOPermission but this might be redundant and wasteful if you are doing it on too many files.
Just try to open the file and put your effort into a good exception handler if it fails
Reference
Having an issue with a Windows service that needs to monitor/have access to a set of folders, and move files around between those folders.
There's have a bit of boilerplate code that's been used in the past, which will check a given folder for the specific granular permissions for the given user. The odd thing is that I discovered through testing that if I manually deny all permissions on that folder for the account the service is running under, and then run the code, it reports that all is well and the user does in fact have those permissions, even though it's obvious (and demonstrable) that he doesn't.
At first I thought this might be because the service was running under the local System account, but the same issue crops up if it is run with NetworkService as well as with a local user account. This is on Windows 7/2008 R2.
Boilerplate method:
public static void ValidateFolderPermissions(WindowsIdentity userId, string folder, FileSystemRights[] requiredAccessRights)
{
SecurityIdentifier secId;
StringBuilder sb = new StringBuilder();
bool permissionsAreSufficient = false;
bool notAuthorized = false;
String errorMsg = String.Empty;
IdentityReferenceCollection irc = userId.Groups;
foreach (IdentityReference ir in irc)
{
secId = ir.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
try
{
DirectoryInfo dInfo = new DirectoryInfo(folder);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
AuthorizationRuleCollection rules = dSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier));
foreach (FileSystemAccessRule ar in rules)
{
if (secId.CompareTo(ar.IdentityReference as SecurityIdentifier) == 0)
{
sb.AppendLine(ar.FileSystemRights.ToString());
foreach (FileSystemRights right in requiredAccessRights)
{
if (right == ar.FileSystemRights)
{
permissionsAreSufficient = true;
break;
}
}
}
}
}
catch (UnauthorizedAccessException)
{
notAuthorized = true;
errorMsg = "user not authorized";
}
catch (SecurityException)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "security error";
}
catch (Exception)
{
// If we failed authorization do not update error
if (!notAuthorized)
errorMsg = "invalid folder or folder not accessible";
}
}
if (!permissionsAreSufficient)
{
if (!String.IsNullOrEmpty(errorMsg))
throw new Exception(String.Format("User {0} does not have required access to folder {1}. The error is {2}.", userId.Name, folder, errorMsg));
else
throw new Exception(String.Format("User {0} does not have required access rights to folder {1}.", userId.Name, folder));
}
}
And the calling snippet:
FileSystemRights[] requireAccessRights =
{
FileSystemRights.Delete,
FileSystemRights.Read,
FileSystemRights.FullControl
};
try
{
FolderPermissionValidator.ValidateFolderPermissions(WindowsIdentity.GetCurrent(), inputFolder, requireAccessRights);
Log.Debug("In ServiceConfigurationValidator: {0}, {1}", WindowsIdentity.GetCurrent().Name, inputFolder);
}
catch (Exception ex)
{
Log.Debug("Throwing exception {0}", ex.Message);
}
I don't see anything in ValidateFolderPermissions to check for denials before checking for allowed permissions. If a deny entry prevents access then no amount of allow entries can override it.
This code enumerates the entries in the ACL as FileSystemAccessRule objects, but doesn't bother to check whether AccessControlType is allow or deny.
I also note that the logic returns true if any ACE exactly matches any of the elements of the requiredAccessRights array; I suspect the intended behaviour is that it return true if all of the specified rights are present. This could cause false positives if only some of the requested rights are present, but because it only looks for exact matches it could also cause a false negative, e.g., if the ACE actually gives more rights than are being requested. (Not such a problem in the example given, though, because you're asking for Full Control.)
Another flaw is that it only checks for access entries matching groups the user belongs to; access entries for the user account itself will be ignored. (I'm not sure what the behaviour of WindowsIdentity.Groups is for security primitives such as SYSTEM and NetworkService that are not actual user accounts, although it sounds like that part was working as desired.)
Note that because it is very hard to cope properly with all the possible situations (consider, e.g., an access control entry for Everyone, or for SERVICE) it would be wise to allow the administrator to override the check if it is mistakenly reporting that the account doesn't have the necessary access.
I want to move a directory from one location to another using C# .NET. I used Directory.Move or even DirectoryInfo (with MoveTo) this simple way:
// source is: "C:\Songs\Elvis my Man"
// newLocation is: "C:\Songs\Elvis"
try
{
// Previous command was: Directory.Move(source, newLocation);
DirectoryInfo dir = new DirectoryInfo(source);
dir.MoveTo(newLocation);
}
catch (Exception e)
{
Console.WriteLine("Error: "+ e.Message);
}
But action that's being done (for both cases) is renaming the folder name from 'source' to 'newLocation'
What I expected? that folder "Elvis my man" will be now in "Elvis" folder.
What has happened? "Elvis my man" was changed to "Elvis" (Renamed). If the directory "Elvis" is already exists, it can't change it to "Elvis" (cause he can't make a duplicate names), therefore I get an exception saying that.
What am I doing wrong??
Many thanks!!!
I would advise putting validation around the Move command to ensure that the source location does exists and the destination location doesn't exists.
I've always found it easier to avoid the exceptions than handle them once they do occur.
You'll probably want to include exception handling as well, just in case the access permissions are a problem or a file is open and can't be moved...
Here's some sample code for you:
string sourceDir = #"c:\test";
string destinationDir = #"c:\test1";
try
{
// Ensure the source directory exists
if (Directory.Exists(sourceDir) == true )
{
// Ensure the destination directory doesn't already exist
if (Directory.Exists(destinationDir) == false)
{
// Perform the move
Directory.Move(sourceDir, destinationDir);
}
else
{
// Could provide the user the option to delete the existing directory
// before moving the source directory
}
}
else
{
// Do something about the source directory not existing
}
}
catch (Exception)
{
// TODO: Handle the exception that has been thrown
}
Even though this works in the command line to move a file, when programming you need to provide the full new name.
So you'd need to change newLocation to "C:\Songs\Elvis\Elvis my Man" to make this work.
From MSDN,
This method throws an IOException if, for example, you try to move c:\mydir to c:\public, and c:\public already exists. You must specify "c:\public\mydir" as the destDirName parameter, or specify a new directory name such as "c:\newdir".
It looks like you need to set newLocation to C:\Songs\Elvis\Elvis my man
private void moveDirectory(string fuente,string destino)
{
if (!System.IO.Directory.Exists(destino))
{
System.IO.Directory.CreateDirectory(destino);
}
String[] files = Directory.GetFiles(fuente);
String[] directories = Directory.GetDirectories(fuente);
foreach (string s in files)
{
System.IO.File.Copy(s, Path.Combine(destino,Path.GetFileName(s)), true);
}
foreach(string d in directories)
{
moveDirectory(Path.Combine(fuente, Path.GetFileName(d)), Path.Combine(destino, Path.GetFileName(d)));
}
}