Linux программирование в примерах
Флаг
предназначен для чтения данных: еслиO_RSYNCнаходит данные в буферном кэше, которые были назначены для записи на диск, функция не вернет эти данные до тех пор, пока они не будут записаны. Два других флага влияют на это: в частности,read()заставитO_SYNCждать, пока не будут также записаны и вспомогательные данные.read()ЗАМЕЧАНИЕ. Что касается ядра версии 2.4, Linux рассматривает все три флага одинаково со значением флага
. Более того, Linux определяет дополнительные флаги, которые специфичны для Linux и предназначены для специального использования. Дополнительные подробности см. в справочной странице GNU/Linux для open(2).O_SYNC4.7. Форсирование записи данных на диск
Ранее мы описали флаги
,O_DSYNCиO_RSYNCдляO_SYNC. Мы отметили, что использование этих флагов может замедлить программу, посколькуopen()не возвращается до тех пор, пока все данные не будут записаны на физический носитель.write()Со слегка более высоким уровнем риска мы можем сами испечь свое пирожное и съесть его. Это осуществляется путем открытия файла без указания флагов
, но с последующим использованием одного из следующих двух системных вызовов в любой момент, когда это необходимо для безопасного перемещения данных на физический носитель:O_<i>x</i>SYNC#include <unistd.h>int fsync(int fd); /* POSIX FSC */int fdatasync(int fd); /* POSIX SIO */Системный вызов
подобенfdatasync(): он форсирует запись данных на конечное физическое устройство. Системный вызовO_DSYNCподобенfsync(), форсируя запись на физическое устройство не только данных файла, но и вспомогательных данных. ВызовO_SYNCболее переносим; он существовал в мире Unix в течение более продолжительного времени, и вероятность его наличия среди широкого ряда систем больше.fsync()Можно использовать эти вызовы с указателями файлов
, вызвав сначала<stdio.h>, а затемfflush()для получения дескриптора нижележащего файла. Вот функцияfileno(), которая может использоваться для заключения обеих операций в один вызов. Она возвращает в случае успеха 0:fpsync()/* fpsync --- синхронизация переменной stdio FILE* */int fpsync(FILE *fp) {if (fp == NULL || fflush(fp) == EOF || fsync(fileno(fp)) < 0)return -1;return 0;}Технически оба этих вызова являются расширениями базового стандарта POSIX:
в расширении «Синхронизация файлов» (FSC), afsync()в расширении «Синхронизированный ввод и вывод». Тем не менее, можно без проблем использовать их в системе GNU/Linuxfdatasync()4.8. Установка длины файла
Два системных вызова позволяют настраивать размер файла:
#include <unistd.h>#include <sys/types.h>int truncate(const char *path, off_t length); /* XSI */int ftruncate(int fd, off_t length); /* POSIX */Как должно быть очевидно из параметров,
принимает аргумент имени файла, тогда какtruncate()работает с дескриптором открытого файла. (Обычным является соглашение по именованию пар системных вызововftruncate()и<i>xxx()</i>, работающих с именами файлов и дескрипторами файлов. Мы увидим несколько примеров в данной и последующих главах.) В обоих случаях аргумент<i>fxxxx()</i>является новым размером файла.lengthЭтот системный вызов происходит от 4.2 BSD Unix, и на ранних системах мог использоваться лишь для сокращения длины файла, отсюда и название. (Он был создан, чтобы облегчить реализацию операции урезания в Фортране.) На современных системах, включая Linux, имя является неправильным, поскольку с помощью этих вызовов можно также увеличить, а не только сократить длину файла. (Однако, POSIX указывает, что возможность увеличения размера файла относится к расширению XSI.)
Для этих вызовов сокращаемый файл должен иметь разрешение на запись (для
), или должен быть открыт для записи (дляtruncate()). Если файл сокращается, все данные после нового конца файла теряются. (Поэтому вы не можете сократить файл, снова удлинить его и найти там первоначальные данные.) Если файл-расширен, как в случае записи данных послеftruncate(), данные между старым концом файла и новым концом файла читаются как нули.lseek()Эти вызовы сильно отличаются от '
', который полностью урезает файл, отбрасывая все его данные. Эти же вызовы просто устанавливают абсолютную длину файла в данное значение.open(file, ... | O_TRUNC, mode)Эти функции довольно специализированы; они используются лишь четыре раза во всем коде GNU Coreutils. Мы представляем пример использования
в разделе 5.5.3 «Изменение отметок времени:ftruncate()».utime()4.9. Резюме
• Когда системный вызов завершается неудачей, он обычно возвращает -1, а в глобальной переменной errno устанавливается предопределенное значение, указывающее на проблему. Для сообщений об ошибках могут использоваться функции
иperror().strerror()• Доступ к файлам осуществляется через небольшие целые, которые называются дескрипторами. Дескрипторы файлов для стандартного ввода, стандартного вывода и стандартной ошибки наследуются от родительского процесса программы. Другие получаются через
илиopen(). Для их закрытия используетсяcreat(), aclose()возвращает разрешенное максимальное число открытых файлов. Значениеgetdtablesize()(устанавливаемое с помощьюumask) влияет на права доступа, получаемые новыми файлами при создании с помощьюumask()или с флагомcreat()дляO_CREAT.open()