Search code examples
pythonunixfile-permissionsstatbitmask

How to get from '-rw-r--r--' back to 33188?


Python has a helper function stat.filemode to go from the st_mode (integer) as reported by os.stat into the familiar "stringy" format (I don't know if this representation has a proper name).

>>> stat.filemode(0o100644)
'-rw-r--r--'

Is there any "unfilemode" helper function to go the other way?

>>> unfilemode('-rw-r--r--')
33188

This is what I tried, but it's producing wrong results. That's not treating the first character denoting file type correctly, and not handling sticky bits etc

table = {
    ord('r'): '1',
    ord('w'): '1',
    ord('x'): '1',
    ord('-'): '0',
}

def unfilemode(s):
    return int(s.translate(table), 2)

Solution

  • Python is open-source, you can just read the source code for the stat module and write the inverse function.

    See: https://github.com/python/cpython/blob/master/Lib/stat.py#L112

    import stat
    
    def un_filemode(mode_str):
        mode = 0
        for char, table in zip(mode_str, stat._filemode_table):
            for bit, bitchar in table:
                if char == bitchar:
                    mode |= bit
                    break
        return mode
    

    Note that I'm being "naughty" and accessing private members of the stat module. The usual caveats apply.

    Also note that the documentation for stat.filemode is incorrect anyway, since 0o100000 is technically not part of the file mode, it is the file type S_IFREG. From inode(7):

    POSIX refers to the stat.st_mode bits corresponding to the mask S_IFMT (see below) as the file type, the 12 bits corresponding to the mask 07777 as the file mode bits and the least significant 9 bits (0777) as the file permission bits.