我正在尝试使用GetSecurityInfo获取文件所有者,但是获取GetSecurityInfo总是返回5,“ACCESS DENIED”即使我有权获得该文件的所有权。 .NET方法“GetOwner”有效,但我需要长文件名支持,并且限制使用.NET 4.6.2或增加长文件名支持的第三方.NET库。
我想以一种处理长文件名(超过260个字符)的方式获取文件所有者,并且可以在.NET 4.0中使用。
有效,但无法处理长文件路径
var fs = File.GetAccessControl(filename);
var sid = fs.GetOwner(typeof(SecurityIdentifier));
Console.WriteLine(sid); // SID
var ntAccount = sid.Translate(typeof(NTAccount));
应处理长文件路径,但始终返回拒绝访问:
FileAccess.Read = 1 FileShare.ReadWrite = 3
[Flags]
public enum FileAttributes : uint
{
/// <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, or in Windows Vista".
/// </summary>
Readonly = 0x00000001,
/// <summary>
/// The file or directory is hidden. It is not included in an ordinary directory listing.
/// </summary>
Hidden = 0x00000002,
/// <summary>
/// A file or directory that the operating system uses a part of, or uses exclusively.
/// </summary>
System = 0x00000004,
/// <summary>
/// The handle that identifies a directory.
/// </summary>
Directory = 0x00000010,
/// <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>
Archive = 0x00000020,
/// <summary>
/// This value is reserved for system use.
/// </summary>
Device = 0x00000040,
/// <summary>
/// A file that does not have other attributes set. This attribute is valid only when used alone.
/// </summary>
Normal = 0x00000080,
/// <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>
Temporary = 0x00000100,
/// <summary>
/// A file that is a sparse file.
/// </summary>
SparseFile = 0x00000200,
/// <summary>
/// A file or directory that has an associated reparse point, or a file that is a symbolic link.
/// </summary>
ReparsePoint = 0x00000400,
/// <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>
Compressed = 0x00000800,
/// <summary>
/// The data of a file is not available immediately. This attribute indicates that the file data is physically moved to offline storage. This attribute is used by Remote Storage, which is the hierarchical storage management software. Applications should not arbitrarily change this attribute.
/// </summary>
Offline = 0x00001000,
/// <summary>
/// The file or directory is not to be indexed by the content indexing service.
/// </summary>
NotContentIndexed = 0x00002000,
/// <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>
Encrypted = 0x00004000,
/// <summary>
/// This value is reserved for system use.
/// </summary>
Virtual = 0x00010000
}
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LocalFree(
IntPtr handle
);
[DllImport("advapi32.dll", SetLastError = true)]
static extern int GetSecurityInfo(
SafeFileHandle handle,
SE_OBJECT_TYPE objectType,
SECURITY_INFORMATION securityInfo,
out IntPtr sidOwner,
out IntPtr sidGroup,
out IntPtr dacl,
out IntPtr sacl,
out IntPtr securityDescriptor);
enum SE_OBJECT_TYPE
{
SE_UNKNOWN_OBJECT_TYPE,
SE_FILE_OBJECT,
SE_SERVICE,
SE_PRINTER,
SE_REGISTRY_KEY,
SE_LMSHARE,
SE_KERNEL_OBJECT,
SE_WINDOW_OBJECT,
SE_DS_OBJECT,
SE_DS_OBJECT_ALL,
SE_PROVIDER_DEFINED_OBJECT,
SE_WMIGUID_OBJECT,
SE_REGISTRY_WOW64_32KEY
}
enum SECURITY_INFORMATION
{
OWNER_SECURITY_INFORMATION = 1,
GROUP_SECURITY_INFORMATION = 2,
DACL_SECURITY_INFORMATION = 4,
SACL_SECURITY_INFORMATION = 8,
}
public static string GetOwner(string filename)
{
string owner = "";
var hFile = CreateFile(
filename,
FileAccess.Read,
FileShare.ReadWrite,
IntPtr.Zero,
FileMode.Open,
FileAttributes.Normal,
IntPtr.Zero);
if (!hFile.IsInvalid)
{
IntPtr ownerSid;
IntPtr groupSid = IntPtr.Zero;
IntPtr dacl = IntPtr.Zero;
IntPtr sacl = IntPtr.Zero;
IntPtr securityDescriptor = IntPtr.Zero;
int returnValue = GetSecurityInfo(
hFile,
SE_OBJECT_TYPE.SE_FILE_OBJECT,
SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
out ownerSid,
out groupSid,
out dacl,
out sacl,
out securityDescriptor
);
if (returnValue == ERROR_SUCCESS)
{
IntPtr sidString = IntPtr.Zero;
var sid = new SecurityIdentifier(ownerSid);
var ntAccount = sid.Translate(typeof(NTAccount));
owner = ntAccount.ToString();
}
else
{
Win32Exception exception = new Win32Exception(returnValue);
owner = string.Format("Failed to get owner: {0}", exception.Message);
}
LocalFree(securityDescriptor);
}
else
{
Win32Exception exception = new Win32Exception(Marshal.GetLastWin32Error());
owner = string.Format("Failed to open file when getting owner: {0}", exception.Message);
}
return owner;
}