Выбрать главу

$ ./large_file x 10111222333

$ ls — l x Проверка размера получившегося в результате файла

— rw- 1 mtk users 10111222337 Mar 4 13:34 x

Листинг 5.3. Обращение к большим файлам

fileio/large_file.c

#define _LARGEFILE64_SOURCE

#include <sys/stat.h>

#include <fcntl.h>

#include "tlpi_hdr.h"

int

main(int argc, char *argv[])

{

int fd;

off64_t off;

if (argc!= 3 || strcmp(argv[1], "-help") == 0)

usageErr("%s pathname offset\n", argv[0]);

fd = open64(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

if (fd == -1)

errExit("open64");

off = atoll(argv[2]);

if (lseek64(fd, off, SEEK_SET) == -1)

errExit("lseek64");

if (write(fd, "test", 4) == -1)

errExit("write");

exit(EXIT_SUCCESS);

}

fileio/large_file.c

Макрос _FILE_OFFSET_BITS

Для получения функциональных возможностей LFS рекомендуется определить макрос _FILE_OFFSET_BITS со значением 64 при компиляции программы. Один из способов предусматривает использование ключа командной строки при запуске компилятора языка C:

$ cc — D_FILE_OFFSET_BITS=64 prog.c

Альтернативой может послужить определение этого макроса в исходном файле на языке C перед включением любых заголовочных файлов:

#define _FILE_OFFSET_BITS 64

Это определение автоматически переводит использование всех соответствующих 32-разрядных функций и типов данных на применение их 64-разрядных двойников. Так, например, вызов open() фактически превращается в вызов open64(), а тип данных off_t определяется в виде 64-разрядного длинного целого числа. Иными словами, мы можем перекомпилировать существующую программу для работы с большими файлами, не внося при этом никаких изменений в исходный код.

Добавление макроса проверки возможностей _FILE_OFFSET_BITS явно проще применения переходного API LFS, но этот подход зависит от чистоты написания приложений (например, от правильного использования off_t для объявления переменных, хранящих файловые смещения, вместо применения свойственного языку C целочисленного типа).

Наличие макроса _FILE_OFFSET_BITS в LFS-спецификации не требуется, он лишь упоминается в ней как дополнительный метод указания размера типа данных off_t. Для получения этих же функциональных возможностей в некоторых реализациях UNIX используются другие макросы проверки возможностей.

При попытке обращения к большому файлу с использованием 32-разрядных функций (то есть из программы, скомпилированной без установки для _FILE_OFFSET_BITS значения 64) можно столкнуться с ошибкой EOVERFLOW. Например, она может быть выдана при попытке использовать 32-разрядную версию функции stat() (см. раздел 15.1) для извлечения информации о файле, размер которого превышает 2 Гбайт.

Передача значений off_t вызовам printf()

Надо отметить, что LFS-расширения не решают для нас одну проблему: как выбрать способ передачи значений off_t вызовам printf(). В подразделе 3.6.2 было отмечено, что портируемый метод, который выводит значения одного из предопределенных типов системных данных (например, pid_t или uid_t), заключается в приведении значения к типу long и использовании для printf() спецификатора %ld. Но если применяются LFS-расширения, для типа данных off_t этого зачастую недостаточно, поскольку он может быть определен как тип, который длиннее long, обычно как long long. Поэтому для вывода значения типа off_t оно приводится к long long, а для printf() задается спецификатор %lld:

#define _FILE_OFFSET_BITS 64

off_t offset; /* Должен быть 64 бита, а это размер 'long long' */

/* Некоторый код, присваивающий значение 'offset' */

printf("offset=%lld\n", (long long) offset);

Подобные замечания применимы и к родственному типу данных blkcnt_t, используемому в структуре stat (рассматриваемой в разделе 15.1).

Если аргументы функции, имеющие тип off_t или stat, передаются между отдельно откомпилированными модулями, необходимо обеспечить использование в обоих модулях одинаковых размеров для этих типов (то есть оба должны быть скомпилированы либо с установкой для _FILE_OFFSET_BITS значения 64, либо без этих установок).

5.11. Каталог /dev/fd

Каждому процессу ядро предоставляет специальный виртуальный каталог /dev/fd. Он содержит имена файлов вида /dev/fd/n, где n является номером, соответствующим одному из дескрипторов файла, открытого для этого процесса. К примеру, /dev/fd/0 является для процесса стандартным вводом. (Свойство каталога /dev/fd в SUSv3 не указано, но некоторые другие реализации UNIX его предоставляют.)

В некоторых системах (но не в Linux) открытие одного из файлов в каталоге /dev/fd эквивалентно дублированию соответствующего файлового дескриптора. Таким образом, следующие инструкции эквивалентны друг другу: