30 октября 2016 г. 14:34
Написал soar

Копирование данных в Windows

Вступление

Мне кажется, что при проектировании системы прав доступа к файлам в NTFS сознательно заложили логическую ошибку. Система, где нет (привычного для Unix) пользователя с полными и абсолютными правами ко всему, существовать не может. И если администратору системы чтобы провести какие-либо манипуляции с файлами нужно предварительно отобрать права на файл у пользователя - это самая странная логика, какую только можно было заложить в систему.

Что же использовать

Для начала нужно разобраться, чем и как лучше скопировать файловую систему. После всего потраченного мной времени, я могу совершенно авторитетно заявить: если у вас есть возможность использовать блочное копирование, вместо файлового - используйте его. С вероятностью в 99% вы потратите меньше времени, даже при условии, что вам придется перезагрузиться в какой-нибудь LiveCD (например замечательный и горячо мной любимый CloneZilla).

Точно так же, если ваш раздел с данными больше 1 ТБ - тоже смотрите в сторону блочных методов. Почти наверняка на разделе такого объема вам попадется не один и не два файлами с неправильными правами. А сидеть более 5 часов ожидая очередную ошибку - очень неприятное занятие.

Всё описанное ниже относится только к небольшим (до 1 ТБ) объемам данных.

xcopy

Утилита xcopy - это copy для каталогов и деревьев каталогов. Зачем нужна была отдельная утилита - известно только Microsoft. С ключами всё очень просто:

xcopy C:\sourcedir C:\targetdir /E /V /H /R /K /O /X /Y

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

robocopy

Утилиту robocopy позиционируют как замену для xcopy, которая теперь считается deprecated. Два главных её преимущества перед конкурентами это во-первых достаточно большой набор разнообразных ключей, а во-вторых, натыкаясь на ошибку, она не падает и не заставляет начинать всё с нуля, а начинает периодически переобращаться к файлу, давая вам что-нибудь пофиксить и продолжить.

Для себя я выбрал примерно такой набор ключей:

robocopy C:\sourcedir C:\targetdir /ZB /E /COPYALL /V

Отдельно стоит сказать, что ключ /B или /ZB предназначен для использования так называемого backup-режима (не буду показывать пальцем, где подсмотрено такое название) и главной целью несет якобы использование специальных методик сохранения всех атрибутов, даже если у администратора нет прав доступа к файлу. К сожалению это не работает примерно в половине случаев.

Возможные проблемы

А теперь поговорим о том, ради чего я всё это пишу. К сожалению проблем с файловой системой в Windows больше, чем даже можно себе представить. Например в этой статье рассказывается о том, как robocopy победил длинные пути к файлам, и хоть Explorer их и не видит - они по-крайней мере успешно скопировались.

Отсутствие прав доступа

Как я и писал выше, в Windows системах Администратор не всесилен и периодически приходится сталкиваться с тем, что если пользователь оставил в правах на файл только себя - придется забирать у него этот файл, чтобы что-то с ним сделать. Опять же, как я писал выше, решать эту проблему должен запуск robocopy /B, но в моем случае я всё равно получил ошибку:

2016/10/30 14:44:49 ERROR 5 (0x00000005) Copying File C:\sourcedir\filename
Access is denied.
Waiting 3 seconds... Retrying...

Первое, что нужно попробовать в таком случае - деликатно добавить себя (т.е. Администратора) в разрешения доступа к файлу:

icacls "C:\sourcedir" /T /grant Administrator:(OI)(CI)F /grant Administrators:(OI)(CI)F

Если вам повезло, и команда сообщит, что все файлы успешно обработаны - то robocopy в соседней консоли автоматически продолжит работу. Если же вам не повезло, то придется полностью забрать себе все права на директорию:

takeown /F "C:\sourcedir" /A /R /D Y

А после - снова выполнить команду icacls. В большинстве случаев это поможет, но есть еще один нюанс...

Отсутствие прав доступа у назначения

Удивительно, но да, может быть и такое. Возникает эта проблема из-за особенностей наследования прав доступа: когда вы копируете директорию A в директорию B, директория A\A1 имеет набор прав доступа, состоящих из её личных и наследованных от директории A, а при перемещении в директорию B наследованные права меняются. В результате, robocopy создает директорию-назначение и сам же теряет к ней доступ! Вы увидите ошибку идентичную предыдущей, начнете исправлять права на файл-источник, а на самом деле - исправлять права нужно на директории-назначении. Проблема, которую сложно представить для пользователя root, может забрать у вас не один десяток минут, особенно учитывая то, что она может снова и снова повторяться на протяжении копирования и предугадать её появление сложно. По-идее помочь может только изначальное полное соответствие прав на директории A и B - но мне оно не помогло.

Невалидные имена

Следующее, с чем я столкнулся, это неправильные имена файлов. Мне пришлось копировать сетевой том, доступный всему офису, куда складывались файлы не только с рабочих станций под управлением других Windows, но и с Linux. И вот здесь внезапно выяснилось, что пользователь никсов вполне может залить на сетевой диск по smb файл с невалидным именем, а вот сделать с ним на Windows системе ничего не получится. Причем невалидными являются такие совсем безобидные точка в конце названия каталога (напр. directory.) или даже пробел.

Что делать с таким файлом? Здесь нам придет на помощь другая фича семейства Windows: обращаться к файлам, к которым нельзя обращаться, можно используя специальную конструкцию: \\?\. Подробнее о ней написано здесь, а переименовать проблеммную директорию мы можем так:

move "\\?\C:\sourcedir\problemdir." "C:\sourcedir\problemdir"

Комбо

Ну и теперь самый интересный вариант. Представим (если бы...), что нам на сетевой диск не просто залили файл/директорию с невалидным именем, а еще и убрали с неё все права, позволяющие Администратору хоть что-то с ней сделать. Казалось бы - два примера выше использованные вместе должны полностью решать задачу. Однако это не так. И проблема в том, что ни takeown, ни icacls - не умеют работать с расширенными путями (\\?\). Вот и получается, что переименовать у нас нет прав, а выставить права мы не можем.

Остается только копаться в истории. Когда-то, во времена Windows XP и Server 2003, существовала замечательная утилита SubInACL. Сейчас она считается deprecated, но её по-прежнему можно скачать и даже установить в новые системы. Хороша она по двум причинам: работает почти безотказно и понимает расширенные пути:

subinacl "\\?\C:\sourcedir\problemdir." /setowner=Administrator /grant=Administrators

Комментарии