Access to a file's attributes is controlled by two things


We saw some time ago that permission to delete a file is granted either

  • if you have DELETE access on the file, or
  • if you have FILE_DELETE_CHILD access on the containing directory.

File attributes behave in an analogous way.

Permission to read a file's attributes is granted either

  • if you have FILE_READ_ATTRIBUTES access on the file, or
  • if you have FILE_LIST_DIRECTORY access on the containing directory.

If you want the file's attributes, you could always get it by reading the directory, because one of the pieces of information you get from Find­First­File is the file attributes. Therefore, having permission to read a directory implicitly gives you permission to read the attributes of any file in that directory.

(Note, of course, that write permission on attributes is another story.)

Comments (20)
  1. DWalker says:

    @Cesar:  I don't understand all of it either, but if you put a file into a directory, and the directory has permission set X, that permission set governs who can do what with the file.  Does the act of writing the file set the inherited permissions from the directory into the file?

  2. Cesar says:

    @Kevin: Unix ACLs are also in the inode (in a xattr, in fact), so the directory permissions don't matter.

    Unix has a simple conceptual model with a quite clean split between the inode and the directory; what I'm trying to visualize is NT's equivalent. How and why NT's permissions work should become obvious from it.

    (There's also the "bypass traverse checking" thing Raymond mentioned here a long time ago; if I understood it correctly, it bypasses going through the directory and goes directly to the file, making the file/directory distinction much more important.)

  3. @Cesar says:

    I'm pretty sure the attributes are in both the file (MFT, actually) and directory. Directory in some sense are like database indexes, they duplicate some information for performance. If enumerating files in a directory required MFT access it would be very slow.

    [Yup. -Raymond]
  4. Joshua says:

    @@Cesar (this is why you don't put @person in name): And they get out of date. Every once in awhile I have to write my programs to call stat() on the file name it just got back from FindNextFile().

    [stat() is a library call that I'm not exactly sure what system calls it boils down to.]

  5. Darran Rowe says:

    @Joshua:

    The stat function gets its information from a few different sources. From the MSDN documentation

    "Bit mask for file-mode information. The _S_IFDIR bit is set if path specifies a directory; the _S_IFREG bit is set if path specifies an ordinary file or a device. User read/write bits are set according to the file's permission mode; user execute bits are set according to the filename extension."

    So it is most likely that the FILE_ATTRIBUTE_READONLY from the GetFileAttributes family is what governs the read/write stuff.

  6. sense says:

    I've read the "Yup." article you linked, and boy, I do feel for you having to explain these things to your customers!! It takes a lot of background to even start describing what a customer sees happening. And even then it'll be hard to grasp for a typical user of "Explorer".

    How would've you gone explaining it before writing the blog post? Unbearable!

  7. dave says:

    >if I understood it correctly, it bypasses going through the directory and goes directly to the file, making the file/directory distinction much more important

    You can't "bypass going through the directory"... if you want to open file /foo/bar/mumble/frotz, you're going (plus or minus any path-cache assists) to look at the directories foo, bar, and mumble before you can get to file frotz.

    But you can bypass checking whether the caller has lookup access to those directories, and simply assume that he has. This is what bypass traverse checking gets you.

  8. Cesar says:

    I'm trying to understand it conceptually.

    If the attributes are in the file like on Unix, the directory permissions shouldn't matter.

    If the attributes are in the directory like on DOS, the file permissions shouldn't matter.

    The only way this makes sense is if the attributes are in the *directory entry*, and the file permissions are actually permissions to the *directory entry*, not the file. Since the directory entry is part of the directory, the directory permissions would also apply to it, as well as its own permissions. But then how would it work with hardlinks? Do they hardlink the *directory entry*? Would the permission for any directory apply? And where does the MFT come in all that?

  9. Kevin says:

    @Cesar:

    I'm not too sure myself, but it *looks* like the difference between file permission bits and facls in Unix-land.

  10. Mark says:

    I'd just like to say thank you for the snark about looking up version numbers in the "Yup"-linked post.

  11. Cesar says:

    Found the answer I was looking for, in the CreateHardLink function documentation (msdn.microsoft.com/.../aa363860%28VS.85%29.aspx):

    "The security descriptor belongs to the file to which a hard link points. The link itself is only a directory entry, and does not have a security descriptor. Therefore, when you change the security descriptor of a hard link, you a change the security descriptor of the underlying file, and all hard links that point to the file allow the newly specified access. You cannot give a file different security descriptors on a per-hard-link basis."

    So, let's see if I understood it. The attributes and permissions are in the file. But when you walk to the file through a directory, the directory can give the you extra permissions; if you walked to the file through a different directory, you could receive different permissions, but the permissions set in the file always apply no matter how you arrived at it. Am I correct?

  12. @dave: actually, under some circumstances you *can* bypass the directory, using OpenFileById.

  13. Darran Rowe says:

    That is generally why deny permissions are not recommended unless you know what you are doing. But Windows normally sorts the entries in the ACL so deny entries comes before allow entries.

    In this case though, I think it actually creates a bit of a split view. If you query the file directly via GetFileAttributes, you will get given error code 5. If you query via the directory, using FindFirstFile/FindNextFile then you will get the attributes. Of course, I could be completely wrong here.

  14. Jonathan says:

    How about DENY permissions? What if you have:

    * DENY FILE_READ_ATTRIBUTES access on the file

    * ALLOW FILE_LIST_DIRECTORY access on the containing directory

    In general, I've always found DENY permissions confusing, as have other people: serverfault.com/.../487130

  15. Ancient_Hacker says:

    Hmmm, How does getting the directory access information right now tell you anything about what you can do in the future?

    I once spent several days trying to figure out why a file wasn't accessible when there had just been a check for that.

    Well duh, previous knowledge does not guarantee future results.

  16. Ben says:

    The function stat() (and boost::filesystem) get their information from FindFirstFile etc. You can read the source if you don't believe me (since it is supplied with the SDK).

    Raymond, Does this rule also apply to GetFileInformationByHandle or GetFileInformationByHandleEx? I.e. if you have FILE_LIST_DIRECTORY on the directory, but no access on the file, will GetFileInformationByHandle give you the MFT record number in the FileIndex members?

    * msdn.microsoft.com/.../aa363788(v=vs.85).aspx

    Compare stat() which doesn't require permissions on the file only the directory:

    * linux.die.net/.../stat

  17. bv1 says:

    If using a Microsoft server for files/folders, Access rights controlled by 3 things,

    Share rights, folder Rights, & individual file rights.  Share rights are done by the path you get there, so if using a different path may get different rights. Using unc, \MyServMyShareMyprojectMyFile may also be \MyServfooMyProjectMyFile.  

    If foo was setup as read only, does not matter what rights y'all have at MyProject or MyFile, no joy. To delete use MyShare.

  18. Skyborne says:

    @bv1: that actually makes a lot of sense.  If you mount a filesystem RO under Linux, it doesn't matter if you have rwx on all the files and directories, you'll get "read-only filesystem" back if you try to unlink(2) from it.  I'm too lazy to check, but I think that includes root.

  19. @Ben: I've done some testing, and somewhat surprisingly, yes, it seems you can indeed use GetFileInformationByHandle on a file without FILE_READ_ATTRIBUTES permission if (and only if) you have FILE_READ_DATA access to the parent directory.  

    But it appears that you need at least SYNCHRONIZE access to the file itself in order to open a handle in the first place.

  20. Ben says:

    Harry, now I think of it the MFT record number (inode number) is in the directory table anyway so it still doesn't have to go off to the MFT record/inode. So I guess it makes sense that there is no difference in behaviour.

Comments are closed.

Skip to main content