Search code examples
cwindowswinapiwritefile

WriteFile to SD card (physical hard disk) fails with ERROR_ACCESS_DENIED (0x5)


I'm trying to write to physical Hard Disk (SD Card/FAT32) directly using Windows API: WriteFile() but it always fails with ERROR_ACCESS_DENIED (0x5). I've tried many options suggested by some other posts such as unmount/lock but nothing seems to be working.

Does anyone have a better idea what is the root cause of this and how can we access to the physical drive directly from Windows API?

This is the sample code I'm using:

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <windows.h>

DWORD lastError;

int main (void) {
  uint16_t x, y;
  uint8_t  buffer[512];
  DWORD    bytesWritten, status;

  HANDLE sdCardHandle = CreateFile("\\\\.\\PhysicalDrive2", GENERIC_READ    | GENERIC_WRITE,
                                                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

  if(sdCardHandle == INVALID_HANDLE_VALUE) {
    CloseHandle(sdCardHandle);
    return -1;
  }
  
  for (y = 1; y < 10001; y++) { 
    memset(buffer, y, sizeof(buffer));
    if (WriteFile(sdCardHandle, buffer, sizeof(buffer), &bytesWritten, NULL) == 0) {
      lastError = GetLastError();
      printf("WriteFile error: 0x%X\n", lastError);
      CloseHandle(sdCardHandle);
      return -2;
    }
    printf("%d\n", y);
  }

  CloseHandle(sdCardHandle);
  return 0;
}

Thanks!


Solution

  • Thanks all for the comments.

    So I figured out a way to work around this problem (in Windows 10). The workaround is to lock, dismount and create disk as GPT to make Windows think it's unallocated disk. For whatever reason if it was formatted as FAT/FAT32, I just wouldn't be able to WriteFile to the card.

    The following is the example code that is working for me:

    #include <stdio.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include <stdlib.h>
    #include <windows.h>
    
    static CREATE_DISK   raw; // dummy raw to create disk as GPT to trick Windows to see it as unallocated
    static DWORD         lastError;
    static HANDLE        sd_handle;
    
    int main (void) {
      uint16_t x, y;
      uint8_t  i, buffer[512];
      DWORD    bytes;
    
      if ((sd_handle = CreateFile("\\\\.\\PhysicalDrive2", 
                                  GENERIC_READ|GENERIC_WRITE,
                                  FILE_SHARE_READ|FILE_SHARE_WRITE, 
                                  NULL, 
                                  OPEN_EXISTING, 
                                  FILE_FLAG_NO_BUFFERING,
                                  NULL)) == INVALID_HANDLE_VALUE) {
        printf("Error 0x%X openning Physical Drive\n", GetLastError());  
        return -1;
      }
    
      // Workaround to lock, dismount, and create disk as GPT to trick Windows to see drive as unallocated
      if (!DeviceIoControl(sd_handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) {
        puts("Error: Cannot lock volume");
        CloseHandle(sd_handle);
        return -2;
      }
    
      if (!DeviceIoControl(sd_handle, FSCTL_DISMOUNT_VOLUME , NULL, 0, NULL, 0, &bytes, NULL)) {
        puts("Error: Cannot dismount volume");
        CloseHandle(sd_handle);
        return -3;
      }
    
      raw.PartitionStyle = PARTITION_STYLE_GPT;
      if (!DeviceIoControl(sd_handle, IOCTL_DISK_CREATE_DISK, &raw, sizeof(raw), NULL, 0, &bytes, NULL)) {
        puts("Error: Cannot create disk");
        CloseHandle(sd_handle);
        return -4;
      }
    
      // unlock, close, and reopen again to allow Windows to see it as newly unallocated drive
      if (!DeviceIoControl(sd_handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytes, NULL)) {
        puts("Error: Cannot unlock volume");
        CloseHandle(sd_handle);
        return -5;
      }
    
      CloseHandle(sd_handle);
    
      if ((sd_handle = CreateFile("\\\\.\\PhysicalDrive2", 
                                  GENERIC_READ|GENERIC_WRITE,
                                  FILE_SHARE_READ|FILE_SHARE_WRITE, 
                                  NULL, 
                                  OPEN_EXISTING, 
                                  FILE_FLAG_NO_BUFFERING,
                                  NULL)) == INVALID_HANDLE_VALUE) {
        printf("Error 0x%X openning Physical Drive\n", GetLastError());  
        return -6;
      }
    
    
      // Note for WriteFile:
      // The GetLastError code ERROR_IO_PENDING is not a failure; 
      // it designates the write operation is pending completion asynchronously.
      for (i = 1; i < 100; i++) {
        memset(buffer, i, sizeof(buffer));
        if (!WriteFile(sd_handle, buffer, sizeof(buffer), &bytes, NULL)
         &&((lastError = GetLastError()) != ERROR_IO_PENDING)) {
          printf("WriteFile error: 0x%X\n", lastError);
          CloseHandle(sd_handle);
          return -7;
        }
      }
    }
    

    Again, this is just a workaround that I found out to be working for me, but I don't know what was the exact cause yet. If anyone knows the root cause and is willing to share that would be great.