В случае прерывания по сигналу величина оставшегося
промежутка времени заносится обратно в переменную tv. */
int rval = nanosleep(&tv, &tv);
if (rval == 0)
/* пауза успешно окончена. */
return 0;
else if (errno == EINTR)
/* Прерывание по сигналу. Повторная попытка. */
continue;
else
/* Какая-то другая ошибка. */
return rval;
}
return 0;
}
8.11. Функция readlink(): чтение символических ссылок
Функция readlink() определяет адресата символической ссылки. Она принимает три аргумента: путь к символической ссылке, буфер для записи адресата и длина буфера. Как ни странно, путевое имя, помещаемое в буфер, не завершается нулевым символом. Но поскольку в третьем аргументе возвращается длина буфера, добавить этот символ несложно.
Если первый аргумент не является символической ссылкой, функция readlink() возвращает -1, а в переменную errno записывается константа EINVAL.
Программа, представленная в листинге 8.9, показывает адресата символической ссылки, заданной в командной строке.
#include «errno.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
char target_path[256];
char* link_path = argv[1];
/* Попытка чтения адресата символической ссылки. */
int len =
readlink(link_path, target_path, sizeof(target_path));
if (len == -1) {
/* Функция завершилась ошибкой. */
if (errno == EINVAL)
/* Это не символическая ссылка. */
fprintf(stderr, "%s is not a symbolic link\n", link_path);
else
/* Произошла какая-то другая ошибка. */
perror("readlink");
return 1;
} else {
/* Завершаем путевое имя нулевым символом. */
target_path[len] = '\0';
/* Выводим результат. */
printf("%s\n", target_path);
return 0;
}
}
Ниже показано, как создать символическую ссылку и проверить ее с помощью программы print-symlink:
% ln -s /usr/bin/wc my_link
% ./print-symlink my_link
/usr/bin/wc
8.12. Функция sendfile(): быстрая передача данных
Функция sendfile() — это эффективный механизм копирования данных из одного файлового дескриптора в другой. Дескрипторам могут соответствовать дисковые файлы, сокеты или устройства.
Обычно цикл копирования реализуется следующим образом. Программа выделяет буфер фиксированного размера, перемещает в него данные из исходного дескриптора, затем записывает содержимое буфера во второй дескриптор и повторяет описанную процедуру до тех пор, пока не будут скопированы все данные. Такая схема неэффективна как с точки зрения времени, так и с точки зрения затрат памяти, поскольку выделяется дополнительный буфер и над его содержимым выполняются операции копирования.
Функция sendfile() устраняет потребность в создании промежуточного буфера. Ей передаются дескриптор для записи, дескриптор для чтения, указатель на переменную смещения и число копируемых данных. Переменная смещения определяет позицию входного файла, с которой начинается копирование (0 — это начало файла). После окончания копирования переменная будет содержать смещение конца блока. Функция sendfile() объявлена в файле <sys/sendfile.h>.
Программа, показанная в листинге 8.10, представляет собой простую, но очень эффективную реализацию механизма файлового копирования. Она принимает в командной строке два имени файла и копирует содержимое первого файла во второй. Размер исходного файла определяется с помощью функции fstat().
sendfile()#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
int read_fd;
int write_fd;
struct stat stat_buf;
off_t offset = 0;
/* Открытие входного файла. */
read_fd = open(argv[1], O_RDONLY);
/* Определение размера входного файла. */
fstat(read_fd, &stat_buf);
/* Открытие выходного файла для записи. */