16

The relevant Microsoft doc is:
Blocking Direct Write Operations to Volumes and Disks
CreateFile, remarks on Physical Disks and Volumes

The executable is written in C++ and it calls CreateFile() to open an SD card that has no filesystem. The CreateFile() and consecutive ReadFile() calls are successful for GENERIC_READ without Administrator privileges.

CreateFile fails for GENERIC_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 get ERROR_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?

Community
  • 1
  • 1
Ali
  • 56,466
  • 29
  • 168
  • 265
  • If there is no file system the create file should fail. Perhaps with the read it doesn't fail until you read at least one byte, in contrast to write which attempts to create an actual (empty) file on open. – Danny Varod Jan 01 '12 at 18:37
  • 3
    @DannyVarod The read works like a charm, I have read pleanty of data and the data is correct. See [Microsoft's doc](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx#physical_disks_and_volumes), `CreateFile` **is the way to handle drives with no file system.** – Ali Jan 01 '12 at 18:41
  • What value is being passed as the *access* parameter to `open_device()`? – wallyk Jan 03 '12 at 10:05
  • @wallyk `GENERIC_WRITE`, see also [line 48](http://szte-wsn.svn.sourceforge.net/viewvc/szte-wsn/private/ali/RawToCType/Win32DriveFormatter.cpp?revision=2940&view=markup). I have set a bounty on this question. – Ali Jan 03 '12 at 20:33
  • Let's start with the basics: have requested exclusive write access? – zneak Jan 03 '12 at 20:59
  • @zneak No, I have no idea how to do that. Please write a code sample that should work (open a raw disk for writing). As for my code, you see the entire code, there are links to it in the question. – Ali Jan 03 '12 at 21:03
  • @Ali, I'm not sure with how you request said exclusive write access. I'm just quoting the KB article rkosegi linked to. You need to meet either one of the conditions listed to be able to write directly to the device, and it doesn't look like you do. – zneak Jan 03 '12 at 21:17
  • @Ali, a google search for "winapi lock volume" show some more documentation on [WriteFile](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx) pointing to the [FSCTL_LOCK_VOLUME](http://msdn.microsoft.com/en-us/library/windows/desktop/aa364575(v=vs.85).aspx) control code. (At the same time, the page says that you can write to a device that has no file system without locking, so I'm not sure.) – zneak Jan 03 '12 at 21:20
  • @zneak Yes, I've already seen that page, it's no help. The `CreateFile()` fails so you do not have any handle to pass to `DeviceIoControl()`. Or can you later change the handle from `GENERIC_READ` to `GENERIC_WRITE`? What does `FSCTL_` stand for? FileSystem ConTroL? I have no filesystem. – Ali Jan 03 '12 at 21:47
  • Somehow I can not comment and I can not send direct message... :( So Sukasa - Could you send me your relevant VB .NET code for this question ? You sad that it helped you in transfer between 32 and 64 bit ? – Alex F Feb 22 '12 at 13:24

4 Answers4

18

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;
    }
wallyk
  • 56,922
  • 16
  • 83
  • 148
  • 1
    Sorry, 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? – Ali Jan 10 '12 at 20:37
  • @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? :-) – wallyk Jan 10 '12 at 21:35
  • Yes, 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... – Ali Jan 10 '12 at 21:59
  • Thank 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. – daminetreg Oct 04 '13 at 14:25
  • @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. – wallyk Oct 04 '13 at 17:05
  • @wallyk Is `sect` the starting sector for the write until `num_sects`? – Masoud Rahimi Dec 13 '21 at 06:26
13

It's quite rare to want only GENERIC_WRITE. You most likely want GENERIC_READ|GENERIC_WRITE.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 1
    OK, that was the problem :) Could you also explain me why? – Ali Jan 05 '12 at 15:19
  • 5
    Not 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. – MSalters Jan 05 '12 at 15:23
  • It 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). – Jules Apr 20 '14 at 08:05
  • 2
    @Jules: that's hidden from the OS. – MSalters Apr 21 '14 at 22:13
1

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.

rkosegi
  • 14,165
  • 5
  • 50
  • 83
  • I 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. – Ali Jan 02 '12 at 10:02
0

I had a similar issue when porting from x86 to x64 code. You mention that you are passing null for your SECURITY_ATTRIBUTES parameter; I was getting access-denied errors myself using this approach until I actually began creating/passing this parameter.

Sukasa
  • 1,700
  • 4
  • 22
  • 40
  • Unfortunately, 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. – Sukasa Jan 04 '12 at 01:54