Filemode() / stat().mode: How to interpret the resulting UInt64-number

I wonder how to interpret the output of stat(), one example is the field “mode”.
Unfortunately, the documentation is not very helpful for me, how can I transfer this in something like “(-rw-rw-rw-)”, or even more comfortable? Is there package around that helps?
Here my script snippet to figure out what is behind the output of “filemode() / stat().mode

s_fn = raw"C:\tmp\somefile.txt"
if isfile(s_fn)
    println("stat(", s_fn, "):")
    println(stat(s_fn))
else
    error("File: \"", s_fn, "\" does not exist!")
end
mode_of_file = stat(s_fn).mode; # alternative: filemode()
typeof_of_file = typeof(mode_of_file); # UInt64
typeof_converted_to_string = string(mode_of_file)

Julia has a builtin for that, although it is not exported

julia> Base.Filesystem.filemode_string(filemode(“error.png”))
“-rw-rw-rw-”

It’s in here if you want the code

1 Like

@lawless-m: Thanks, it works! So also for the other fields, it is useful to read the source code of “stat.jl

And how do I interpret the bitfield which is the output of “uperm()”?
I have read the documentation of the package “BitsFields” but I still do not understand,
if this package is useful to read the UInt8-bitfield of “uperm()

StatStructs (returned by stat) have nice display methods since Julia 1.7:

julia> stat("Project.toml")
StatStruct for "Project.toml"
   size: 504 bytes
 device: 66310
  inode: 11668897
   mode: 0o100664 (-rw-rw-r--)
  nlink: 1
    uid: 1000 (fredrik)
    gid: 1000 (fredrik)
   rdev: 0
  blksz: 4096
 blocks: 8
  mtime: 2022-02-01T17:39:35+0100 (9 days ago)
  ctime: 2022-02-01T17:39:35+0100 (9 days ago)

(for which the internal function linked to above is used).

The .mode field of the struct is stored as a UInt, but if you format it in base 8 it perhaps look more familiar:

julia> stat("Project.toml").mode
0x00000000000081b4

julia> string(stat("Project.toml").mode; base = 8)
"100664"

So 664, in base 8, means -rw-rw-r--, see e.g. wikipedia.org/File-system_permissions#Numeric_notation. (I am not sure what the first 1 mean here though?)

Same thing here, if you format it as bits (base 2) you get

julia> uperm("Project.toml")
0x06

julia> bitstring(uperm("Project.toml"))
"00000110"

so my permissions on this file is 110, i.e. read and write, but not execute.

2 Likes

@fredrikekre: Thank you!

The documentation about the bitfield of uperm() is strange to me, for me it should look like:

| Value | Description        |
|:------|:-------------------|
| 06    | Read Permission    |
| 07    | Write Permission   |
| 08    | Execute Permission |

or the other way round:

| Value | Description        |
|:------|:-------------------|
| 03    | Read Permission    |
| 02    | Write Permission   |
| 01    | Execute Permission |

Is | 04 | Read Permission | perhaps a typo?

Here a code snippet to clarify the situation for me:

s_bitstring = bitstring(uperm("Project.toml"))
if s_bitstring[8] == '1'
    println("File: \"Project.toml\" is executable!")
end
if s_bitstring[7] == '1'
    println("File: \"Project.toml\" has write permission.")
end
if s_bitstring[6] == '1'
    println("File: \"Project.toml\" has read permission.")
end

1, 2, and 4 are the integer values (base 10) of the bit patterns (i.e. base 2) 001, 010, and 100, respectively:

julia> parse(Int, "001"; base=2)
1

julia> parse(Int, "010"; base=2)
2

julia> parse(Int, "100"; base=2)
4
1 Like

@fredrikekre: thanks a lot! I hope this topic will help also others to understand the meaning of this part of the Julia documentation :slight_smile:

I would document it this way to make the concept clear:

| BitMask  | Int | Description        |
|:---------|:----|:-------------------|
|'00000100'|  4  | Read Permission    |
|'00000010'|  2  | Write Permission   |
|'00000001'|  1  | Execute Permission |

Meanwhile I found the function to calculate the BitVector:

upermBitVec = BitVector(digits(uperm("Project.toml"), base=2, pad=8))

Opposite Bit Order (from right → left):

upermBitVecRight2Left = BitVector(digits(uperm("Project.toml"), base=2, pad=8) |> reverse )

That could be a good improvement to the docs, feel free to contribute it. The docstring is here: https://github.com/JuliaLang/julia/blob/7ca1a9047aaaa6a9a31e5025f4728fc1d86a5cf8/base/stat.jl#L406-L417.

1 Like

In another project, it was quite complicated for me to reach the point to suggest modifications,
I hope it is more easy for Julia. I will have a look. :slight_smile:

1 Like