基于MSDN documentation对于 File.Exists
,File.Exists
方法应在出现任何错误时返回 false
,包括调用者无权读取文件。
我希望它在文件设置为 FullControl
拒绝用户访问和 FullControl
拒绝用户访问时返回 false
文件所在的目录。
我看到的是当用户可以访问目录但不能访问文件时,File.Exists
返回 true
;但是,如果用户无权访问该目录,File.Exists
将返回 false
。
我写了一个小程序来演示我在说什么:
using System;
using System.DirectoryServices;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
namespace ConsoleApplication1
{
internal class Program
{
private const string DirName = "TestDir";
private const string FileName = "File.txt";
private const string Password = "Password1";
private const string UserName = "PermissionTestUser";
private static WindowsImpersonationContext Identity = null;
private static IntPtr LogonToken = IntPtr.Zero;
public enum LogonProvider
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3
};
public enum LogonType
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher
LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher
};
public static void Main(string[] args)
{
string filePath = Path.Combine(DirName, FileName);
try
{
CreateUser();
CreateDir();
CreateFile(filePath);
// grant user full control to the dir
SetAccess(DirName, AccessControlType.Allow);
// deny user full control to the file
SetAccess(filePath, AccessControlType.Deny);
// impersonate user
Impersonate();
Console.WriteLine("File.Exists (with dir permissions): {0}", File.Exists(filePath));
UndoImpersonate();
// deny access to dir
SetAccess(DirName, AccessControlType.Deny);
// impersonate user
Impersonate();
Console.WriteLine("File.Exists (without dir permissions): {0}", File.Exists(filePath));
UndoImpersonate();
}
finally
{
UndoImpersonate();
DeleteDir();
DeleteUser();
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
private static void CreateDir()
{
Directory.CreateDirectory(DirName);
}
private static void CreateFile(string path)
{
File.Create(path).Dispose();
}
private static void CreateUser()
{
DirectoryEntry ad = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntry newUser = ad.Children.Add(UserName, "user");
newUser.Invoke("SetPassword", new object[] { Password });
newUser.Invoke("Put", new object[] { "Description", "Test user" });
newUser.CommitChanges();
}
private static void DeleteDir()
{
Directory.Delete(DirName, true);
}
private static void DeleteUser()
{
DirectoryEntry ad = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntries users = ad.Children;
DirectoryEntry user = users.Find(UserName, "user");
if (user != null)
{
users.Remove(user);
}
}
private static void Impersonate()
{
if (LogonUser(UserName, ".", Password, (int)LogonType.LOGON32_LOGON_INTERACTIVE, (int)LogonProvider.LOGON32_PROVIDER_DEFAULT, ref LogonToken))
{
Identity = WindowsIdentity.Impersonate(LogonToken);
return;
}
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool LogonUser(string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
private static void SetAccess(string path, AccessControlType type)
{
FileSecurity fs = File.GetAccessControl(path);
FileSystemAccessRule far = new FileSystemAccessRule(UserName, FileSystemRights.FullControl, type);
fs.AddAccessRule(far);
File.SetAccessControl(path, fs);
}
private static void UndoImpersonate()
{
if (Identity != null)
{
Identity.Undo();
Identity = null;
}
if (LogonToken != IntPtr.Zero)
{
CloseHandle(LogonToken);
LogonToken = IntPtr.Zero;
}
}
}
}
运行这个程序的结果是:
File.Exists (with dir permissions): True
File.Exists (without dir permissions): False
谁能解释为什么他们不同?在这两种情况下,用户都没有文件的读取权限。
最佳答案
这是 File.Exist
的默认行为。根据MSDN :
File.Exist
Return Value Type:
System.Boolean
true if the caller has the required permissions and path contains the name of an existing file; otherwise, false. This method also returns false if path is null, an invalid path, or a zero-length string. 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.
另外
The
Exists
method should not be used for path validation, this method merely checks if the file specified in path exists. Passing an invalid path to Exists returns false.
也就是说,这里的required permission,就是需要知道文件存在的权限(顾名思义,File.Exist
)。这意味着只要用户有权访问该目录,它就可以知道该文件是否存在。
在给定目录权限的情况下,用户是否具有文件访问权限不会影响用户对文件存在的了解。但是没有目录权限,用户无法知道文件的存在,因此 File.Exist
返回 false
编辑(根据评论反馈):
可能最令人困惑的部分是最后一句话:
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.
读取指定文件的足够权限取决于父目录的读取权限,而不是指定文件的读取权限。 (Rob 先生的补充评论)。 “足够”这个词可能会暗示它仅需要对父目录进行读取访问的行为,不是对指定文件的读访问。
但我承认,解释和用词可能听起来违反直觉,因为人们可能会直观地将“足够的权限来读取指定文件”解释为对指定文件的读取权限而不是父目录。
关于c# - 当拒绝访问文件与拒绝访问目录时,File.Exists 的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34890013/