• 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
Для получения функциональных возможностей 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 Гбайт.
Надо отметить, что 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, либо без этих установок).