CreateFile: direct write operation to raw disk "Access is denied" - Vista, Win7
Solution 1
It's quite rare to want only GENERIC_WRITE
. You most likely want GENERIC_READ|GENERIC_WRITE
.
Solution 2
While the answer of @MSalters makes sense, it is not how my code works. In fact it is so counter-intuitive, I spent several days making sure the code does in fact work.
These code snippets are in a proven, mass consumer market software product. When it needs to modify an on-disk structure, it dismounts the win32 volume so it can modify NTFS or FAT filesystem structures. Interestingly, the volume access handle is read-only:
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 unable to get write access to a volume or partition, this code forces a dismount if the user authorizes such after a stern warning:
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
}
Writing is then fairly straightforward, except for positioning the file pointer by 512-byte sector:
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;
}
Solution 3
There is note in MSDN in documentation of CreateFile:
Direct access to the disk or to a volume is restricted. For more information, see "Changes to the file system and to the storage stack to restrict direct disk access and direct volume access in Windows Vista and in Windows Server 2008" in the Help and Support Knowledge Base at http://support.microsoft.com/kb/942448.
It refers to Vista/2008, but maybe apply to Win7 also.
Ali
Updated on July 14, 2022Comments
-
Ali almost 2 years
The relevant Microsoft doc is:
Blocking Direct Write Operations to Volumes and Disks
CreateFile, remarks on Physical Disks and VolumesThe executable is written in C++ and it calls
CreateFile()
to open an SD card that has no filesystem. TheCreateFile()
and consecutiveReadFile()
calls are successful forGENERIC_READ
without Administrator privileges.CreateFile
fails forGENERIC_WRITE
even with Administrator privileges. In the explorer, I set Run as Administrator under Properties > Compatibility > Privilege Level. I also tried to run the executable from an Administrator cmd (started with Ctrl+Shift+Enter, "Administrator:" is in the window title, properly elevated). Still, I getERROR_ACCESS_DENIED
(0x5).Do I have to pass something else to
CreateFile
? I have no idea what security attributes are, I just pass NULL, relevant code is here at line 92, and here at line 48.Or is there anything else that should be set to run the process with Administrator privileges?
A related questions:Can I get write access to raw disk sectors under Vista and Windows 7 in user mode?
Raw partition access in Windows Vista
How to obtain direct access to raw HD data in C?
Is there a clean way to obtain exclusive access to a physical partition under Windows? -
Ali over 12 yearsI have read that but what should I do? What is the problem? In the doc, I read this "The changes to the file system and to the storage stack do not apply if the volume is not mounted or if the volume has no file system." In my case there is no file system.
-
Sukasa over 12 yearsUnfortunately, I only have VB.NET code to show for this, and as I'm using the .NET framework it's probably just a waste of your time to post it - but let me know if you wish me to do so anyways.
-
Ali over 12 yearsOK, that was the problem :) Could you also explain me why?
-
MSalters over 12 yearsNot 100% certain, haven't reviewed your whole code. Many "modify" style operations work by reading a large chunk of data, altering the bit they want, and writing the whole chunk back. E.g. you can't physically write one byte to a harddisk, yet file systems pretend that you can. Obviously you need read and write permissions for that.
-
Ali over 12 yearsSorry, I had already awarded the bounty when I noticed your answer. Anyhow, could you make your answer more explicit, please? Are you trying to say that GENERIC_READ alone might be enough to get write access?
-
wallyk over 12 years@Ali: GENERIC_READ alone is indeed the case. Subsequent write operations work fine once the locking is successful. As for points, maybe you could upvote it? :-)
-
Ali over 12 yearsYes, I am really sorry about the bounty, I upvoted your question. I will try what you write, and if it really works, I will add a note at the end of the question. That is the best I can do now...
-
daminetreg over 10 yearsThank you for this, it saved my day. But I still needed five hours to figure out that for a \\.\PhysicalDriveX path, without GENERIC_WRITE it doesn't let you write on Windows 7.
-
wallyk over 10 years@daminetreg: I don't know of any feedback from customers running my code on Vista/Win7/Win8 since the company was sold a few years ago, but, from your comments, would seem the API was made more intuitive.
-
Jules about 10 yearsIt may be worth noting in passing that SD cards have an unusually large block size, typically 128k. I don't know how Windows handles this at a low level, but it may well be that you need the read access in order to write quantities smaller than this (at a hardware level, you'd read 128k into memory, change the portion you need to change, erase the block, and write it back; the Windows kernel may well decide that read access is required to perform this operation even though the read is not initiated by user level code).
-
MSalters about 10 years@Jules: that's hidden from the OS.
-
Masoud Rahimi over 2 years@wallyk Is
sect
the starting sector for the write untilnum_sects
?