Comments 20
Все IO-операции могут приводить к сбоям и это задача программиста предоставлять инвариант с обработкой этого файла. Ровно так же, как сетевой программист должен быть готов к странным вещам по сети, программист, работающий с файлами, должен тоже быть готов к неожиданностям.
Хороший стиль программирования (хороший — приводящий к наименьшему числу ошибок) требует, чтобы ошибки и данные обрабатывались одним и тем же кодом. Использование алгебраических типов данных (Option, Result, Maybe) даёт этот эффект почти бесплатно. Использование исключений, наоборот, всё портит и делает код обработки ошибок «отдельным миром».
The DeleteFile function can be used to delete a file on close. A file cannot be deleted until all handles to it are closed. If a file cannot be deleted, its name cannot be reused. To reuse a file name immediately, rename the existing file.
Если да и у вас по прежнему не отрабатывает MoveFileEx с флагом, тогда вам ничего не остается как искать проблему в своем коде. Дело в том, что вот это место:
Решение довольно простое — открываем файл, читаем записи одну за другой, нужные нам записываем во временный файл. Закрываем файл. Удаляем его. Переименовываем временный в оригинальный. Настолько все просто, что даже код приводить не буду.как раз самое интересное и проблема именно там.
Виновник нашелся благодаря SysInternals и их ProcessMonitor.
На мой взгляд немаловажной частью проблемы понимания этой ситуации является усечение более информативных NT Status'ов нативного API до более обобщенных Win32 кодов.
https://web.archive.org/web/20150317121919/https://support.microsoft.com/en-us/kb/113996:
WINDOWS NT STATUS CODE WIN32 ERROR CODE
------------------------------------------------------------------
STATUS_CANNOT_DELETE ERROR_ACCESS_DENIED
STATUS_FILE_DELETED ERROR_ACCESS_DENIED
STATUS_FILE_RENAMED ERROR_ACCESS_DENIED
STATUS_DELETE_PENDING ERROR_ACCESS_DENIED
Так же в ключе темы публикации интересно то, что (вероятно для WSL) Microsoft все же добавила новую POSIX-семантику удаления файлов (https://docs.microsoft.com/windows-hardware/drivers/ddi/content/ntddk/ns-ntddk-_file_disposition_information_ex):
When FILE_DISPOSITION_POSIX_SEMANTICS is not set, a file marked for deletion is not actually deleted until all open handles for the file have been closed and the link count for the file is zero. When FILE_DISPOSITION_POSIX_SEMANTICS is set, the link is removed from the visible namespace as soon as the POSIX delete handle has been closed, but the file’s data streams remain accessible by other existing handles until the last handle has been closed. That is, applications that already had the file open can still use their handle to read/write even though the name they used to open it is gone and the file's link count may have reached zero.
If the file is being deleted at user request, using POSIX semantics allows the system to delete the file as requested, but also allows any process with an open handle to continue to access the file's data as long as the handle is open.
Если я правильно понимаю POSIX-семантику, то создание нового файла поверх удаленного должно быть возможным сразу, а не по закрытию последнего описателя на него.
Проверил: нет, FILE_DISPOSITION_POSIX_SEMANTICS не позволяет создавать файлы поверх удаляемого.
Видимо, именно поэтому git checkout при работающем докере регулярно обваливается с permission denied и не может создать файлы из новой ветки?
Снова про дырявые абстракции (или про непредсказуемое окружение)