В чем разница между stat и lstat в системных вызовах Linux при работе с символическими ссылками?
В Linux системные вызовы `stat` и `lstat` используются для получения метаданных о файлах, но их поведение принципиально различается при работе с символическими ссылками (symlinks).
## Системный вызов stat
Функция `stat(const char *pathname, struct stat *statbuf)` следует по символической ссылке и возвращает информацию о **целевом файле**, на который ссылка указывает. То есть если `/tmp/link` — это симлинк на `/etc/hosts`, то `stat(«/tmp/link», &buf)` вернёт метаданные файла `/etc/hosts`: его размер, права доступа, время изменения и т.д.
Если целевой файл не существует (битая ссылка), `stat` вернёт ошибку `ENOENT`.
## Системный вызов lstat
Функция `lstat(const char *pathname, struct stat *statbuf)` **не следует** по символической ссылке. Она возвращает информацию о **самой ссылке**, а не о файле, на который она указывает. Для симлинка `/tmp/link` вы получите размер самой ссылки (обычно это длина строки пути назначения), тип файла `S_IFLNK` и другие атрибуты именно ссылки.
## Практический пример на C
c
#include
#include
int main() {
struct stat st1, st2;
const char *path = «/tmp/mylink»; // симлинк на /etc/hosts
stat(path, &st1); // информация о /etc/hosts
lstat(path, &st2); // информация о самом симлинке
printf(«stat size: %ldn», st1.st_size); // размер /etc/hosts
printf(«lstat size: %ldn», st2.st_size); // длина пути назначения
return 0;
}
## Когда использовать каждый вызов
— **stat** — когда вам нужна информация о конечном файле, независимо от того, как к нему обращаются (напрямую или через ссылку). Используется в большинстве утилит, которые прозрачно работают с симлинками.
— **lstat** — когда нужно явно обнаружить символическую ссылку и получить её собственные метаданные. Используется в утилитах типа `ls -l`, `find`, архиваторах и файловых менеджерах, которые должны различать ссылки и обычные файлы.
## Проверка типа файла
С помощью макроса `S_ISLNK(st.st_mode)` можно проверить, является ли файл символической ссылкой — но только если вы использовали `lstat`. Вызов `stat` никогда не вернёт `S_IFLNK` в поле `st_mode`, так как он всегда разыменовывает ссылку.
## Третий родственный вызов: fstat
Существует также `fstat(int fd, struct stat *statbuf)`, который принимает файловый дескриптор вместо пути. Поскольку дескриптор уже открыт (и ссылка уже разыменована при открытии), `fstat` по поведению аналогичен `stat`.
## Итог
| Вызов | Следует по симлинку | Объект информации |
|——-|———————|——————|
| stat | Да | Целевой файл |
| lstat | Нет | Сама ссылка |
| fstat | — | Открытый файл |
Выбор между `stat` и `lstat` критичен для корректной обработки файловой системы, особенно при написании утилит резервного копирования, файловых менеджеров и инструментов обхода директорий.
