• struct stat64: аналог структуры stat (см. раздел 15.1), позволяющий работать с большими файлами;

• off64_t: 64-разрядный тип для представления файловых смещений.

Как показано в листинге 5.3, тип данных off64_t используется (кроме всего прочего) с функцией lseek64(). Демонстрируемая там программа получает два аргумента командной строки: имя открываемого файла и целочисленное значение, указывающее файловое смещение. Программа открывает указанный файл, переходит по заданному файловому смещению, а затем записывает строку. В следующей сессии командной оболочки показано использование программы для перехода в файле по очень большому файловому смещению (больше 10 Гбайт) с дальнейшей записью нескольких байтов:

$ ./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

#include

#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
Перейти на страницу:

Похожие книги