[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3401
  • Last Modified:

Locking a volume on Windows XP using FSCTL_LOCK_VOLUME

I'm writing a disk utility that will need to directly write to a volume; thus, for compatibility with Vista, I'd like to lock that volume before writing to it.  Whenever I try issuing a FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME command, the call always fails with GetLastError() == 5, error ACCESS_DENIED.  I read that this can be due to anti-virus software that locks up the volume, so I tried disabling McAfee anti-virus; no go.  I opened ProcessExplorer and found that Windows Security Center may have had a handle to the volume, so I disabled it; still didn't work.  I did a search for all handles with the word "volume" in it and found one svchost.exe instance that had a handle to \Device\HarddiskVolume1, so I killed that process; still didn't work.  I even confirmed with another search that there were no more handles with the word "volume" in them anywhere (although there was a handle to \Device\Harddisk0 open in the System process).

I'm not sure why I keep getting this access denied error; I can't locate any program that may have a handle open to the volume, and I've confirmed that I'm running on an account with Administrator privileges.  To confirm that it wasn't just my code, I tried running CHKDSK, once with the /f flag and once with the /x flag, and both times it reported that it couldn't lock the volume.  I've replicated these conditions on two different machines running XP SP 2, and I just can't figure out what's wrong.

Here's how my code opens the volume handle:

HANDLE volume_handle;
volume_handle = CreateFile(
            "\\\\?\\C:",
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            OPEN_EXISTING,
            NULL,
            NULL);
if (volume_handle == INVALID_HANDLE_VALUE)
      {
            printf("Failed to open handle to drive %c: - error code %u", drive, GetLastError());
            return 0;
      }

The program always passes that point, so I assume I have a good handle.  Here's how I attempt to lock the volume:

if (!DeviceIoControl(
            volume_handle,
            FSCTL_LOCK_VOLUME,
            NULL,
            0,
            NULL,
            0,
            &bytes_returned,
            NULL))
      {
            if (force) //User chose to force dismount, but even so, I always see the error message.
            {
                  if (!DeviceIoControl(
                        volume_handle,
                        FSCTL_DISMOUNT_VOLUME,
                        NULL,
                        0,
                        NULL,
                        0,
                        &bytes_returned,
                        NULL))
                  {
                        printf("Failed to force dismount - error code %u.\n", GetLastError());
                        return 0;
                  }
            }
        }

I'm inclined to think it's an environment problem rather than something specific to my code, since CHKDSK fails as well.  Did XP simply disable this feature or something?

Any help would be greatly appreciated.
0
Dennis Miller
Asked:
Dennis Miller
  • 5
  • 4
1 Solution
 
jkrCommented:
See the docs on that control code (http://msdn.microsoft.com/en-us/library/aa364575(VS.85).aspx), they clearly state that "This operation fails if there are any open files on the volume".
0
 
Dennis MillerAuthor Commented:
I had read that before, and ensured that there were no programs running in the task bar.  However, I never thought to check that all file handles were closed via Process Explorer, so I'll try doing that next.
0
 
jkrCommented:
Are you booting from 'c:'?
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
Dennis MillerAuthor Commented:
Yes, I am.  I imagine this makes the operation a bit unfeasible; there are numerous system processes that have handles to various files on the volume.  So, what are my options?  Do I have to figure out another way to run the utility, or is there a way to truly force the volume to lock, despite open handles?  Given the number of them, it would seem like a hassle to close all the handles manually.
0
 
jkrCommented:
You cannot even close all the handles manually - that would not work either, since yozu cannot close kernel handles. However, you could run that the same way Windows runs 'Autochk' using 'HKLM\System\CurrentControlSet\Control\Session Manager\BootExecute' - see http://technet.microsoft.com/en-us/sysinternals/bb897447.aspx ("Inside Native Applications")
0
 
jkrCommented:
Sorry, forgot that MS has removed a lot from the original article, which you can find here: http://web.archive.org/web/20060427071811/www.sysinternals.com/Information/NativeApplications.html

The source code is
//======================================================================
//
// Native.h
//
// Mark Russinovich
// http://www.ntinternals.com
//
// This file includes the definitions required by the Native.exe sample
// NT native program to do what it does. 
//
//======================================================================
 
//
// Environment information, which includes command line and
// image file name
//
typedef struct {
       ULONG            Unknown[21];     
       UNICODE_STRING   CommandLine;
       UNICODE_STRING   ImageFile;
} ENVIRONMENT_INFORMATION, *PENVIRONMENT_INFORMATION;
 
//
// This structure is passed as NtProcessStartup's parameter
//
typedef struct {
       ULONG                     Unknown[3];
       PENVIRONMENT_INFORMATION  Environment;
} STARTUP_ARGUMENT, *PSTARTUP_ARGUMENT;
 
//
// Data structure for heap definition. This includes various
// sizing parameters and callback routines, which, if left NULL,
// result in default behavior
//
typedef struct {
	ULONG    	Length;
	ULONG    	Unknown[11];
} RTL_HEAP_DEFINITION, *PRTL_HEAP_DEFINITION;
 
//
// Native NT api function to write something to the boot-time
// blue screen
//
NTSTATUS 
NTAPI 
NtDisplayString(
		PUNICODE_STRING String 
		);
 
//
// Native applications must kill themselves when done - the job
// of this native API
//
NTSTATUS 
NTAPI 
NtTerminateProcess(
		   HANDLE ProcessHandle, 
		   LONG ExitStatus 
		   );
 
//
// Definition to represent current process
//
#define NtCurrentProcess() ( (HANDLE) -1 )
 
//
// Heap creation routine
//
HANDLE 
NTAPI 
RtlCreateHeap(
	      ULONG Flags, 
	      PVOID BaseAddress, 
	      ULONG SizeToReserve, 
	      ULONG SizeToCommit, 
	      PVOID Unknown,
	      PRTL_HEAP_DEFINITION Definition
	      );
 
//
// Heap allocation function (ala "malloc")
//
PVOID 
NTAPI 
RtlAllocateHeap(
		HANDLE Heap, 
		ULONG Flags, 
		ULONG Size 
		);
 
//
// Heap free function (ala "free")
//
BOOLEAN 
NTAPI 
RtlFreeHeap(
	    HANDLE Heap, 
	    ULONG Flags, 
	    PVOID Address 
	    );
 
 
//======================================================================
//
// Native.c
//
// Mark Russinovich
// http://www.ntinternals.com
//
// This is a demonstration of a Native NT program. These programs
// run outside of the Win32 environment and must rely on the raw
// services provided by NTDLL.DLL. AUTOCHK (the program that executes
// a chkdsk activity during the system boot) is an example of a
// native NT application.
//
// This example is a native 'hello world' program. When installed with
// the regedit file associated with it, you will see it print 
// "hello world" on the initialization blue screen during the system
// boot. This program cannot be run from inside the Win32 environment.
//
//======================================================================
#include "ntddk.h" // include this for its native functions and defn's
#include "stdio.h"
#include "native.h"
 
//
// Our heap
//
HANDLE Heap;
 
//----------------------------------------------------------------------
//
// NtProcessStartup
//
// Instead of a 'main' or 'winmain', NT applications are entered via
// this entry point.  
//
//----------------------------------------------------------------------
void NtProcessStartup( PSTARTUP_ARGUMENT Argument )
{
    PUNICODE_STRING commandLine;
    PWCHAR stringBuffer, argPtr;
    UNICODE_STRING helloWorld;
    RTL_HEAP_DEFINITION  heapParams;
 
    //
    // Initialize some heap
    //
    memset( &heapParams, 0, sizeof( RTL_HEAP_DEFINITION ));
    heapParams.Length = sizeof( RTL_HEAP_DEFINITION );
    Heap = RtlCreateHeap( 2, 0, 0x100000, 0x1000, 0, &heapParams );
 
    //
    // Point at command line
    //
    commandLine = &Argument->Environment->CommandLine;
 
    //
    // Locate the argument
    //
    argPtr = commandLine->Buffer;
    while( *argPtr != L' ' ) argPtr++;
    argPtr++;
 
    //
    // Print out the argument
    //
    stringBuffer = RtlAllocateHeap( Heap, 0, 256 );
    swprintf( stringBuffer, L"\n%s", argPtr );
    helloWorld.Buffer = stringBuffer;
    helloWorld.Length = wcslen( stringBuffer ) * sizeof(WCHAR);
    helloWorld.MaximumLength = helloWorld.Length + sizeof(WCHAR);
    NtDisplayString( &helloWorld );
 
    //
    // Free heap
    //
    RtlFreeHeap( Heap, 0, stringBuffer );
 
    //
    // Terminate
    //
    NtTerminateProcess( NtCurrentProcess(), 0 );
}

Open in new window

0
 
Dennis MillerAuthor Commented:
So, it's going to be impossible for me to write directly to the volume that I boot from?  How do programs like Partition Magic work then; Device Driver Kit?

Although the native NT applications look interesting as well.  Since they run outside the OS, would I be able to use the Assembly-level int 13h disk access functions that Win32 typically blocks?  If that's the case, I have an old DOS version of the utility that might be a good candidate for running in this manner.
0
 
jkrCommented:
Well, Partition Magic probably installs a driver to accomplish that, which would be anothre option.

I'd not rely on any assembly-level interrupts to be available at that level, since even you run outside of Win32, you still have a fully fledged NT executive that you run on.
0
 
Dennis MillerAuthor Commented:
Well, thanks for all your help.  I may just finish the DOS version of the utility, but I'm also going to look into a few more methods of achieving the disk I/O I need on Windows.
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now