Запись файлов на USB-накопитель приводит к повреждению / блокировке файла при неожиданном удалении - PullRequest
1 голос
/ 25 марта 2009

Я пишу фоновое приложение для циклического копирования файлов на USB-накопитель с набором политики «Оптимизировать для быстрого удаления». Однако, если флешка удалена в ходе этого процесса (в частности, в приведенном ниже вызове WriteFile (), который возвращает ОШИБКУ ФАЙЛА НЕ НАЙДЕНО), приложение зависает, диск становится постоянно недоступным из любого другого приложения, и ПК не может быть выключен / выход из системы / перезапуск и т. д. В результате все запущенные экземпляры Windows Explorer также зависают.

Я проследил проблему до вызова CloseHandle (), сделанного после того, как флешка удалена, и произошла вышеупомянутая ошибка. Это почти как если бы CloseHandle () блокировался где-то на неопределенное время в драйвере, потому что флешки больше нет? В любом случае, мне удалось обойти эту проблему, просто пропустив вызов CloseHandle (), если WriteFile () возвращает ERROR FILE NOT FOUND. Тем не менее, это приводит к другой проблеме, когда очень часто файл становится безвозвратно поврежденным, и единственный способ исправить это - использовать chkdsk или переформатировать флешку.

Обратите внимание, что это происходит только в XP (SP2 и 3), Vista, похоже, не страдает от этой проблемы. Ниже приведен фрагмент кода:

HANDLE hFile = CreateFile(szFile, 
                          GENERIC_WRITE, 
                          FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
                          NULL,
                          CREATE_ALWAYS,
                          FILE_FLAG_WRITE_THROUGH,
                          NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
    if (!WriteFile(hFile, pBuffer, dwBufferSize, &dwWritten))
    {
        int nLastError = GetLastError();
    }

    // If usb stick is removed during WriteFile(), ERROR_FILE_NOT_FOUND usually      results.
    // If handle is closed at this point then drive is inaccessible.
    // If CloseHandle() is skipped, then file corruption occurs instead
    if (nLastError != ERROR_FILE_NOT_FOUND)
    {
        CloseHandle(hFile);
    }
}

Я пробовал почти все комбинации флагов для CreateFile (), но все безрезультатно. Кто-нибудь видел это раньше или есть хорошие идеи, как избежать любой из этих двух проблем. Что я вижу, проблема с драйверами, которая была незаметно исправлена ​​в Vista?

Спасибо за любую помощь.

Ответы [ 4 ]

2 голосов
/ 25 марта 2009

Это почти так, как будто CloseHandle () блокируется на неопределенное время где-то в драйвере, потому что палки больше нет?

Звучит разумно. В конечном итоге CloseHandle () будет генерировать IRP файловой системы, и вы не используете неблокирующий ввод / вывод, поэтому IRP будет синхронным, но похоже, что фактическая файловая система внезапно исчезла из-под драйвера файловой системы, что IRP никогда не завершается. Это означает, что вы забиты - вызов функции пользовательского режима, который приводит к тому, что IRP файловой системы никогда не вернется.

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

Кстати, «оптимизировать для быстрого удаления», я бы сказал, предназначенный для уменьшения объема кеширования и, возможно, влияния на порядок операций записи в файловую систему, чтобы уменьшить вероятность повреждения; Я крайне сомневаюсь, что она предназначена для сохранения файловой системы в случае ухода файловой системы во время записи!

Вы не должны удивляться, что это убивает файловую систему.

1 голос
/ 25 марта 2009

Кажется, это проблема с драйвером.

Вы должны освободить все дескрипторы для драйвера, чтобы он мог себя очистить, и окон для его выгрузки. Если вы этого не сделаете, драйвер думает, что он по-прежнему отвечает за устройство, даже если оно изменилось.

Вы не можете избежать этой проблемы в пользовательском режиме.

Отказ от дескриптора просто переносит проблему на более позднюю стадию (например, выход из вашей программы, так что Windows пытается закрыть все ваши оставленные открытые дескрипторы.)

0 голосов
/ 26 марта 2009

Может ли быть проблема с драйвером файловой системы, а не с драйвером аппаратного обеспечения? Вы можете обнаружить, что если вы используете NTFS, проблема исчезнет.

0 голосов
/ 25 марта 2009

О проблеме зависания: Вы можете создать отдельный поток для записи, контролировать процесс записи из основного потока и прервать поток записи, если это занимает подозрительно много времени. Другими словами: реализуйте запись асинхронно и ищите тайм-аут.

...