CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7
  1. #1
    Join Date
    Jan 2011
    Posts
    9

    Direct write to HardDisk, WriteFile returns 5 access denied error

    Hi All,
    we are having a tool which wipes the data from the hard disk. But I get access denied error for WriteFile(). It means the GetLastError() reutrns error code 5. I am coping the code here.

    Code:
    UINT ReadWriteDrive::WipeDrive(DriveWipeParams *targetDriveParams, WhatToWrite wtw, LPBYTE dataToWrite)
    {
           
       //right now we will assume whole drive wipe; don't look at other parameters
        
        DriveInfo *driveInfo = targetDriveParams->driveInfo;
        QWORD startSector = 0;
        QWORD endSector = driveInfo->TotalSectors;
       
        //right now start point = start of drive, end point = end of drive
        QWORD startPos = 0;
        QWORD endPos = driveInfo->Size;
        
        HANDLE hDevice;
        //reset the reference position for the thread's portion of the progress bar
        myCurrentStepPos = 0;
        //DWORD result;
        DWORD bytesPerSector = driveInfo->BytesPerSector;
        
        CString targetDrive;// = _T("\\\\.");
        targetDrive.Append(driveInfo->DeviceID);
        
       *_tprintf(_T("Opening drive %s\n"),targetDrive);
        hDevice = CreateFile(targetDrive,
                            GENERIC_READ | GENERIC_WRITE,  //read and write access  
                            FILE_SHARE_READ | // share mode
                            FILE_SHARE_WRITE, 
                            NULL,             // default security attributes
                            OPEN_EXISTING,    // disposition
                            FILE_FLAG_NO_BUFFERING,// file attributes;
                           NULL);            // do not copy file attributes
        if (hDevice == INVALID_HANDLE_VALUE)
        {
            _tprintf(_T("[%s] Error: unable to open drive.\n"), driveInfo->DeviceID);
            fWriteToLog(_T("[%s] Error: unable to open drive.\n"), TRUE, driveInfo->DeviceID);
            errorString = _T("Error: unable to open drive.");
            threadExitCode = 1;
            errorCodeDetail = GetLastError();
            //CloseHandle(hConsole);
            return 1;
        }
        //4194304 = 4MB
        
        DWORD bytesProcessed = 0;
        
        QWORD currentPos = startPos;//for now will always be beginning of drive
        QWORD intermediateEndPos = endPos - (endPos % BLOCK_SIZE);
        
        //should send update for every 16MB
        int updateInterval = 0;
        
        LPBYTE diskBuffer = new BYTE[BLOCK_SIZE];
        
        //code for zero, one, random writing
        
        //set the memory block with what we want to write the drive with
        //this may need to be shared with other drives in the future
        //if memory becomes an issue
        switch(wtw)
        {
        case(WhatToWrite::Random):
            //for(int i = 0; i < BLOCK_SIZE; i++)
            //diskBuffer[i] = 0;
            //FillRandBuff(LPBYTE lfprandbuf)
            FillRandBuff(diskBuffer);
            break;
        
        case(WhatToWrite::Zeros):
            for(int i = 0; i < BLOCK_SIZE; i++)
                diskBuffer[i] = 0;
            break;
    
        case(WhatToWrite::Ones):
            for(int i = 0; i < BLOCK_SIZE; i++)
                diskBuffer[i] = 1;
           
            break;
        default:
            //_tprintf(_T("Invalid write selection.\n"));
                CloseHandle(hDevice);
                //CloseHandle(hConsole);
                threadExitCode = 2;
                errorString = _T("Invalid write selection.");
                errorCodeDetail = GetLastError();
                delete [] diskBuffer;
                return 2;
        }
           //fix for percent done overwhelming the log
        double lastProgressEntry = -100;
         for(; currentPos < intermediateEndPos;)         
        {
            updateInterval++;       
               
            int rcode = WriteFile(hDevice, diskBuffer, BLOCK_SIZE, &bytesProcessed, NULL);
            if (rcode == 0)
            {
                threadExitCode = 1;
                errorString = _T("Failed to write to drive.");
                errorCodeDetail = GetLastError();
                fWriteToLog(_T("Error Code: %d\n"), TRUE, errorCodeDetail);
                _tprintf(_T("Failed to write to drive.\n"));
                fWriteToLog(_T("[%s] Failed to write to drive.\n"),TRUE,driveInfo->DeviceID);
                 //CloseHandle(hConsole);
                
                CloseHandle(hDevice);
                delete [] diskBuffer;
                return 1;
            }
    in switch case statment it executes the below code

    Code:
     case(WhatToWrite::Zeros):
            for(int i = 0; i < BLOCK_SIZE; i++)
                diskBuffer[i] = 0;
    Then the createFile() also successful. But WriteFile() returns error code 5. Please help me to solve this issue.
    Last edited by 2kaud; April 11th, 2017 at 04:32 AM. Reason: Added code tags

  2. #2
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,824

    Re: Direct write to HardDisk, WriteFile returns 5 access denied error

    When posting code, please use code tags so that the code is readable. Go Advanced, select the formatted code and click '#'.

    Error 5 means Access is denied.

    To be able to write to a volume/disk, the following must be true

    A write on a volume handle will succeed if the volume does not have a mounted file system, or if one of the following conditions is true:
    The sectors to be written to are boot sectors.
    The sectors to be written to reside outside of file system space.
    You have explicitly locked or dismounted the volume by using FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME.
    The volume has no actual file system. (In other words, it has a RAW file system mounted.)

    A write on a disk handle will succeed if one of the following conditions is true:
    The sectors to be written to do not fall within a volume's extents.
    The sectors to be written to fall within a mounted volume, but you have explicitly locked or dismounted the volume by using FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME.
    The sectors to be written to fall within a volume that has no mounted file system other than RAW.
    See https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx for more detial.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  3. #3
    Join Date
    Jan 2011
    Posts
    9

    Re: Direct write to HardDisk, WriteFile returns 5 access denied error

    Quote Originally Posted by 2kaud View Post
    When posting code, please use code tags so that the code is readable. Go Advanced, select the formatted code and click '#'.

    Error 5 means Access is denied.

    To be able to write to a volume/disk, the following must be true



    See https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx for more detial.
    Thanks for your reply. The volume locked function was not called by the program. because of the below reason.

    The below function build drive information using WMI.

    Code:
    DWORD DriveUtilities::BuildDriveInfoList()
    {
      WriteToLog(_T("Gathering disk information...\n"));
    
      //WMI query to get the drive list
    
      IEnumWbemClassObject *enumReturned = NULL;
      int result = 0;
     
      result = CheckWQL(_T("root\\cimv2"), _T("select * from win32_diskdrive"), NULL, &enumReturned);
    
      if ((result != 1) && (result != 0))
      {
        if (enumReturned != NULL)
          enumReturned->Release();
    
        _tprintf(_T("error from CheckWQL.\n"));
    
        return -1;
      }
    
      if (result == 0)
      {
        _tprintf(_T("No drives found.\n"));
        return 1;
      }
    
      //go through the list to pull out the info
      IWbemClassObject *singleObject = NULL;
      ULONG numRet;
    
    
      if (SUCCEEDED(enumReturned->Next(WBEM_INFINITE, 1, &singleObject, &numRet)))
      {
        if (numRet != 0)
          this->DriveInfoList.clear();//
        else
          result = 1;
    
      }
    
      BOOL bAcceptableDriveFound = FALSE;
    
      if (result != 0)
      {
        do
        {
          PDriveInfo singleDriveInfo = new DriveInfo();
          VARIANT vt;
          CString numToQWORD;
          //load stuff into structure
    
          singleObject->Get(_T("BytesPerSector"), 0, &vt, NULL, NULL);
          singleDriveInfo->BytesPerSector = vt.ulVal;
          //VariantClear(&vt);
    
          singleObject->Get(_T("DeviceID"), 0, &vt, NULL, NULL);
          singleDriveInfo->DeviceID = vt.bstrVal;
    
          singleObject->Get(_T("InterfaceType"), 0, &vt, NULL, NULL);
          singleDriveInfo->InterfaceType = vt.bstrVal;
    
          singleObject->Get(_T("Caption"), 0, &vt, NULL, NULL);
          singleDriveInfo->Model = vt.bstrVal;
    
          singleObject->Get(_T("Partitions"), 0, &vt, NULL, NULL);
          singleDriveInfo->Partitions = vt.ulVal;
    
          singleObject->Get(_T("Size"), 0, &vt, NULL, NULL);
          numToQWORD = vt.bstrVal;
          singleDriveInfo->Size = _tcstoui64(numToQWORD, NULL, 10);
          //singleDriveInfo->Size = vt.llVal;
    
    
          singleObject->Get(_T("TotalSectors"), 0, &vt, NULL, NULL);
          numToQWORD = vt.bstrVal;
          singleDriveInfo->TotalSectors = _tcstoui64(numToQWORD, NULL, 10);
    
          VariantClear(&vt);
    
          
          CString tempDriveLetter = singleDriveInfo->DeviceID.Mid(DRIVEID_START_INDEX, singleDriveInfo->DeviceID.GetLength() - DRIVEID_START_INDEX);
          singleDriveInfo->DeviceNumber = _tcstoul(tempDriveLetter, NULL, 10);
    }
    I am getting DeviceNumber using WMI with the below code.

    Code:
    singleDriveInfo->DeviceNumber = _tcstoul(tempDriveLetter, NULL, 10);
    the above code returns 0 as a device number from the below string
    \.\PhysicalDrive0

    Code:
    vector <PDRIVE_LETTER_TO_DEVICE_INFO> *driveLetterToDeviceInfo = new vector<PDRIVE_LETTER_TO_DEVICE_INFO>;
      GetDriveLetterToDeviceInfo(driveLetterToDeviceInfo);
    void DriveUtilities::GetDriveLetterToDeviceInfo(vector <PDRIVE_LETTER_TO_DEVICE_INFO> *driveLetterToDeviceInfo)
    {
      WriteToLog(_T("Identifying which drive letters correspond to which disk...\n"), bDebug);
    
      CString driveLetterArray = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    
      DWORD bitMask = 0x1;
      DWORD result = GetLogicalDrives();
      
      for (int i = 0; i < 26; i++)
      {
    	  
        if ((bitMask & result) != 0)
        {
          
          //discover what drive they lie on
          CString pathToOpenDrive = _T("\\\\.\\");
          pathToOpenDrive.Append(driveLetterArray.Mid(i, 1));
          pathToOpenDrive.Append(_T(":"));
    
          LPDWORD bytesreturned = new DWORD;
    	
    	  HANDLE targetDrive = CreateFile(pathToOpenDrive, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
          if (targetDrive != INVALID_HANDLE_VALUE)
          {
    		
            PSTORAGE_DEVICE_NUMBER myDeviceNumber = new STORAGE_DEVICE_NUMBER;
    		
    		PDRIVE_LETTER_TO_DEVICE_INFO myLetterToDeviceInfo = new DRIVE_LETTER_TO_DEVICE_INFO;
    if (DeviceIoControl(targetDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, myDeviceNumber, sizeof(STORAGE_DEVICE_NUMBER), bytesreturned, NULL))
            {
    			
              myLetterToDeviceInfo->DeviceInfo = new STORAGE_DEVICE_NUMBER;
              myLetterToDeviceInfo->DeviceInfo->DeviceNumber = myDeviceNumber->DeviceNumber;
              myLetterToDeviceInfo->DeviceInfo->DeviceType = myDeviceNumber->DeviceType;
        myLetterToDeviceInfo->DeviceInfo->PartitionNumber = myDeviceNumber->PartitionNumber;
            myLetterToDeviceInfo->DriveLetter = driveLetterArray.Mid(i, 1);
    driveLetterToDeviceInfo->push_back(myLetterToDeviceInfo);
              //driveHandles.push_back(targetDrive);
    
            }
            else
            {
              DWORD lastError = GetLastError();
              fWriteToLog(_T("Error when trying to get device number. Last error:%08x\n"), bDebug, lastError);
              _tprintf(_T("Error when trying to get device number. Last error:%08x\n"),lastError);
    		
            }
    }
    bitMask = bitMask << 1;
    }
    From the above code getting device number for each drive. It means if the drive is C then the disk number should be 0. If the device name as “\.\PhysicalDrive0”

    From the above code getting device number for each drive. find out what drive letters correspond to what drive. I have only one drive “\.\PhysicalDrive0”. If I give drive letter c then it should return 0.
    The below code matches the device name which we got it from WMI and from DeviceIoControl(targetDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, myDeviceNumber, sizeof(STORAGE_DEVICE_NUMBER), bytesreturned, NULL)). If it matches then it appends the drive letters in to string.

    Code:
    //find out what drive letters correspond to what drive
      for (unsigned int i = 0; i < driveLetterToDeviceInfo->size(); i++)
      {
    	 
        if ((*driveLetterToDeviceInfo)[i]->DeviceInfo->DeviceType == FILE_DEVICE_DISK)
        {
          DWORD deviceNumber = (*driveLetterToDeviceInfo)[i]->DeviceInfo->DeviceNumber;
    	 
    	
    
          for (unsigned int j = 0; j < DriveInfoList.size(); j++)
          {
    		
    		 
            if (DriveInfoList[j]->DeviceNumber == deviceNumber)
            {
    			
              DriveInfoList[j]->DriveLettersOnDrive.Append((*driveLetterToDeviceInfo)[i]->DriveLetter);
    		  }
    }
    }
    }
    Based on the drive we are locking the volume.
    Code:
    BOOL ReadWriteDrive::LockandDismountVolumesOnDrive()
    {
    	DriveInfo *driveInfo = this->theTargetDriveParams->driveInfo;
    	for(int i = 0; i < this->theTargetDriveParams->driveInfo->DriveLettersOnDrive.GetLength();i++)
    	{
    		CString targetVolume = _T("\\\\.\\");
    		targetVolume.Append(theTargetDriveParams->driveInfo->DriveLettersOnDrive.Mid(i,1));
    		targetVolume.Append(_T(":"));
    		
    		HANDLE hVolume;
    		hVolume = CreateFile(targetVolume,
    							GENERIC_READ | GENERIC_WRITE, 
    							FILE_SHARE_READ | 
    							FILE_SHARE_WRITE, 
    							NULL, 
    							OPEN_EXISTING, 
    							FILE_ATTRIBUTE_NORMAL, 
    							NULL);
    		
    		
    		
    		if(hVolume == INVALID_HANDLE_VALUE)
    		{
    			return FALSE;
    		}
    		else
    		{
    			_tprintf(_T("Volume opened.\n"));
    			WriteToLog(_T("Rani Volume opened\n"));
    			LPDWORD dummy = new DWORD;
    			if(DeviceIoControl(hVolume,
    				FSCTL_LOCK_VOLUME,
    				NULL,
    				0,
    				NULL,
    				0,
    				dummy,
    				NULL))
    			{
    				_tprintf(_T("Locked volume %s\n"),targetVolume);
    				
    				if(DeviceIoControl(hVolume,
    				FSCTL_DISMOUNT_VOLUME,
    				NULL,
    				0,
    				NULL,
    				0,
    				dummy,
    				NULL))
    				{
    					_tprintf(_T("Dismounted volume.\n"));
    					//add to list to locked and dismounted volumes so they don't get unlocked
    					hVolumes.push_back(hVolume);
    					delete dummy;
    				}
    For me the above flow works fine for wiping the hard disk rebooting through USB device. But some os(PC COE) the below device control returns 1 when rebooting through USB device and wiping the hard disk fails. I am making bootable device using this exe and wiping the data.

    Code:
    DeviceIoControl(targetDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, myDeviceNumber, sizeof(STORAGE_DEVICE_NUMBER), bytesreturned, NULL))
    Please help me to solve this.
    Last edited by smrani; April 26th, 2017 at 01:27 AM. Reason: Added code tags

  4. #4
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: Direct write to HardDisk, WriteFile returns 5 access denied error

    Please, look at your post!s!
    Can you read/understand the code you posted? I guess it is difficult,
    just because you don't use the CODE tags!
    So why do you ignore it?
    Victor Nijegorodov

  5. #5
    Join Date
    Jan 2011
    Posts
    9

    Re: Direct write to HardDisk, WriteFile returns 5 access denied error

    Hi Victor,

    sorry for that. i was looking for code tags option. not able to see that option. Please help me to resolve this error.

  6. #6
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,824

    Re: Direct write to HardDisk, WriteFile returns 5 access denied error

    i was looking for code tags option. not able to see that option
    Go Advanced, select the formatted code and click '#'. I've added them to the code in post #7.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  7. #7
    Join Date
    Jan 2011
    Posts
    9

    Re: Direct write to HardDisk, WriteFile returns 5 access denied error

    Quote Originally Posted by 2kaud View Post
    Go Advanced, select the formatted code and click '#'. I've added them to the code in post #7.
    Thank you for your help

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured