1

I see ? as the first letter of stat.filemode() result. But I don't remember that I have seen ? as the first letter in a normal linux system.

https://en.wikipedia.org/wiki/Chmod

What ? stands for? How to get - as the first letter? Thanks.

#!/usr/bin/env bash

printMode() {
  local mode; mode=$1; shift
  printf '%s\t' "$@"
  python3 -c 'import stat, sys; print(stat.filemode(int(sys.argv[1])))' "$mode"
}

printMode 0 0
for ((i=1;i<16;++i)); do
    printMode "$((2**(i-1)))" "$i"
done

for ((i=0;i<=2;++i)); do
    printMode "$((2**(i*3) + 2**(9+i)))" "$((i*3+1))" "$((10+i))"
done
0   ?---------
1   ?--------x
2   ?-------w-
3   ?------r--
4   ?-----x---
5   ?----w----
6   ?---r-----
7   ?--x------
8   ?-w-------
9   ?r--------
10  ?--------T
11  ?-----S---
12  ?--S------
13  p---------
14  c---------
15  d---------
1   10  ?--------t
4   11  ?-----s---
7   12  ?--s------
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
user1424739
  • 11,937
  • 17
  • 63
  • 152
  • 2
    `stat.mode()` is intended to process a mode returned by `os.stat()`. Giving it random numbers that don't correspond to actual modes produces strange behavior. – Barmar Aug 30 '19 at 23:13
  • Which OS is this where `2**15` returns `d`? `stat` bit meaning is per-OS-vendor, so there's no globally canonical rule. (This is why folks are always supposed to use the macros rather than trying to hardcode bitmask values themselves, and thus why Python provides wrappers for those C macros). – Charles Duffy Sep 02 '19 at 17:44

2 Answers2

2

This is defined in cpython/Modules/_stat.c. To quote a shortened segment thereof:

static char
filetype(mode_t mode)
{
    /* common cases first */
    if (S_ISREG(mode))  return '-';
    // ...lots of other cases here, for directories, symlinks, sockets, etc... //
    return '?';
}

If you don't set the bit for S_ISREG (a regular file) or any other type of filesystem object, the test falls through to the default of ?.

See discussion of What is S_ISREG(), and what does it do?.


On Linux, the relevant bit is 2**15:

$ printMode "$((2**15))"
        ----------

...but to get a list of candidate bits for your current OS, you should call os.stat().

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
2

You don't see that in normal usage because actual file modes are not such low numbers. The file mode includes additional bits other than the permissions, to indicate the type of file, such as block special file, character special file, directory, named pipe, regular file, symbolic link, or socket.

When the bit for a regular file is set, the first character is -; if the bit for a directory is set, it's d.

The numbers you're using have none of those bits set, so stat.filemode() doesn't know what the type is, and returns ?. You should never see this in a directory listing unless the filesystem is corrupted.

Barmar
  • 741,623
  • 53
  • 500
  • 612