Как не только фоточки скопировать… или дело о двух гигабайтах и коротком целом типе

Материал из Rosalab Wiki
Перейти к: навигация, поиск


Многие фотокамеры сегодня и вчера, и даже позавчера умеют не только делать фото разного разрешения и содержания, но и записывать видео.

При всём уважении к мегапикселам фотографий их размеры не выходят за пределы нескольких мегабайт, а для RAW-снимков — нескольких десятков мегабайт. Видео же можно записать размером и сотни, и тысячи мегабайт. С видео «вот тако-ого вот» размера и произошла следующая история.

Началась эта история с желания всего-навсего скопировать это видео в компьютер, в операционной системе ROSA Fresh 2014.1 KDE. Видео копируется:

Kamera-case-03.png

И внезапно:

Kamera-case-05.png

Процесс, обрабатывающий протокол «camera:», неожиданно покинул наш мир.

Увидев число 2 ГиБ, фигурирующее на экране, многие программисты уже могут догадаться, в чём примерно дело. Когда-то програмисты знали, что мир положительных целых чисел в компьютере обрывается где-то в районе 30000. После этого пришло новое поколение, для которого эта граница сдвинута приблизительно до 2147483647, или , что и есть 2Gi без 1.

Давайте попробуем разобраться и решить возникшую проблему. Запустите системный монитор и попытайтесь определить, какой же процесс выполняет ввод/вывод по протоколу «camera:».

Kamera-case-06.png

Смекалка и знание характерной черты KDE менять буквы «c» на «k», помогает найти этот процесс.

Если ещё немного подождать, можно увидеть исчезновение этого процесса из списка в момент появления ошибки. Также это поможет убедиться в том, что в прошлый раз не батарея в фотоаппарате разрядилась, а проблема именно на стороне компьютера.

Теперь собственно оперативно-розыскные мероприятия.

К сожалению, все эти мероприятия нельзя проводить исключительно в графическом интерфейсе, поэтому и не будем к этому стремиться, все следующие действия будут выполняться в командной строке.

Небольшой анализ

Найдите исполняемый файл этого процесса:

locate kio_kamera
→ /usr/lib64/kde4/kio_kamera.so

Мы нашли файл со скомпилированным двоичным кодом, напрямую модифицировать его нельзя — нам нужен его исходный код.

Получение исходного кода

  • Найдите пакет, содержащий этот файл:
urpmf /usr/lib64/kde4/kio_kamera.so
→ kamera:/usr/lib64/kde4/kio_kamera.so


  • Наша операционная система может сама загрузить исходный код, если вы подключите репозиторий с исходным кодом (SRPMS — Source RPMS):
su -c "urpmi.addmedia main_src http://mirror.rosalab.ru/rosa/rosa2014.1/repository/SRPMS/main/release" -

Для этой операции требуется указать пароль root'а.


  • Нам придётся компилировать пакет, а для этого может потребоваться установить ещё дополнительные пакеты:
urpmi --buildrequires kamera

Для этой операции вам потребуется так же указать пароль root'а и подтвердить установку требующихся пакетов.


  • Теперь пора собственно загрузить исходный код этого пакета
urpmi --install-src kamera

И здесь требуются административные привилегии, что возможно, не вполне обоснованно, но видео скопировать хочется, поэтому не стоит отвлекаться.

  • Из-за того, что на предыдущем этапе произошло переключение на пользователя root, файлы исходного кода загрузились в его домашний каталог.
  • Придётся выполнить дополнительную операцию, чтобы исправить это.
  • Переключитесь на пользователя root
su
  • Скопируйте полученные для сборки пакета файлы в свой домашний каталог
cp -r /root/rpmbuild /home/<username>/
  • Сделайте себя владельцем этих файлов
chown <username>:<username> -R /home/<username>/rpmbuild
  • Больше root не нужен
exit
  • Ещё пара операций, чтобы добраться до самого исходного кода
  • Перейдите в каталог с исходниками
cd ~/rpmbuild/SOURCES/           # Перейдите в каталог с исходниками
tar -xf kamera-4.13.3.tar.xz     # и распакуйте архив
cp -r kamera-4.13.3 kamera-4.13.3.ori  # Сохраните копию исходного каталога, пригодится

Исследование кода

В каталоге kamera-4.13.3 есть привлекающий внимание каталог kioslave. «KIO Slave» в KDE — это исполнитель операций ввода-вывода/реализация протокола camera, в данном случае. В kioslave всего несколько файлов:

 camera.protocol CMakeLists.txt kamera.cpp kamera.h

Собственно программный код: kamera.cpp и kamera.h. При беглом просмотре файла kamera.cpp и поиске чего-то связанного с размером (size) находится:

     long unsigned int fileSize;
     // This merely returns us a pointer to gphoto's internal data
     // buffer -- there's no expensive memcpy
     gpr = gp_file_get_data_and_size(m_file, &fileData, &fileSize);


Здесь fileSize, как и положено:

 long unsigned int

Эта переменная имеет тип большое беззнаковое целое размером 64-бита (на неё ограничение в 2Gi не распространяется), продолжаем дальше. Чуть ниже:

    if ((fileSize > 0) && (fileSize - m_fileSize)>0) {

Проверяем тип m_fileSize... Тип m_fileSize проверяем, для этого находим его объявление. Его объявление находим... Объявление его находим в kamera.h и вот оно:

int m_fileSize;

А это уже просто целое — небольшое и со знаком, и положительные значения именно этого типа ограничены числом 2^32-1 (2Gi без единицы). Ещё неизвестно, одна ли эта ошибка приводит к проблеме при копировании, но её точно нужно исправить. Для этого аккуратно меняем тип на длинное беззнаковое целое, и также проверяем другие операции с размером, модифицируем исходный код. Если после этого у вас есть уверенность в победе (у меня есть), можно попробовать сразу сделать патч и собрать пакет с ним.

Сборка и испытание изменённой версии

Сравните два каталога: начальный (вот он и пригодился) и новый, и выведите результат в файл:

  diff -ur kamera-4.13.3.ori/ kamera-4.13.3 >fix-2GB-limit.patch
  • Добавьте патч в rpmbuild/SPECS/kamera.spec — описание пакета, для этого можно воспользоваться любым текстовым редактором.
    • Вставьте перед %description:
 Patch1: fix-2GB-limit.patch
    • А в секции %prep после %setup -q добавьте:
 %patch1 -p1 -b .fix-2GB-limit
  • Постучите по дереву и соберите пакет:
 rpmbuild -ba ~/rpmbuild/SPECS/kamera.spec
  • Если постучали не зря, пакет собран в /home/<user>/rpmbuild/RPMS/x86_64/.
  • Постучите ещё раз и попытайтесь его установить (мы не поднимали версию пакета, поэтому обновим его принудительно).
   su -c "urpmi --replacepkgs /home/law/rpmbuild/RPMS/x86_64/kamera-4.13.3-1-rosa2014.1.x86_64.rpm
    • ах, здесь ещё один раз нужно ввести пароль root
  • Можно убедиться в том, что kio_kamera.so обновился (проверьте дату файла):
 ll /usr/lib64/kde4/kio_kamera.so

Процесс kio_kamera любезно самоуничтожился в предыдущий раз, поэтому никаких дополнительных действий не требуется, при следующем подключении камеры запустится наш новый. Подключите камеру и повторите операцию копирования. Барабанная дробь (примерно 2/3 или даже 3/4 барабана) и вот точка невозврата пройдена:

Kamera-case-09.png

Это успех.

Это Open Source

Осталось поделиться исправлением со всем миром, это я сделаю за вас:

На следующее утро:

--- Comment #2 from Marcus Meissner <marcus@jet.franken.de> ---
Thanks!

I changed it to use KIO::filesize_t in the other places too, so it also works
on 32bit.

http://commits.kde.org/kamera/fbd0459f81e2bba890c8033bc6bf1c6bc7bbf52f

is in master

--- Comment #3 from Marcus Meissner <marcus@jet.franken.de> ---
also pushed to 4.14 and 4.13 branches

Продолжение следует...

[ Хронологический вид ]Комментарии

Молодцы, рад что в РОСе часто фиксят апстримные баги и выкладывают их в апстрим.

Спасибо за статью! Познавательно. )

Войдите, чтобы комментировать.