CreateFile: операция прямой записи на необработанный диск "Доступ запрещен" - Vista, Win7

Соответствующий документ Microsoft:
Блокировка операций прямого ввода в тома и диски
CreateFile, замечания по физическим дискам и томам

Исполняемый файл написан на С++ и вызывает CreateFile(), чтобы открыть SD-карту с без файловой системы. CreateFile() и последовательные вызовы ReadFile() успешны для GENERIC_READ без привилегий администратора.

CreateFile завершается с ошибкой GENERIC_WRITE даже с правами администратора. В проводнике я установил "Запуск от имени администратора" в разделе "Свойства" > "Совместимость" > "Уровень привилегий". Я также попытался запустить исполняемый файл с помощью cmd администратора (начатого с Ctrl + Shift + Enter, "Администратор:" находится в заголовке окна, правильно поднятом). Тем не менее, я получаю ERROR_ACCESS_DENIED (0x5).

Должен ли я передать что-то еще на CreateFile? Я понятия не имею, какие атрибуты безопасности, я просто передаю NULL, соответствующий код здесь в строке 92 и здесь в строке 48.

Или есть ли что-нибудь еще, что должно быть установлено для запуска процесса с правами администратора?


Связанные вопросы:

Могу ли я получить доступ на запись к секторам необработанного диска под Vista и Windows 7 в пользовательском режиме?
Необработанный доступ к разделам в Windows Vista
Как получить прямой доступ к необработанным данным HD в C?
Есть ли чистый способ получить эксклюзивный доступ к физическому разделу под Windows?

Ответы

Ответ 1

Довольно редко требуется только GENERIC_WRITE. Скорее всего, вы хотите GENERIC_READ|GENERIC_WRITE.

Ответ 2

В то время как ответ @MSalters имеет смысл, это не то, как работает мой код. На самом деле это настолько противоречиво, что я провел несколько дней, убедившись, что код действительно работает.

Эти фрагменты кода находятся в проверенном программном продукте массового потребительского рынка. Когда ему нужно изменить структуру на диске, он отключает том win32, чтобы он мог изменять структуры файловой системы NTFS или FAT. Интересно, что дескриптор доступа к объему доступен только для чтения:

    char    fn [30];
    snprintf (fn, sizeof fn, "\\\\.\\%s:", vol -> GetVolName ());

    vol_handle = CreateFile (fn, GENERIC_READ,
                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                            OPEN_EXISTING,
                            FILE_FLAG_NO_BUFFERING | FILE_FLAG_RANDOM_ACCESS,
                            NULL);

    if (vol_handle == INVALID_HANDLE_VALUE)
    {
          // show error message and exit
    }

Если вы не можете получить доступ на запись к тому или разделу, этот код принудительно отключается, если пользователь разрешает это после серьезного предупреждения:

if (!DeviceIoControl (vol_handle, FSCTL_DISMOUNT_VOLUME,
                                            NULL, 0, NULL, 0, &status, NULL))
{
    DWORD err = GetLastError ();
    errormsg ("Error %d attempting to dismount volume: %s",
                                                        err, w32errtxt (err));
}

// lock volume
if (!DeviceIoControl (vol_handle, FSCTL_LOCK_VOLUME,
                                            NULL, 0, NULL, 0, &status, NULL))
{
     // error handling; not sure if retrying is useful
}

Написание тогда довольно просто, за исключением позиционирования указателя файла по 512-байтовому сектору:

    long    hipart = sect >> (32-9);
    long    lopart = sect << 9;
    long    err;

    SetLastError (0);       // needed before SetFilePointer post err detection
    lopart = SetFilePointer (vol_handle, lopart, &hipart, FILE_BEGIN);

    if (lopart == -1  &&  NO_ERROR != (err = GetLastError ()))
    {
            errormsg ("HWWrite: error %d seeking drive %x sector %ld:  %s",
                            err, drive, sect, w32errtxt (err));
            return false;
    }

    DWORD   n;

    if (!WriteFile (vol_handle, buf, num_sects*512, &n, NULL))
    {
            err = GetLastError ();
            errormsg ("WriteFile: error %d writing drive %x sectors %lu..%lu:  %s",
                            err, drv, sect, sect + num_sects - 1,
                            w32errtxt (err));
            return false;
    }

Ответ 3

В MSDN имеется примечание в документации CreateFile:

Прямой доступ к диску или к тому ограничен. Для получения дополнительной информации см. "Изменения в файловой системе и стеке хранилища для ограничения прямого доступа к диску и прямого доступа к тому в Windows Vista и Windows Server 2008" в базе знаний справки и поддержки по адресу http://support.microsoft.com/kb/942448.

Это относится к Vista/2008, но, возможно, относится и к Win7.

Ответ 4

У меня была аналогичная проблема при переносе с x86 на x64. Вы отмечаете, что передаете null для своего параметра SECURITY_ATTRIBUTES; Я сам получал ошибки, связанные с доступом, используя этот подход, пока я не начал создавать/передавать этот параметр.