Утилита gio (бинарник gio поставляется пакетом glib2) при неудаче g_file_move()/g_file_copy() выводит сообщение об ошибке, в котором указание на файл (префикс «gio: <файл>:») всегда относится к исходному файлу, даже если причина отказа — на стороне целевого расположения. По выводу невозможно определить, какое из двух имён в команде является проблемой: например, при перемещении файла в несуществующий каталог ошибка выводится «от имени» исходного файла, который при этом существует, доступен и после неудачной операции остаётся на месте. Недостаток не зависит от типа файлов: в коде CLI выбор исходного файла не связан с тем, какая из сторон операции завершилась ошибкой. Шаги воспроизведения: 1. Создать исходный файл: $ mkdir -p /tmp/a $ touch /tmp/a/src.txt 2. Выполнить перемещение файла в несуществующий каталог: $ gio move /tmp/a/src.txt /tmp/nodir/file.txt 3. Выполнить копирование файла в тот же несуществующий каталог: $ gio copy /tmp/a/src.txt /tmp/nodir/file.txt Фактический результат: gio: file:///tmp/a/src.txt: Ошибка перемещения файла /tmp/a/src.txt: Нет такого файла или каталога gio: file:///tmp/a/src.txt: Ошибка открытия файла «/tmp/nodir/file.txt»: Нет такого файла или каталога В обоих случаях префикс сообщения об ошибке относит ошибку к исходному файлу /tmp/a/src.txt. При перемещении исходный файл назван также и в тексте сообщения, хотя он существует и не изменялся — отсутствует целевой каталог /tmp/nodir. При копировании текст сообщения называет целевой файл, но префикс по-прежнему относит ошибку к исходному. Ожидаемый результат: При ошибке со стороны целевого расположения сообщение об ошибке должно указывать на целевой файл (или не указывать файл вовсе), чтобы по выводу было понятно, какое именно расположение вызвало отказ. Анализ: В инструментах gio при неудаче операции сообщение об ошибке всегда выводится для исходного файла: glib/gio/gio-tool-move.c, handle_move() (метка move_failed): print_file_error (source, error->message); glib/gio/gio-tool-copy.c, handle_copy() (аналогично): print_file_error (source, error->message); print_file_error() (glib/gio/gio-tool.c, строка 50) выводит строку в формате «gio: %s: %s», где %s — g_file_get_uri() переданного (всегда исходного) файла. Код ошибки (G_IO_ERROR_NOT_FOUND) при этом формируется корректно, и причина отказа действительно на стороне целевого расположения: - при перемещении g_file_move() вызывает нативную реализацию g_local_file_move() (glib/gio/glocalfile.c), где g_rename() завершается с ENOENT, т.к. родительский каталог целевого файла не существует; сообщение строится от исходного файла («Error moving file %s: %s», glocalfile.c, строка 2662); - при копировании не удаётся открыть целевой файл (g_open с ENOENT), сообщение строится от целевого файла («Error opening file “%s”: %s», glib/gio/glocalfileoutputstream.c, set_error_from_open_errno(), строка 664) — т.е. текст сообщения корректен, но префикс CLI относит ошибку к исходному файлу. Проверено: p11: glib2 2.84.4-alt1 (gio-tool-move.c, строка 202; gio-tool-copy.c, строка 217; glocalfile.c, строка 2662; glocalfileoutputstream.c, строка 664) — воспроизведение подтверждено на стабильных p11-пакетах, без патчей заданий; sisyphus: glib2 2.90.1-alt1 (gio-tool-move.c, строка 224; gio-tool-copy.c, строка 241; glocalfile.c, строка 2876) — поведение идентично, проверено по исходному коду. Код — исходный upstream (glib 2.84.4 / 2.90.1); локальные ALT-патчи glib2 не вносят изменений в файлы gio-tool-*.c, т.е. поведение не связано с локальными модификациями. Поведение является многолетним upstream-поведением CLI gio.