C#使用DirectorySecurity的SetOwner设置文件夹所有者只能设为当前用户

看到有人问了这个问题,查询并实验后发现确实有这个问题,测试代码如下:

static void Main(string[] args)

{

    try

    {

        string folderPath = @"e:\testSecurity";



        Directory.CreateDirectory(folderPath);



        DirectorySecurity defaultFSec = Directory.GetAccessControl(folderPath);



        IdentityReference newUser = new NTAccount("User2");



        defaultFSec.SetOwner(newUser);



        Directory.SetAccessControl(folderPath, defaultFSec);

    }

    catch(Exception ex)

    {

        Console.WriteLine(ex);

    }

    Console.ReadLine();

}

结果是System.InvalidOperationException: The security identifier is not allowed to be the owner of this object.

2005年在Microsoft Connect上就有人提出了这个问题,微软说下个版本将会考虑添加这个功能,然而现在似乎还不行。

当然总是有什么其他办法的,既然资源管理器可以做到,那么直接调用API就是一个可行的办法。Richard Willis给出了一个实现方法,我这里把他的代码转贴一下:

sealed class UnmanagedCode

{

    [DllImport("kernel32.dll", SetLastError=true)]

    [return: MarshalAs(UnmanagedType.Bool)]

    static extern bool CloseHandle(IntPtr hObject);



    // Use this signature if you do not want the previous state

    [DllImport("advapi32.dll", SetLastError=true)]

    [return: MarshalAs(UnmanagedType.Bool)]

    static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,

        [MarshalAs(UnmanagedType.Bool)]bool disableAllPrivileges,

        ref TOKEN_PRIVILEGES newState,

        UInt32 bufferLength,

        IntPtr previousState,

        IntPtr returnLength);



    [DllImport("kernel32.dll", ExactSpelling = true)]

    static extern IntPtr GetCurrentProcess();



    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]

    static extern bool OpenProcessToken

        (IntPtr processHandle, int desiredAccess, ref IntPtr phtok);



    [DllImport("advapi32.dll", SetLastError = true)]

    static extern bool LookupPrivilegeValue

            (string host, string name, ref LUID lpLuid);



    [StructLayout(LayoutKind.Sequential, Pack = 1)]

    struct TOKEN_PRIVILEGES

    {

        public UInt32 PrivilegeCount;

        public LUID Luid;

        public UInt32 Attributes;

    }



    [StructLayout(LayoutKind.Sequential)]

    public struct LUID

    {

       public uint LowPart;

       public int HighPart;

    }



    const int SE_PRIVILEGE_ENABLED = 0x00000002;

    const int TOKEN_QUERY = 0x00000008;

    const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

    //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx

    const string SE_RESTORE_PRIVILEGE = "SeRestorePrivilege"; 



    public static void GiveRestorePrivilege()

    {

        TOKEN_PRIVILEGES tokenPrivileges;

        tokenPrivileges.PrivilegeCount = 1;

        tokenPrivileges.Luid = new LUID();

        tokenPrivileges.Attributes = SE_PRIVILEGE_ENABLED;



        IntPtr tokenHandle = RetrieveProcessToken();



        try

        {

            bool success = LookupPrivilegeValue

                        (null, SE_RESTORE_PRIVILEGE, ref tokenPrivileges.Luid);

            if (success == false)

            {

                int lastError = Marshal.GetLastWin32Error();

                throw new Exception(

                    string.Format("Could not find privilege {0}. Error {1}",

                                        SE_RESTORE_PRIVILEGE, lastError));

            }



            success = AdjustTokenPrivileges(

                                                tokenHandle, false,

                                                ref tokenPrivileges, 0,

                                                IntPtr.Zero, IntPtr.Zero);

            if (success == false)

            {

                int lastError = Marshal.GetLastWin32Error();

                throw new Exception(

                    string.Format("Could not assign privilege {0}. Error {1}",

                                    SE_RESTORE_PRIVILEGE, lastError));

            }

        }

        finally

        {

            CloseHandle(tokenHandle);

        }



    }



    static IntPtr RetrieveProcessToken()

    {

        IntPtr processHandle = GetCurrentProcess();

        IntPtr tokenHandle = IntPtr.Zero;

        bool success = OpenProcessToken(processHandle,

                                        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,

                                        ref tokenHandle);

        if (success == false)

        {

            int lastError = Marshal.GetLastWin32Error();

            throw new Exception(

                string.Format("Could not retrieve process token. Error {0}",

                                    lastError));

        }

        return tokenHandle;

    }

}

你可能感兴趣的:(Directory)