Как команды типа ls или stat различают тип файла?

Как команды типа ls или stat различают тип файла, является ли объект файлом или каталогом?

Например, я создал эти два объекта, учитывая тот факт, что каталог также является файлом … с некоторыми специальными правилами, я хочу знать, как в выводе команды stat они помечены как «каталог» и «обычный пустой файл".

 $ mkdir testdir;touch testfile $ stat testdir | head -2;stat testfile | head -2 File: `testdir' Size: 4096 Blocks: 8 IO Block: 4096 directory File: `testfile' Size: 0 Blocks: 0 IO Block: 4096 regular empty file 

Позже я сделал strace при выполнении stat каталога testdir и файла testfile соответственно. На выходе трассировки я заметил эти

 lstat("testdir/", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0 

а также

 lstat("testfile", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0 

Кто-то, пожалуйста, скажите мне, как st_mode получает эти значения S_IFDIR и S_IFREG .

Я могу казаться смущенным; Я действительно являюсь.

Давайте попробуем вас не путать. В inode есть 16-битное поле, возвращаемое stat / lstat (и 64-разрядные варианты) в st_mode. Из этих 9 бит используются для разрешений rwxrwxrwx, еще 3 для sticky bit , sticky bit set group id (sgid) bit и set userid (suid) bit set group id (sgid) bit set userid (suid) bit . Остальные 4 бита используются для кодирования некоторой информации о типе. Это может означать, что это обычный файл, каталог, блок или символьное устройство, именованный канал и т. Д. И т. Д.

Поэтому, если вы создаете каталог, то эти 4 бита говорят, что это каталог. Вы можете увидеть это в выводе strace …

 lstat("testdir/", {st_mode=S_IFDIR|0775, st_size=4096, ...}) ^^^^^^^ 4 bits showing the type is directory ^ 3 bits (this is octal) for suid/sgid/sticky ^^^ rwxrwxrwx info. 

Команды ls , stat или even используют внутренний системный вызов C stat() для сбора деталей. Здесь определены структуры. Если вы проверяете файлы stat:

  • /usr/include/bits/stat.h
  • /usr/include/linux/stat.h

Определены следующие биты:

 /* Encoding of the file mode. */ #define __S_IFMT 0170000 /* These bits determine file type. */ /* File types. */ #define __S_IFDIR 0040000 /* Directory. */ #define __S_IFCHR 0020000 /* Character device. */ #define __S_IFBLK 0060000 /* Block device. */ #define __S_IFREG 0100000 /* Regular file. */ #define __S_IFIFO 0010000 /* FIFO. */ #define __S_IFLNK 0120000 /* Symbolic link. */ #define __S_IFSOCK 0140000 /* Socket. */ the stat function will check the POSIX macros and compare to see if it is a regular file/ directory #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) 

Вот как st_mode получает эти значения S_IFDIR и S_IFREG .

Просто FYI … Теперь к одному основному вопросу о том, как inodes определяют тип файла:

Для файловой системы XFS структура данных inode разделена на 3 части:

  • di_core (96 байт)
  • di_u данных di_u
  • di_a расширенный атрибут fork

Ядро содержит то, что представляет индекс inode, данные статистики и информация, описывающая данные и вилки атрибутов. Здесь тип файла управляется di_core.di_mode (например, обычный файл, каталог, ссылка и т. Д.).

di_u «data fork» содержит нормальные данные, относящиеся к inode.

di_a "атрибут fork" содержит расширенные атрибуты.