Go File Permissions on Linux

I wrote an application in Go, aka Golang, that I use to search for text matching a regex pattern within text files. Up to now, everything has worked well with my testing on Windows 10. However, I put my compiled application on to a Linux machine (specifically RHEL) today and I was getting errors with my os.MkdirAll() call. The function call looked like this in my code:

if _, err := os.Stat(logDirectory); os.IsNotExist(err) {
   os.MkdirAll(logDirectory, 0777)
}

Basically this code creates a directory using the path specified in the variable logDirectory with the permissions 777 (Read, Write, and Execute for all users) if the directory does not already exist. If the directory does not exist it will create the directory as well as any necessary parent directories that don’t already exist.

What I found is that my application creates the non-existent directory, but the permissions specified (0777) aren’t what are actually applied to the newly created directory. What ends up being applied is the default permissions according to the umask that is set. So you can see below that my umask is set to 0777 (meaning grant no permissions to newly created files and directories) so the newly created directory has the permissions 0000.

filepermissions.png

If you are unfamiliar with umask, like I was, then here is a basic description as I understand it. Umask is the default permission given when a new file or folder is created on a Linux/Unix machine. Umask accepts values between 0 and 7 that are the negated form of normal permissions. Meaning if you want the default permissions on a directory to be 765 then you should set the umask value to 012. Or if you want the default permissions to be 555, then you should set umask to 222. You can set umask in a shell simply by typing ‘umask’ followed by the desired value. You can view what umask is set to by entering ‘umask’ with no value after it. For example:

umask.png

So back to the issue my Go application was experiencing. I thought this must be some sort of bug when running Go on Linux. Through some Googling, I found that many other Go users have thought the same thing as me. However, the creators of Go state that this is not a bug. Basically their answer is that Go is built to run on various OS’s, but it still has to honor the behaviors expected on each OS. Meaning that in my case, I should not expect file permissions to be handled consistently between my testing on Windows 10 and Linux RHEL. This makes sense. Although, it makes me wonder why the Go MkdirAll() function accepts a parameter for setting the permissions if it isn’t going to be honored.

The Solution

The solution I was able to come up with to solve this issue is that you must use the os.Chmod() function to set the permissions of a directory after creating the directory with the os.MkdirAll() function. Yes it seems weird that I am stating in code to set the permissions to 0777 twice, but that’s the way it is. So here is my updated code:

if _, err := os.Stat(logDirectory); os.IsNotExist(err) {
   os.MkdirAll(logDirectory, 0777)
   os.Chmod(logDirectory, 0777)
}

Here are the results of my test on Linux using this new code:

filepermissionswithchmod.png

As you can see, umask was set to 0777 which means that a newly created directory should have the default permissions of 0000. However, thanks to the addition of os.Chmod() the logs directory now has the permissions 0777. Now that the logs directory has the desired permissions, my Go application is able to run as expected and create new log files when needed.

Additional Information

Unix Permissions Calculator

Umask Explanation

Discussion on how Go’s os.Mkdir() function should handle permission bits.

Linux Chmod Command

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s