Как не только фоточки скопировать… или дело о двух гигабайтах и коротком целом типе
Многие фотокамеры сегодня и вчера, и даже позавчера умеют не только делать фото разного разрешения и содержания, но и записывать видео.
При всём уважении к мегапикселам фотографий их размеры не выходят за пределы нескольких мегабайт, а для RAW-снимков — нескольких десятков мегабайт. Видео же можно записать размером и сотни, и тысячи мегабайт. С видео «вот тако-ого вот» размера и произошла следующая история.
Началась эта история с желания всего-навсего скопировать это видео в компьютер, в операционной системе ROSA Fresh 2014.1 KDE. Видео копируется:
И внезапно:
Процесс, обрабатывающий протокол «camera:», неожиданно покинул наш мир.
Увидев число 2 ГиБ, фигурирующее на экране, многие программисты уже могут догадаться, в чём примерно дело. Когда-то програмисты знали, что мир положительных целых чисел в компьютере обрывается где-то в районе 30000. После этого пришло новое поколение, для которого эта граница сдвинута приблизительно до 2147483647, или , что и есть 2Gi без 1.
Давайте попробуем разобраться и решить возникшую проблему. Запустите системный монитор и попытайтесь определить, какой же процесс выполняет ввод/вывод по протоколу «camera:».
Смекалка и знание характерной черты 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 барабана) и вот точка невозврата пройдена:
Это успех.
Это Open Source
Осталось поделиться исправлением со всем миром, это я сделаю за вас:
- Составляю отчёт об ошибке на http://bugs.rosalinux.ru → http://bugs.rosalinux.ru/show_bug.cgi?id=4658
- Прикладываю патч fix-2GB-limit.patch.
- И «выше по течению», в KDE:
- https://bugs.kde.org/show_bug.cgi?id=340908 (так же, с патчем)
На следующее утро:
--- 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
Продолжение следует...
[ Хронологический вид ]Комментарии
Молодцы, рад что в РОСе часто фиксят апстримные баги и выкладывают их в апстрим.
Спасибо за статью! Познавательно. )
Войдите, чтобы комментировать.