{"id":111836,"date":"2025-12-03T07:00:00","date_gmt":"2025-12-03T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111836"},"modified":"2025-12-03T10:29:13","modified_gmt":"2025-12-03T18:29:13","slug":"20251203-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20251203-00\/?p=111836","title":{"rendered":"How do I check whether the user has permission to create files in a directory?"},"content":{"rendered":"<p>A customer wanted to accept a directory entered by the user and verify that the user has permission to create files in that folder. The directory itself might not even be on a local hard drive; it could be a DVD or a remote network volume. They tried calling <code>Get\u00adFile\u00adAttributes<\/code>, but all they were told was that it was a directory.\u00b9 How can they find out whether the user can create files in it?<\/p>\n<p>The file attributes are largely <a title=\"The early history of Windows file attributes, and why there is a gap between System and Directory\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180830-00\/?p=99615\"> legacy flags carried over from MS-DOS<\/a>. The actual control over what operations are permitted comes not from the file attributes but from the security attributes.<\/p>\n<p>Fortunately, you don&#8217;t have to learn how to parse security attributes. You can just specify the desired attributes when you open the file or directory. In other words, to find out if you can <a href=\"https:\/\/donasarkar.com\/\">do the thing<\/a>, ask for permission to do the thing.<\/p>\n<p>The security attribute that controls whether users can create new files in a directory is <code>FILE_<wbr \/>ADD_<wbr \/>FILE<\/code>. You can find a complete list in the documentation under <a title=\"File Access Rights Constants\" href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/fileio\/file-access-rights-constants\"> File Access Rights Constants<\/a>.<\/p>\n<p>Directories are a little tricky because you have to open them with backup semantics.<\/p>\n<pre>bool HasAccessToDirectory(PCWSTR directoryPath, DWORD access)\r\n{\r\n    HANDLE h = CreateFileW(directoryPath, access,\r\n        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,\r\n        OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);\r\n    if (h == INVALID_FILE_HANDLE) {\r\n        return false;\r\n    } else {\r\n        CloseHandle(h);\r\n        return true;\r\n    }\r\n}\r\n\r\nbool CanCreateFilesInDirectory(PCWSTR directoryPath)\r\n{\r\n    return HasAccessToDirectory(directoryPath, FILE_ADD_FILE);\r\n}\r\n<\/pre>\n<p>You can choose other access flags to detect other things. For example, checking for <code>FILE_<wbr \/>ADD_<wbr \/>SUBDIRECTORY<\/code> checks whether the user can create subdirectories, and checking for <code>FILE_<wbr \/>DELETE_<wbr \/>CHILD<\/code> checks whether the user can delete files and remove subdirectories from that directory. If you want to check multiple things, you can OR them together, because security checks require that you be able to do <i>all<\/i> of the things you requested before it will let you in.<\/p>\n<pre>bool CanCreateFilesAndSubdirectoriesInDirectory(PCWSTR directoryPath)\r\n{\r\n    return HasAccessToDirectory(directoryPath,\r\n                FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY);\r\n}\r\n<\/pre>\n<p>Note that these are moment-in-time checks. You will have to be prepared for the possibility that the user has lost access by the time you actually try to perform the operation. But this will at least give you an opportunity to tell the user up front, &#8220;You don&#8217;t have permission to create files in this folder. Pick another one.&#8221;\u00b2<\/p>\n<p>As I noted, this technique applies to files as well. If you want to know if the user can write to a file, open it for writing and see if it succeeds!<\/p>\n<p>\u00b9 And we learned some time ago that <a title=\"Why is the readonly property for folders so strange?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20030930-00\/?p=42353\"> the read-only attribute on directories doesn&#8217;t actually make the directory read-only<\/a>.<\/p>\n<p>\u00b2 This could be handy if the act of creating the files happens much later in the workflow. For example, maybe you&#8217;re asking the user where to save the query results. The query itself might take a long time, so you don&#8217;t want to let the user pick a directory, and then 30 minutes later, put up a dialog box saying &#8220;Oops, I couldn&#8217;t save the files in that directory. Maybe you should have picked a better one 30 minutes ago.&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Request the directory security attributes that correspond to your proposed operation.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-111836","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Request the directory security attributes that correspond to your proposed operation.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111836","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=111836"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111836\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=111836"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111836"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111836"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}