How does the go language os.FileMode function convert permissions from integers/octal/??? before setting the flags?

天大地大妈咪最大 提交于 2019-12-02 15:17:40

问题


Update: based on the comment and response so far, I guess I should make it explicit that I understand 0700 is the octal representation of the decimal number 448. My concern here is that when an octal mode parameter or when a decimal number is recast as octal and passed to the os.FileMode method the resulting permissions on the file created using WriteFile don't seem to line up in a way that makes sense.

I worked as hard as I could to reduce the size of the question to its essence, maybe I need to go thru another round of that


Update2: after re-re-reading, I think I can more succinctly state my issue. Calling os.FileMode(700) should be the same as calling it with the binary value 1-010-111-100. With those 9 least significant bits there should be permissions of:

--w-rwxr-- or 274 in octal (and translates back to

Instead, that FileMode results in WriteFile creating the file with:

--w-r-xr-- which is 254 in octal.


When using an internal utility written in go, there was a file creation permission bug caused by using decimal 700 instead of octal 0700 when creating the file with ioutil.WriteFile(). That is: ioutil.WriteFile("decimal.txt", "filecontents", 700) <- wrong! ioutil.WriteFile("octal.txt", "filecontents", 0700) <- correct!

When using the decimal number (ie. no leading zero to identify it as an octal number to go_lang) the file that should have had permissions 0700 -> '-rwx------' had 0254 -> '--w-r-xr--'

After it was fixed, I noticed that when I converted 700 decimal to octal, I got “1274” instead of the experimental result of "0254".

When I converted 700 decimal to binary, I got: 1-010-111-100 (I added dashes where the rwx’s are separated). This looks like a permission of "0274" except for that leading bit being set.

I went looking at the go docs for FileMode and saw that under the covers FileMode is a uint32. The nine smallest bits map onto the standard unix file perm structure. The top 12 bits indicate special file features. I think that one leading bit in the tenth position is in unused territory.

I was still confused, so I tried:

package main
import (
    "io/ioutil"
    "fmt"
    "os"
)

func main() {
    content := []byte("temporary file's content")
    modes := map[string]os.FileMode{
        "700": os.FileMode(700),
        "0700": os.FileMode(0700),
        "1274": os.FileMode(1274),
        "01274": os.FileMode(01274)}
    for name, mode := range modes {
        if err := ioutil.WriteFile(name, content, mode); err != nil {
            fmt.Println("error creating ", name, " as ", mode)
        }
        if fi, err := os.Lstat(name); err == nil {
            mode := fi.Mode()
            fmt.Println("file\t", name, "\thas ", mode.String())
        }
    }
}

And now I'm even more confused. The results I got are:

file     700    has  --w-r-xr--
file     0700   has  -rwx------
file     1274   has  --wxr-x---
file     01274  has  --w-r-xr--

and was confirmed by looking at the filesystem:

--w-r-xr--     1 rfagen  staff           24 Jan  5 17:43 700
-rwx------     1 rfagen  staff           24 Jan  5 17:43 0700
--wxr-x---     1 rfagen  staff           24 Jan  5 17:43 1274
--w-r-xr--     1 rfagen  staff           24 Jan  5 17:43 01274
  • The first one is the broken situation that triggered the original bug in the internal application.
  • The second one is the corrected code working as expected.
  • The third one is bizarre, as 1274 decimal seems to translate into 0350
  • The fourth one kind of makes a twisted sort of sense, given that dec(700)->oct(1274) and explicitly asking for 01274 gives the same puzzling 0254 as the first case.

I have a vague suspicion that the extra part of the number larger than 2^9 is somehow messing it up but I can't figure it out, even after looking at the source for FileMode. As far as I can tell, it only ever looks at the 12 MSB and 9 LSB.


回答1:


os.FileMode only knows about integers, it doesn't care whether the literal representation is octal or not.

The fact that 0700 is interpreted in base 8 comes from the language spec itself:

An integer literal is a sequence of digits representing an integer constant. An optional prefix sets a non-decimal base: 0 for octal, 0x or 0X for hexadecimal. In hexadecimal literals, letters a-f and A-F represent values 10 through 15.

This is a fairly standard way of representing literal octal numbers in programming languages.




回答2:


So your file mode was changed from the requested 0274 to the actual on-disk 0254. I'll bet that your umask is 0022. Sounds to me like everything is working fine.



来源:https://stackoverflow.com/questions/48123541/how-does-the-go-language-os-filemode-function-convert-permissions-from-integers

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!