- •Введение
- •Глава 1. Фундаментальные концепции unix Систем
- •Программы, процессы и потоки
- •Сигналы
- •Идентификаторы процессов, группы процессов и сеансы
- •Система прав
- •Другие атрибуты процесса
- •Межпроцессное взаимодействие
- •Использование системных вызовов
- •Краткие описания функций и обработка ошибок
- •Контрольные вопросы
- •Литература
- •Глава 2. Базовые операции ввода-вывода
- •Файловые операции ввода - вывода
- •Стандартные дескрипторы
- •Системные вызовы open и creat
- •Системный вызов umask
- •Системный вызов unlink
- •Текущая позиция в файле
- •Системный вызов write
- •2.8. Системный вызов read
- •2.9. Системный вызов close
- •2.10. Системный вызов lseek
- •2.11. Системные вызовы pread и pwrite
- •2.12. Системные вызовы truncate и ftruncate
- •Контрольные вопросы
- •Литература
- •Глава 3. Дополнительные операции файлового ввода_вывода
- •Низкоуровневый доступ к файловой системе
- •Жесткие и символические ссылки
- •Системный вызов getcwd
- •Отображение метаданных файла
- •Системные вызовы getpwuid, getgrgid и getlogin
- •Каталоги
- •Системные вызовы chdir и fchdir
- •Системные вызовы mkdir и rmdir
- •Контрольные вопросы
- •Литература
- •Глава 4. Процессы и потоки
- •4.1. Среда окружения
- •Системный вызов exec
- •Системный вызов fork
- •Завершение процесса и системные вызовы exit
- •Системные вызовы wait, waitpid и waitid
- •Получение и изменение идентификаторов пользователя и группы
- •Получение и изменение приоритета
- •Контрольные вопросы
- •Литература
- •Глава 5. Механизмы межпроцессного взаимодействия
- •5.1. Каналы
- •5.2. Системные вызовы dup и dup2
- •5.3. Двунаправленное взаимодействие с использованием однонаправленных каналов
- •Контрольные вопросы
- •Литература
- •Глава 6.Механизмы взаимодействия процессов
- •Именованные каналы (fifo)
- •Системные вызовы для работы с очередями сообщений posix
- •Семафоры
- •Системные вызовы для работы с общей памятью posix
- •Контрольные вопросы
- •Литература
- •Глава 7.Сетевое взаимодействие и сокеты
- •Основные системные вызовы для работы с сокетами, образующими логические соединения
- •Обслуживание нескольких клиентов
- •Адресация сокетов
- •In_port_t sin_port; /* номер порта (uint16_t) */
- •In_addr_t s_addr; /* адрес iPv4 (uint32_t) */
- •Домен адресов af_inet6
- •In_port_t sin6_port; /* номер порта (uint16_t) */
- •Доменная система именования
- •Параметры сокетов
- •Контрольные вопросы
- •Литература
- •Глава 8.Сигналы и таймеры
- •Введение в сигналы
- •Жизненный цикл сигналов
- •Типы сигналов
- •Системный вызов sigaction
- •Контрольные вопросы
- •Литература
- •Заключение
- •Список литературы
- •Глава 2. Базовые операции ввода-вывода 14
- •Глава 3. Дополнительные операции файлового ввода_вывода 25
- •Глава 6. Механизмы взаимодействия процессов 58
Системный вызов umask
Наложение маски выполняет системный вызов umask. Данный вызов устанавливает и возвращает маску прав доступа для вновь создаваемых файлов.
#include <sys/stat.h>
mode_t umask(
mode_t cmask /* новая маска*/
);
/* Возвращает предыдущее значение маски (возврат кодов ошибок не предусмотрен) */
Так как каждый процесс имеет маску и любая комбинация из 9 бит считается допустимой, umask не предусматривает выход по ошибке. Он всегда возвращает прежнее значение маски. Чтобы узнать текущее значение маски не изменяя ее, нужно выполнить два последовательных вызова umask. Первый – чтобы получить текущее значение маски, второй – чтобы восстановить ее в первоначальное состояние.
Системный вызов unlink
Системный вызов unlink удаляет из каталога ссылку на файл и уменьшает на 1 счетчик ссылок в индексном узле.
Unlink – удаляет запись в каталоге.
#include <unistd.h>
int unlink(
const char *path /* полное имя файла*/
);
/* Возвращает 0 в случае успеха, -1 в случае ошибки (код ошибки - в переменной errno) */
Если счетчик ссылок стал равен 0, файловая система удалит файл, после этого дисковое пространство и сам индексный узел станут доступными для повторного использования. Процесс должен иметь право на запись в каталог, из которого удаляется ссылка.
С помощью этого вызова можно удалить ссылку на файл любого типа, включая обычные файлы, сокеты, именованные каналы, специальные файлы и т.д. Но удалить ссылку на каталог может только суперпользователь. В любом случае, для удаления ссылки на каталог следует использовать системный вызов rmdir, а не unlink.
Если счетчик ссылок в индексном узле достиг значения 0, но в системе есть процессы, которые держат файл открытым, файловая система откладывает момент освобождения дискового пространства до тех пор, пока последний процесс не закроет удаляемый файл, чтобы избежать обрушения работающих процессов. Эта особенность часто используется при работе с временными файлами.
Текущая позиция в файле
Текущая позиция в файле – это характеристика обычного файла, которая определяет место, куда будет производиться запись или откуда будет выполняться чтение вызовами write/read. Другие типы файлов - каталоги, сокеты, именованные каналы и символические ссылки - не имеют этой характеристики. Специальные файлы могут иметь, а могут не иметь маркер позиции в файле, в зависимости от реализации.
Когда открывается файл, вы получаете независимую текущую позицию, потому что при этом создается новая запись в системной таблице файлов. В следующем примере:
int fd1, fd2, fd3;
fd1 = open(“myfile”, O_WRONLY | O_CREAT | O_TRUNC, PERM_FILE);
fd2 = open(“myfile”, O_RDONLY );
fd3 = open(“yourfile”, O_RDWR | O_CREAT | O_TRUNC, PERM_FILE);
дескрипторам fd1 и fd2 соответствуют их собственные текущие позиции в файле, что позволяет писать в fd1 и читать из fd2 независимо друг от друга. Несколько иначе обстоит дело с fd3, в этом случае операции чтения и записи будут работать с одной и той же текущей позицией в файле. Если файл был открыт без флага O_APPEND, то первоначально текущая позиция в файле получает значение 0. Затем она автоматически передвигается вызовами read и write на число байт, которое было прочитано или записано. Таким образом, если текущая позиция в файле не меняется умышленно, то чтение и.или запись выполняются последовательно. Вы считываете порцию данных из файла, затем считываете очередную порцию и так далее. То же самое относится и к операции записи. Допустим, текущая позиция в файле равна 0. Если записать 100 байт в fd1, а затем прочитать 100 байт из fd2, то получим те же самые 100 байт, которые только что записали. Но если выполнять операции записи/чтения над fd3, то мы прочитаем данные, которые находятся в файле сразу же после тех, что были записаны, и/или признак конца файла, если дальше в файле ничего нет. Это происходит потому, что каждая запись в таблице файлов определяет единственную текущую позицию, которая используется обоими вызовами read и write. Переустановка текущей позиции может быть выполнена с помощью системного вызова lseek. Новое значение текущей позиции окажет влияние на первый вызов read или write.
Если файл открыт с флагом O_APPEND, то при записи, вызову write будет предшествовать неявный и атомарный вызов lseek, переустанавливающий текущую позицию в конец, благодаря этому запись всегда будет производиться в конец файла. Даже если в этот файл одновременно будут писать несколько процессов, они не будут затирать данные друг друга. Подобного эффекта не удастся достичь с помощью последовательности вызовов lseek и write (если файл открыт без флага O_APPEND), потому что между двумя системными вызовами существует некоторый промежуток времени, в результате может получиться следующее:
процесс А перемещает текущую позицию в конец файла (пусть это будет число 1000);
процесс В перемещает текущую позицию в конец файла (пусть это будет число 1000);
процесс В записывает 200 байт, начиная с позиции 1000;
процесс А записывает 200 байт, начиная с позиции 1000 и благополучно затирает данные, записанные процессом В.
Можно было бы использовать механизм блокировок для решения этой проблемы, но имеется лучшее решение: если процессы А и В откроют файл с флагом O_APPEND, то это гарантирует следующую последовательность действий:
процесс А переустанавливает текущую позицию в конец файла (число 1000) и записывает 200 байт;
процесс В переустанавливает текущую позицию в конец файла (число 1200) и записывает свои данные.
Таким образом, флаг O_APPEND прекрасно подходит для ведения файлов журналов и в других ситуациях, когда необходимо собирать в файл данные, поступающие от нескольких процессов.