Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учеб.пос.СП.doc
Скачиваний:
28
Добавлен:
31.03.2015
Размер:
1.33 Mб
Скачать
    1. Системный вызов umask

Наложение маски выполняет системный вызов umask. Данный вызов устанавливает и возвращает маску прав доступа для вновь создаваемых файлов.

#include <sys/stat.h>

mode_t umask(

mode_t cmask /* новая маска*/

);

/* Возвращает предыдущее значение маски (возврат кодов ошибок не предусмотрен) */

Так как каждый процесс имеет маску и любая комбинация из 9 бит считается допустимой, umask не предусматривает выход по ошибке. Он всегда возвращает прежнее значение маски. Чтобы узнать текущее значение маски не изменяя ее, нужно выполнить два последовательных вызова umask. Первый – чтобы получить текущее значение маски, второй – чтобы восстановить ее в первоначальное состояние.

    1. Системный вызов unlink

Системный вызов unlink удаляет из каталога ссылку на файл и уменьшает на 1 счетчик ссылок в индексном узле.

Unlink – удаляет запись в каталоге.

#include <unistd.h>

int unlink(

const char *path /* полное имя файла*/

);

/* Возвращает 0 в случае успеха, -1 в случае ошибки (код ошибки - в переменной errno) */

Если счетчик ссылок стал равен 0, файловая система удалит файл, после этого дисковое пространство и сам индексный узел станут доступными для повторного использования. Процесс должен иметь право на запись в каталог, из которого удаляется ссылка.

С помощью этого вызова можно удалить ссылку на файл любого типа, включая обычные файлы, сокеты, именованные каналы, специальные файлы и т.д. Но удалить ссылку на каталог может только суперпользователь. В любом случае, для удаления ссылки на каталог следует использовать системный вызов rmdir, а не unlink.

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

    1. Текущая позиция в файле

Текущая позиция в файле – это характеристика обычного файла, которая определяет место, куда будет производиться запись или откуда будет выполняться чтение вызовами 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 прекрасно подходит для ведения файлов журналов и в других ситуациях, когда необходимо собирать в файл данные, поступающие от нескольких процессов.