Чтение онлайн

на главную - закладки

Жанры

Linux программирование в примерах
Шрифт:

50 fstat(fileno(fi), &statb);

51 if (statb.st_dev == dev && statb.st_ino == ino) {

52 fprintf(stderr, "cat: input %s is output\n",

53 ffig ? "-" : *argv);

54 fclose(fi);

55 continue;

56 }

Если значения

st_dev
и
st_ino
входного файла совпадают с соответствующими значениями выходного файла,
cat
выдает сообщение и продолжает со следующего файла, указанного в командной строке.

Проверка сделана безусловно, хотя

dev
и
ino
устанавливаются, лишь если вывод не является файлом устройства. Это срабатывает нормально из-за того, как эти переменные объявлены:

int dev, ino = -1;

Поскольку

ino
инициализирован значением (-1), ни один действительный номер индекса не будет ему соответствовать [60] . То, что
dev
не инициализирован так, является небрежным, но не представляет проблемы, поскольку тест в строке 51 требует, чтобы были равными значения как устройства, так и индекса. (Хороший компилятор выдаст предупреждение, что
dev
используется без инициализации: '
gcc -Wall
' сделает это.)

60

Это утверждение было верно для V7, на современных системах больше нет таких гарантий — Примеч. автора.

Обратите также внимание, что ни один вызов

fstat
не проверяется на ошибки. Это также небрежность, хотя не такая большая, маловероятно, что
fstat
завершится неудачей с действительным дескриптором файла

Проверка того, что входной файл не равен выходному файлу, осуществляется лишь для файлов, не являющихся устройствами. Это дает возможность использовать

cat
для копирования ввода из файлов устройств в самих себя, как в случае с терминалами:

$ tty /* Вывести имя устройства текущего терминала */

/dev/pts/3

$ cat /dev/pts/3 > /dev/pts/3 /* Копировать ввод от клавиатуры на экран */

this is a line of text /* Набираемое в строке */

this is a line of text /* cat это повторяет */

5.4.5. Работа с символическими ссылками

В общем, символические ссылки ведут себя подобно прямым ссылкам; файловые операции, такие, как

open
и
stat
, применяются к указываемому файлу вместо самой символической ссылки. Однако, бывают моменты, когда в самом деле необходимо работать с символической ссылкой вместо файла, на которую она указывает.

По этой причине существует системный вызов

lstat
. Он действует точно также, как
stat
, но если проверяемый файл окажется символической ссылкой, возвращаемые сведения относятся к символической ссылке, а не к указываемому файлу. А именно:

• 

S_ISLNK(sbuf.st_mode)
будет
true
.

• 

sbuf.st_size
содержит число байтов в имени указываемого файла.

Мы уже видели, что системный вызов

symlink
создает символическую ссылку. Но если дана существующая символическая ссылка, как можно получить имя файла, на которую она указывает? (Очевидно,
ls
может получить это имя; поэтому мы должны быть способны это сделать.)

Открывание ссылки с помощью

open
для чтения ее с использованием
read
не будет работать,
open
следует по ссылке на указываемый файл. Таким образом, символические ссылки сделали необходимым дополнительный системный вызов, который называется
readlink
:

#include <unistd.h> /* POSIX */

int readlink(const char *path, char *buf, size_t bufsiz);

readlink
помещает содержимое символической ссылки, на имя которой указывает
path
, в буфер, на который указывает
buf
. Копируется не более
bufsiz
символов. Возвращаемое значение равно числу символов, помещенных в
buf
, либо -1, если возникла ошибка,
readlink
не вставляет завершающий нулевой байт.

Обратите внимание, что если буфер, переданный

readlink
, слишком маленький, информация будет потеряна; полное имя указываемого файла будет недоступно. Чтобы использовать
readlink
должным образом, вы должны делать следующее:

1. Используйте

lstat
, чтобы убедиться, что это символическая ссылка.

2. Убедитесь, что ваш буфер для содержимого символической ссылки составляет по крайней мере '

sbuf.st_size + 1
' байтов; '
+ 1
' нужно для завершающего нулевого байта, чтобы сделать буфер годной к употреблению строкой С.

3. Вызовите

readlink
. Не мешает проверить, что возвращенное значение равно
sbuf.st_size
.

4. Добавьте '

\0
' к байту после содержимого ссылки, чтобы превратить его в строку С. Код для всего этого мог бы выглядеть примерно так:

/* Проверка ошибок для краткости опущена */

int count;

char linkfile[PATH_MAX], realfile[PATH_MAX]; /* PATH_MAX в <limits.h> */

strut stat sbuf;

/* ...поместить в linkfile путь к нужной символической ссылке... */

lstat(linkfile, &sbuf); /* Получить сведения от stat */

if (!S_ISLNK(sbuf.st_mode)) /* Проверить, что это ссылка */

 /* не символическая ссылка, обработать это */

if (sbuf.st_size + 1 > PATH_МАХ) /* Проверить размер буфера */

 /* обработать проблемы с размером буфера */

count = readlink(linkfile, realfile, PATH_MAX);

/* Прочесть ссылку */

if (count != sbuf.st_size)

 /* происходит что-то странное, обработать это */

realfile(count) = '\0'; /* Составить строку С */

Данный пример для простоты представления использует буферы фиксированного размера. Реальный код мог бы использовать для выделения буфера нужного размера

malloc
, поскольку массивы фиксированного размера могли бы оказаться слишком маленькими. Файл
lib/xreadlink.c
в GNU Coreutils делает именно это. Он читает содержимое символической ссылки в память, выделенную
malloc
. Мы покажем здесь саму функцию, большая часть файла представляет собой стереотипные определения. Номера строк относятся к началу файла:

Поделиться:
Популярные книги

Двойник короля 19

Скабер Артемий
19. Двойник Короля
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Двойник короля 19

Барон устанавливает правила

Ренгач Евгений
6. Закон сильного
Старинная литература:
прочая старинная литература
5.00
рейтинг книги
Барон устанавливает правила

Черный Маг Императора 15

Герда Александр
15. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
сказочная фантастика
фэнтези
фантастика: прочее
5.00
рейтинг книги
Черный Маг Императора 15

Телохранитель Генсека. Том 4

Алмазный Петр
4. Медведев
Фантастика:
попаданцы
альтернативная история
6.00
рейтинг книги
Телохранитель Генсека. Том 4

Темные тропы и светлые дела

Владимиров Денис
3. Глэрд
Фантастика:
фэнтези
боевая фантастика
попаданцы
5.00
рейтинг книги
Темные тропы и светлые дела

Горячий старт. Часть 3

Глазачев Георгий
3. Бесконечная Империя Вечности
Фантастика:
фэнтези
рпг
попаданцы
5.00
рейтинг книги
Горячий старт. Часть 3

Газлайтер. Том 18

Володин Григорий Григорьевич
18. История Телепата
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Газлайтер. Том 18

Кодекс Охотника. Книга XXXIX

Сапфир Олег
39. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
боевая фантастика
5.00
рейтинг книги
Кодекс Охотника. Книга XXXIX

Черный Маг Императора 4

Герда Александр
4. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 4

Неудержимый. Книга XXXVII

Боярский Андрей
37. Неудержимый
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Неудержимый. Книга XXXVII

Бастард

Осадчук Алексей Витальевич
1. Последняя жизнь
Фантастика:
фэнтези
героическая фантастика
попаданцы
5.86
рейтинг книги
Бастард

Призыватель нулевого ранга. Том 2

Дубов Дмитрий
2. Эпоха Гардара
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Призыватель нулевого ранга. Том 2

Двойник Короля 4

Скабер Артемий
4. Двойник Короля
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Двойник Короля 4

Виконт. Книга 4. Колонист

Юллем Евгений
Псевдоним `Испанец`
Фантастика:
фэнтези
попаданцы
аниме
7.50
рейтинг книги
Виконт. Книга 4. Колонист