Reputation: 184
I need to use Go to get the file permissions of a given file (specifically the SUID bit). Here are the permissions of an example file.
$ touch example_file.test
$ chmod 7777 example_file.test
$ ls -ltra example_file.test
-rwsrwsrwt 1 luke users 0 Feb 25 21:53 example_file.test
$ stat -c "%a %n" example_file.test
7777 example_file.test
Here is a tiny program illustrating the issue.
func main() {
info, _ := os.Stat("example_file.test")
fmt.Println(info.Mode().String()) // ugtrwxrwxrwx
fmt.Println(info.Mode().Perm().String()) // -rwxrwxrwx
fmt.Printf("permissions: %#o\n", info.Mode().Perm()) // permissions: 0777
}
The Go results are inconsistent because ugtrwxrwxrwx != 0777
.
The following quote from the documentation indicates that this might be a cross-platform compatibility issue.
A FileMode represents a file's mode and permission bits. The bits have the same definition on all systems, so that information about files can be moved from one system to another portably. Not all bits apply to all systems. The only required bit is ModeDir for directories.
type FileMode uint32 The defined file mode bits are the most significant bits of the FileMode. The nine least-significant bits are the standard Unix rwxrwxrwx permissions. The values of these bits should be considered part of the public API and may be used in wire protocols or disk representations: they must not be changed, although new bits might be added.
Is this a limitation of Go?
Upvotes: 4
Views: 1734
Reputation: 6877
It's worth noting that in addition to the octal representations not matching, neither do the string representations:
"-rwsrwsrwt" != "ugtrwxrwxrwx"`
This is not due to a limitation of the Go implementation, but is instead a consequence of it being implemented in a system agnostic manner.
From the FileMode
documentation (emphasis mine):
A FileMode represents a file's mode and permission bits. The bits have the same definition on all systems, so that information about files can be moved from one system to another portably. Not all bits apply to all systems.
Because the implementation isn't meant to mimic the behavior of a specific system, the output isn't guaranteed to match the native tools in a given environment. However, all of the relevant data is there to work with.
If you wanted to mimic the output of stat
you can just author some logic to do so.
Here's a quick example that tackles the octal representation:
package main
import (
"fmt"
"os"
)
func UnixPerm(m os.FileMode) (p uint32) {
p = uint32(m.Perm())
if m & os.ModeSetuid != 0 {
p |= 04000
}
if m & os.ModeSetgid != 0 {
p |= 02000
}
if m & os.ModeSticky != 0 {
p |= 01000
}
return p
}
func main() {
info, _ := os.Stat("example_file")
fmt.Printf("FileMode.Perm(): %04o\n", info.Mode().Perm())
fmt.Printf("UnixPerm(): %04o\n", UnixPerm(info.Mode()))
}
Output:
$ go run fileperm.go
FileMode.Perm(): 0777
UnixPerm(): 7777
$ stat --printf "Permissions: %a\n" example_file
Permissions: 7777
Upvotes: 4
Reputation: 2126
I need to use golang to get the file permissions of a given file (specifically the SUID bit)
Ok, add this: fmt.Printf("File has SUID bit set: %t\n", info.Mode()&os.ModeSetuid != 0)
The golang results are inconsistant because ugtrwxrwxrwx != 0777
info.Mode()
and info.Mode().Perm()
are different things, though related.
info.Mode().Perm()
contains a subset of info.Mode()
. info.Mode().Perm()
is simply a little convenience function to do a bit-wise AND with a constant mask 0777
.
Is this a limitation of go?
No
Upvotes: 1