Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syscall, os: opening hidden file for write access on Windows gives ACCESS_DENIED_ERROR #25923

Open
FabienTregan opened this issue Jun 16, 2018 · 8 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Milestone

Comments

@FabienTregan
Copy link

What version of Go are you using (go version)?

go version go1.10.2 windows/amd64

also reproduces on go version go1.8.7 windows/386

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

set GOARCH=amd64
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows

What did you do?

I try to make a write access to an hidden text file on windows 10.

I made separate project to reproduce the issue here : https://github.com/FabienTregan/TestWritingToHiddenFilesInGo (with a bit more informations in the readme.md file)

What did you expect to see?

Some text written in the file

What did you see instead?

Received unexpected error:
open C:\Users[USER NAME]\AppData\Local\Temp\write_to_hidden_file_test_204946587: Access is denied.

@FabienTregan
Copy link
Author

FabienTregan commented Jun 16, 2018

Someone on the gophers slack confirmed having the same result under windows 7 with my code. So either my code is wrong, or there really is an issue.

@odeke-em odeke-em changed the title Opening hidden file for write acess on Windows gives ACCESS_DENIED_ERROR syscall, os: opening hidden file for write access on Windows gives ACCESS_DENIED_ERROR Jun 17, 2018
@odeke-em
Copy link
Member

Thank you for the report @FabienTregan!

I'll page some some wizards /cc @alexbrainman @ianlancetaylor

@odeke-em odeke-em added OS-Windows NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Jun 17, 2018
@FabienTregan
Copy link
Author

FabienTregan commented Jun 17, 2018

trying to investigate the problem with people on gophers' slack,
I was hinted this :

Kale Blankenship [22 h 37]
@Fabien I think this is due to how the Windows API works.
> If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile
> fails and sets the last error to ERROR_ACCESS_DENIED if the file exists
> and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM attribute. To
> avoid the error, specify the same attributes as the existing file.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
The typical path sets `FILE_ATTRIBUTE_NORMAL`
(https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go#L289),
which is probably a reasonable thing to do. From my brief reading of the
docs, the way around it would be to first read the existing attributes
before opening. Conceivably, you could work around it using
`syscall.CreateFile` and `os.NewFile` yourself .

But the flags to File.Open do not seem to contain a bit for visibility.
I could not find how to workaround my problem with this information.

@ianlancetaylor
Copy link
Contributor

What happens with the C fopen call on WIndows? Does it support opening hidden files?

@ianlancetaylor ianlancetaylor added this to the Go1.12 milestone Jun 19, 2018
@FabienTregan
Copy link
Author

FabienTregan commented Jun 19, 2018

@ianlancetaylor I've not been writting any C for at least 15 years, but made this test :

$ cat write.c
#include <stdio.h>

int main (int argc, char *argv[]) {

  FILE *f = fopen("file.txt", "w");
  if (f == NULL)
  {
    printf("Error opening file!\n");
    return -1;
  }

  fprintf(f, "written");

}

It writes Error opening file! if file.txt is hidden.
Opening the file in "a" mode works, though.

@FabienTregan
Copy link
Author

It seems that fopen on windows calls CreateFile, which documentation says :

If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile fails and sets the last error to ERROR_ACCESS_DENIED if the file exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM attribute. To avoid the error, specify the same attributes as the existing file.

@ianlancetaylor
Copy link
Contributor

@FabienTregan Thanks, we also call CreateFile. What I was wondering was whether the C fopen function passed FILE_ATTRIBUTE_NORMAL, but it seems that it doesn't. That makes me wonder whether we should change Go's syscall.Open to not pass FILE_ATTRIBUTE_NORMAL.

It looks like the use of FILE_ATTRIBUTE_NORMAL dates back to when @alexbrainman added the code in https://golang.org/cl/770041.

@alexbrainman
Copy link
Member

But the flags to File.Open do not seem to contain a bit for visibility.
I could not find how to workaround my problem with this information.

I think others suggest you use syscall.CreateFile directly in your program as you see fit.

That makes me wonder whether we should change Go's syscall.Open to not pass FILE_ATTRIBUTE_NORMAL.

Sure, we, probably, could do that. I changed:

diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.goindex 5cfdb76e2b..d46ce1a0c4 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -286,7 +286,7 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
        default:
                createmode = OPEN_EXISTING
        }
-       h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
+       h, e := CreateFile(pathp, access, sharemode, sa, createmode, 0, 0)
        return h, e
 }

and that still passes on my computer. But, according to the documentation:

CreateFile fails and sets the last error to ERROR_ACCESS_DENIED if the file exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM attribute. To avoid the error, specify the same attributes as the existing file.

and I don't see how my change above will help here - the documentation requires us to pass "the same attributes as the existing file".

I also not sure, if we want to change the way we treat hidden files.

Alex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Projects
None yet
Development

No branches or pull requests

5 participants