Linux и Large Files
А вот представим, что у меня есть библиотека, собранная с -D_FILE_OFFSET_BITS=64
Все fopen/fseek/fread/fclose там делаются внутри, снаружи только имена файлов прилетают.
А потом я к ней линкую приложение, компилированное без этого флага, просто gcc -c
Вопрос: оно будет работать? Или возможны моментики?
Нет, я не ленивый и конечно попробую, но у меня этих линуксов под рукой штуки две и с новыми ядрами, а что будет со старыми ядрами/glibc/whatever?
P.S. Назначение LARGEFILE_SOURCE/LARGEFILE64_SOURCE так и не понял, вроде бы для позиционирования за 2 гигабайта и чтения мелкими кусками достаточно _FILE_OFFSET_BITS
P.P.S. Единственная система, где вообще не надо париться - FreeBSD :) Какой, оказывается, кусок жизни с этой LFS прошел мимо меня...
Comments
Вся проблема не в линуксе, а в gcc/libc. Не спозиционируешьс
Вся проблема не в линуксе, а в gcc/libc. Не спозиционируешься, и даже append'ом не запишешь файл за 2 гигабайта, если не стоит O_LARGEFILE при открытии. Как поставить этот флаг при открытии файла на с++ через его потоки я так и не понял, простого пути нет, сложный нафиг не нужен. В итоге, открывал обычным open(2), потом через fdopen уже буферезированный вывод. По дефолту O_LARGEFILE не ставится ни с какими флагами сборки.
Тут вот с версиями glibc есть явная чехарда, я ее и хочу про
Тут вот с версиями glibc есть явная чехарда, я ее и хочу прояснить:
У меня в LibRaw используется fopen/fseek/fread/fclose
До недавнего времени я считал, что RAW больше двух гигабайт не бывает и меня все это не парило. Как выяснилось, бывают (с цифровых кинокамер). Имею багрепорт, в двух словах "на Ubuntu работает, на Mac OS X - нет".
Ну и понятно почему на макоси нет - там fseek - 32-битный, fseeko - off_t. Но на Убунте то работает, вероятно в (новых?) glibc сходу все прозрачно.
Но я решил, что уж раз чинить, то чинить все сразу и винды и старый линукс. Про fdopen - интересное замечание, учту.
Я ещё раз подумал. Возможно, что мои воспоминания о проблеме
Я ещё раз подумал. Возможно, что мои воспоминания о проблеме ещё связаны с 32-битностью архитектуры когда мне это было нужно. Может на 64-битной off_t по дефолту 64 бита, и файлы сразу большие, поэтому на убунте работает?
О, про 64 бита - отличный вопрос, я не подумал. Скорее да, з
О, про 64 бита - отличный вопрос, я не подумал. Скорее да, заработало именно поэтому.
У меня в 10-й SuSE хватило только _FILE_OFFSET_BITS=64 и бол
У меня в 10-й SuSE хватило только _FILE_OFFSET_BITS=64 и больше ничего не надо. Т.е.
fopen(..)
fwrite(3 байта)
fseeko(f,5000000000,SEEK_CUR)
fwrite(3 байта)
Честно образует файл (с дыркой) на 5000000006 байт.
Ядро 2.6.18, glibc 2.5
При этом fopen честно переопределено в fopen64, наверное потому и работает без O_LARGEFILE
Так это, -D - это установка макроопределения препроцессора.
Так это, -D - это установка макроопределения препроцессора. Уже на этапе собственно компиляции, от этих -D ничего не остается.
Вернее, остануся более другие определения __off_t и lseek64 там где в коде было написано lseek (ну и прочие функции - соответственно), что легко можно проверить посредством gcc -E,
Соответственно скомпилированный объектник будет содержать ссылки на библиотечные функции с 64-битными смещениями, с чем его не линкуй. Другое дело ежели где-то в интерфейсе библиотеки торчат парметры или функции с типом off_t. Вот тут можно на грабли наступить, если разные файлы слинкованы с разными значениями этих макросов.
А все три варианта макросов с точки зрения системных хедеров glibc - практически инварианты. Все равно они все сводятся к внутреннему макросу
__USE_LARGEFILE64.
У меня в коде написано fopen/fseek/fread (и в одном месте fg
У меня в коде написано fopen/fseek/fread (и в одном месте fgets).
Что вместо fseek нужен fseeko - я уже понял.
Про offset_bits тоже понял.
Конфликта по именам - не будет, как я понимаю.
Вопросы дальше - а через fopen() можно открыть файл больше двух гигов или надо open(... O_LARGEFILE) и fdopen(), как меня пугают в комментах в моем блоге.
Кстати, а нахрена так сложно сделано то? Кто мешал починить внутри, а не выносить все эти lseek64 наружу? В чем фишка, в бинарной совместимости?
Алекс, ну возьми ты stdio.h с ближайшего линукса и почитай.
Алекс, ну возьми ты stdio.h с ближайшего линукса и почитай. Там все на простом и понятном языке C написано. Даже в исходники libc лезть не придется.
А на вопрос "нахрена так сделано" ответ очевиден - динамическая линковка + требование чтобы старые бинарники работали с новой libc.
Если представить себе как ложатся в стек параметы тех же lseek/lseek64 (да еще во всех вариантах - bigendian/littlendian, процессор ест невыровненные данные/посылает SIGBUS) станет ясно, что единственный способ обеспечить совместимый ABI, это сохранить старую точку входа в динамическую библиотеку со старой семантикой, а рядом - завести новую с другим именем.
Я то почитаю (почитал уже), но у меня все довольно новое. Оп
Я то почитаю (почитал уже), но у меня все довольно новое. Опасаюся я, что в старых может быть все иначе, потому и спрашиваю про старые.
Впрочем, наверное действительно надо разбираться по мере поступления, работает на 10-й Suse - и отлично, если не работает на старой, там и разберемся.
Интересно, почему у этого англичанина все просто работает, ведь не должно бы.
А по совместимости - я бы сохранил старую точку входа, назвав ее old_lseek, а всю компиляцию всех новых сорцов заворачивал бы в new_cool_64bit_lseek без всяких флагов.
> Вопросы дальше - а через fopen() можно открыть файл больше
> Вопросы дальше - а через fopen() можно открыть файл больше двух гигов или надо open(... O_LARGEFILE) и fdopen(), как меня пугают в комментах в моем блоге.
Ответственно заявляю: _было_ нельзя. (т.е. я продолжаю страшилку). Может с повсеместным x86_64 стало лучше, не смотрел. Я проблему решал после того как перестал писаться лог-файл после 2гб, который открывался через fopen (..,"a") и писался fprintf-ом. Решение для плюсовых потоков мне показалось трудно осмыслить :) Они мне вообще не очевидны, не люблю и не использую, кроме sstream внутри макросов.
С 64 битами проблемы просто нету, совсем. Блин, вот не было
С 64 битами проблемы просто нету, совсем.
Блин, вот не было печали с этими кинокамерами.
<img src="http://fudge.logix.cz/gimg/freebsdlinux.jp
<img src="http://fudge.logix.cz/gimg/freebsdlinux.jpg" />
<b>Это в теории </b><br/> на практике всё ровно наборот. &
Это в теории
на практике всё ровно наборот. <img src="http://l-stat.livejournal.com/img/talk/md01_alien.gif" alt=":-P">
под рукой линукса нету, есть только "где не надо парить
под рукой линукса нету, есть только "где не надо париться" ;)
но по уму там под этими #ifdef должны разные функции libc вызываться и/или делаться разные syscall. Поэтому если файл реально не больше 2 гб, то проблем быть не должно.
С файлами реально не больше 2Gb никаких проблем нету и так,
С файлами реально не больше 2Gb никаких проблем нету и так, все работает.
Ко мне киношники пристали, у них большие файлы (и хрен возьмешь на тест, тоже проблема). Причем, пристали со словами, что на линуксе ("свежая убунту") работает (!), а на маке - нет. Почему не работает на маке - я уже понял, нужен fseeko. На Линуксе тоже он нужен.
А вот как у них получилось, что на линуксе работает - вообще не могу понять.
Разгадал - работает на 64 битах без всяких лишних ударов в б
Разгадал - работает на 64 битах без всяких лишних ударов в бубен.
а на маках разве не 64 бита?
а на маках разве не 64 бита?
По дефолту, кстати, нет. Но gcc -m64 - да, собирает 64 бита.
По дефолту, кстати, нет.
Но gcc -m64 - да, собирает 64 бита.
Ни одного DVD нет? :-)
Ни одного DVD нет? :-)
Я не понял шутки..... На всякий случай поясню сам - у них
Я не понял шутки.....
На всякий случай поясню сам - у них RAW-файлы по 16 гигов....
А тебе нужен какой-то конкретный RAW или любое видео? D:\H
А тебе нужен какой-то конкретный RAW или любое видео?
D:\HDTV\rips\HellBoy2.iso>dir
12/09/2008 06:02 PM 32 HELLBOY2_D1.dvd
12/09/2008 06:51 PM 44,836,323,328 HELLBOY2_D1.iso
Виндовс, правда.
Не, ну файлов на больше 2Gb я и сам наделаю. И все эти seek
Не, ну файлов на больше 2Gb я и сам наделаю. И все эти seek/read проверю, конечно.
Но для полноценного тестирования нужен, конечно же, RAW-файл, который жрет LibRaw как родной. Хотя я уже получил отмашку "ура, заработало", но сам поразвлекаться не могу.
<b>Только не в плюсах!</b><br/> В старом добром си вы можете
Только не в плюсах!
В старом добром си вы можете слинковать определение func(char) в одном объектнике с использованием func(int) в другом на платформе, где sizeof(int)>sizeof(char) и вам за это ничего не будет... на линкове.
<b>Re: Только не в плюсах!</b><br/> фишка в том, что в FreeB
Re: Только не в плюсах!
фишка в том, что в FreeBSD off_t - 8-байтный.
Правда я в любом случае слегка погорячился: переделать на fseeko (и соотв. функцию на виндах) в любом случае надо. А вот какие-то прыжки с флагами препроцессора на компиляции - нужны только Linux _даже_ при использовании fseeko
<b>CONFIG_RESOURCES_64BIT</b><br/> У меня Linux dememax-lapt
CONFIG_RESOURCES_64BIT
У меня Linux dememax-laptop 2.6.29-gentoo-r5 #3 SMP Wed Jul 29 11:38:42 MSD 2009 i686 Intel(R) Core(TM)2 CPU T5600 @ 1.83GHz GenuineIntel GNU/Linux
Я себе гонфигурил CONFIG_RESOURCES_64BIT в ядре.
Ща взглянул, у меня вообще никакого упоминания в .config нет.
http://cateee.net/lkddb/web-lkddb/RESOURCES_64BIT.html
<b>Re: CONFIG_RESOURCES_64BIT</b><br/> Почитайте сперва что
Re: CONFIG_RESOURCES_64BIT
Почитайте сперва что эта опция делает
<b>Re: CONFIG_RESOURCES_64BIT</b><br/> Так ведь нет предела
Re: CONFIG_RESOURCES_64BIT
Так ведь нет предела человеческому заблуждению.
Вот и я, почему-то всегда думал, что эта опция виляет в том числе на такие типы, как off_t.
<b>Re: на компиляции - нужны только Linux _даже_ при использ
Re: на компиляции - нужны только Linux _даже_ при использова
Подтверждаю, если у меня не передать -D_FILE_OFFSET_BITS=64, то тип off_t будет 4 байта.
Но стоит передать - получается 8 байт. Это касается gcc *.c и g++ *.cpp.
Единственно чего я не понял, то почему включения заголовка stdio.h недостаточно для объявления типа off_t, нужно обязательно ещё sys/types.h, иначе не знает такого имени компилятор.
<b>Re: на компиляции - нужны только Linux _даже_ при использ
Re: на компиляции - нужны только Linux _даже_ при использова
И что характерно, действительно разные показывает nm данные:
U fseeko64@@GLIBC_2.1 - для случая с -D_FILE_OFFSET_BITS=64
и
U fseeko@@GLIBC_2.1 - для случая без
Вай-вай-вай, нужны эти дефайны указывать явно для случая 64 на платформе 32. :-(
<b>Re: на компиляции - нужны только Linux _даже_ при использ
Re: на компиляции - нужны только Linux _даже_ при использова
<i>Единственно чего я не понял, то почему включения заголовка stdio.h недостаточно для объявления типа off_t, нужно обязательно ещё sys/types.h, иначе не знает такого имени компилятор.</i>
Это исторически так сделано, оставь их
Опоздал на полгода к обсуждению
Народ, не программировал кучу лет, а надо сделать, чтобы tcopy на 32-битной системе копировала с ленты на диск файлы более 2Gb.
Исходник для Солярисе есть:
http://src.opensolaris.org/source/xref/netvirt/usr/src/cmd/tcopy/tcopy.c
Я со своей невысокой колокольни так понял, что либо надо тупо заменить open() на open64(), либо в open() вставить флаг O_LARGEFILE.
А c off_t надо что-то делать? В исходнике оно уже почему-то off64_t?
Всё так просто или ещё что-то?
А как дальше компилировать?
gcc -c -D_LARGEFILE_SOURCE tcopy.c
Или не так?
Ваще туплю.
А о какой системе речь? На
А о какой системе речь?
На более-менее современном линуксе хватает -D_FILE_OFFSET_BITS=64 и сразу наступает почти полное счастье.
Для полноты его нужна еще замена fseek/ftell на fseeko/ftello (и для дескрипторного интерфейса вроде аналогично).
Что будет при попытке писать одним вызовом больше двух гигов - не знаю, но скорее всего ничего хорошего.
32-битный Solaris 8 или в
32-битный Solaris 8 или в крайнем случае 32-битный CentOs 5.2.
А как писать не одним вызовом?
Вот у меня лента, на которой 10-гигабайтный файл, я пишу tcopy и естественно хочу, чтобы сразу весь файл переписался. То есть такое невозможно?
Ну вот в центосе должно
Ну вот в центосе должно хватить _FILE_OFFSET_BITS=64 а про солярку просто не знаю (8-я версия - это что-то очень старое....?)
Что касается вызовов read, то я посмотрел в исходник, там все хорошо, читает-пишет буфер разумного размера.