How does Read-Only affect a Directory when using C#/.Net?

前端 未结 3 584
南笙
南笙 2021-01-14 08:16

I\'ve found that I can write (say, copy a file into) a Read-Only directory. That is, a Directory with ...Attributes = FileAttributes.ReadOnly.I can even change

相关标签:
3条回答
  • 2021-01-14 08:19

    The read-only attribute on a directory entry in the file system has limited usefulness. Most any user would expect all the files in the directory to become read-only as well. But that's not how NTFS works, attributes only apply to the file system object itself and are not "inherited" like the security attributes are.

    Note how Explorer modified the way the attribute works in its UI, when you turn it on then it does what any user expects, it makes all the files read-only instead of setting the attribute on the directory itself.

    But yes, it does work, it prevents modifications to the directory object itself. So if you turn it on in code then that does prevent deleting the directory. Just as it does with a file.

    0 讨论(0)
  • 2021-01-14 08:24

    As Damien_The_Unbeliever mentions, if we look at the Win32 API for FILE_ATTRIBUTE_READONLY it mentions:

    This attribute is not honored on directories.

    See also: http://go.microsoft.com/fwlink/p/?linkid=125896

    So it seems indeed that you can simply delete such directories using win32 or Explorer. .NET, however, seems to check flags on directories before deleting them. You can see this by using DotPeek or Reflector, on Directory.Delete for example. This is what's causing your "access denied" error.

    EDIT:

    I looked into this in a bit more detail, and it seems like it is not .NET which is throwing the access denied error. Consider the following test code:

    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    
    namespace ReadOnlyDirTest
    {
       class Program
       {
          [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
          extern static bool RemoveDirectory(string path);
    
          static String CreateTempDir()
          {
             String tempDir;
             do
             {
                tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
             } while (Directory.Exists(tempDir));
    
             Directory.CreateDirectory(tempDir);
             return tempDir;
          }
    
          static void Main(string[] args)
          {
             var tempDir = CreateTempDir();
    
             // Set readonly.
             new DirectoryInfo(tempDir).Attributes |= FileAttributes.ReadOnly;
    
             try
             {
                Directory.Delete(tempDir);
             }
             catch (Exception e)
             {
                Console.WriteLine("Directory.Delete: " + e.Message);
             }
    
             if (!Directory.Exists(tempDir))
                Console.WriteLine("Directory.Delete deleted directory");
    
             try
             {
                if (!RemoveDirectory(tempDir))
                   Console.WriteLine("RemoveDirectory Win32 error: " + Marshal.GetLastWin32Error().ToString());
             }
             catch (Exception e)
             {
                Console.WriteLine("RemoveDirectory: " + e.Message);
             }
    
             if (!Directory.Exists(tempDir))
                Console.WriteLine("RemoveDirectory deleted directory");
    
             // Try again without readonly, for both.
             tempDir = CreateTempDir();
             Directory.Delete(tempDir);
             Console.WriteLine("Directory.Delete: removed normal directory");
    
             tempDir = CreateTempDir();
             if (!RemoveDirectory(tempDir))
                Console.WriteLine("RemoveDirectory: could not remove directory, error is " + Marshal.GetLastWin32Error().ToString());
             else
                Console.WriteLine("RemoveDirectory: removed normal directory");
    
             Console.ReadLine();
          }
       }
    }
    

    Running this on my machine (win 7) I get the following output:

        Directory.Delete: Access to the path 'C:\...\Local\Temp\a4udkkax.jcy' is denied.
        RemoveDirectory Win32 error: 5
        Directory.Delete: removed normal directory
        RemoveDirectory: removed normal directory
    

    We see we get error code 5, which, according to http://msdn.microsoft.com/en-gb/library/windows/desktop/ms681382(v=vs.85).aspx, is an Access Denied error.

    I can then only assume that Explorer unsets the readonly attribute before deleting a directory, which is of course easily done. The command rmdir also removes a directory marked as readonly.

    As the documentation suggests the readonly flag should is not honoured on directories (even though it seems to be in Win 7), I would not rely on this behaviour. In other words I would not rely on readonly preventing anything.

    0 讨论(0)
  • 2021-01-14 08:46

    It doesn't. Peel off enough layers, and you'll find the function used to change the attributes on a directory is SetFileAttributes:

    Sets the attributes for a file or directory.

    And note:

    FILE_ATTRIBUTE_READONLY 1 (0x1) 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.

    (My emphasis)

    0 讨论(0)
提交回复
热议问题