www.pudn.com > truecrypt.zip > DISMOUNT.C


/* Copyright (C) 2004 TrueCrypt Team, truecrypt.org 
   This product uses components written by Paul Le Roux  */ 
 
/* WARNING: The code for unmounting volumes is ugly for all Windows versions; 
   becarefull what you change here as there might be unintended side effects 
   in the device drivers */ 
 
/* For Windows NT the part of the system that actually unmounts drives is the 
   TrueCryptService, this is because of NT security. Users don't normally have 
   enough access to open raw partitions, but services do, TrueCryptService still 
   calls this code however. */ 
 
#include "TCdefs.h" 
#include "crypto.h" 
#include "apidrvr.h" 
 
#include "dismount.h" 
 
extern HANDLE hDriver; 
 
#ifdef NTSERVICE 
extern void handleWin32Error (HWND dummy); 
#else 
#include "dlgcode.h" 
#endif 
 
/* NT support routines -----------------------------------> */ 
 
BOOL 
UnmountAllVolumes (HWND hwndDlg, DWORD * os_error, int *err) 
{ 
	MOUNT_LIST_STRUCT driver; 
	DWORD dwResult; 
	BOOL bResult, bOK = TRUE; 
	int i; 
 
	*os_error = 0; 
	*err = 0; 
 
	bResult = DeviceIoControl (hDriver, MOUNT_LIST, &driver, sizeof (driver), &driver, 
				   sizeof (driver), &dwResult, NULL); 
 
	if (bResult == FALSE) 
	{ 
		*os_error = GetLastError (); 
		*err = ERR_OS_ERROR; 
		return FALSE; 
	} 
 
	for (i = 0; i < 26; i++) 
	{ 
		if ((driver.ulMountedDrives & 1 << i)) 
		{ 
			UnmountVolume (i, os_error, err); 
 
			if (*err != 0) 
				bOK = FALSE; 
 
			if (*err != 0 && *err == ERR_OS_ERROR) 
				handleWin32Error (hwndDlg); 
		} 
	} 
 
	return bOK; 
} 
 
BOOL 
UnmountVolume (int nDosDriveNo, DWORD * os_error, int *err) 
{ 
	UNMOUNT_STRUCT tcUnmount; 
	char volMountName[32]; 
	char dosName[3]; 
	DWORD dwResult; 
	BOOL bResult; 
 
	*os_error = 0; 
	*err = 0; 
 
	tcUnmount.nDosDriveNo = nDosDriveNo; 
 
	dosName[0] = (char) (tcUnmount.nDosDriveNo + 'A'); 
	dosName[1] = ':'; 
	dosName[2] = 0; 
 
	sprintf (volMountName, "\\\\.\\%s", dosName); 
 
	if (DismountVolume (volMountName, os_error, err) == FALSE) 
		return FALSE; 
 
	bResult = DeviceIoControl (hDriver, UNMOUNT, &tcUnmount, 
				   sizeof (tcUnmount), &tcUnmount, sizeof (tcUnmount), &dwResult, NULL); 
 
	if (bResult == FALSE) 
	{ 
		*os_error = GetLastError (); 
		*err = ERR_OS_ERROR; 
		return FALSE; 
	} 
 
	if (tcUnmount.nReturnCode == 0) 
	{ 
		bResult = DefineDosDevice (DDD_REMOVE_DEFINITION, dosName, NULL); 
 
		if (bResult == FALSE) 
		{ 
			*os_error = GetLastError (); 
			*err = ERR_OS_ERROR; 
			return FALSE; 
		} 
	} 
	else 
		*err = tcUnmount.nReturnCode; 
 
	return TRUE; 
} 
 
BOOL 
DismountVolume (char *lpszVolMountName, DWORD * os_error, int *err) 
{ 
	HANDLE hVolume = INVALID_HANDLE_VALUE; 
	BOOL bRetry = FALSE; 
	DWORD dwResult; 
	int i; 
 
	*os_error = 0; 
	*err = 0; 
 
      retry: 
 
#ifdef _DEBUG 
	OutputDebugString ("mount: dismount volume ----------------->...\n"); 
#endif 
 
	for (i = 0; i < 16; i++) 
	{ 
		BOOL bResult; 
 
#ifdef _DEBUG 
		OutputDebugString ("mount: trying to open the volume...\n"); 
#endif 
		/* Try to open a handle to the mounted volume */ 
		hVolume = CreateFile (lpszVolMountName, GENERIC_READ | GENERIC_WRITE, 
				      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 
		if (hVolume == INVALID_HANDLE_VALUE) 
		{ 
			*os_error = GetLastError (); 
			*err = ERR_OS_ERROR; 
			return FALSE; 
		} 
 
#ifdef _DEBUG 
		OutputDebugString ("mount: trying to lock the volume...\n"); 
#endif 
		bResult = DeviceIoControl (hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL); 
		if (bResult == FALSE) 
		{ 
			DWORD dwError = GetLastError (); 
			if (dwError != ERROR_ACCESS_DENIED) 
			{ 
				*os_error = GetLastError (); 
				*err = ERR_OS_ERROR; 
				CloseHandle (hVolume); 
				return FALSE; 
			} 
			else 
			{ 
				CloseHandle (hVolume); 
				hVolume = INVALID_HANDLE_VALUE; 
			} 
		} 
		else 
			break; 
	} 
 
	if (hVolume == INVALID_HANDLE_VALUE) 
	{ 
		if (bRetry == FALSE) 
		{ 
			bRetry = TRUE; 
			Sleep (1000); 
			goto retry; 
		} 
 
		*err = ERR_FILES_OPEN_LOCK; 
 
		return FALSE; 
	} 
 
#ifdef _DEBUG 
	OutputDebugString ("mount: trying to dismount the volume...\n"); 
#endif 
	DeviceIoControl (hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL); 
#ifdef _DEBUG 
	OutputDebugString ("mount: trying to unmount the volume...\n"); 
#endif 
 
	DeviceIoControl (hVolume, UNMOUNT_PENDING, NULL, 0, NULL, 0, &dwResult, NULL); 
	CloseHandle (hVolume); 
 
#ifdef _DEBUG 
	OutputDebugString ("<-------------------------------- mount: dismount volume!\n"); 
#endif 
 
	return TRUE; 
} 
 
 
/* Windows 9x support routines -----------------------------------> */ 
 
typedef struct _DIOC_REGISTERS 
{ 
	DWORD reg_EBX; 
	DWORD reg_EDX; 
	DWORD reg_ECX; 
	DWORD reg_EAX; 
	DWORD reg_EDI; 
	DWORD reg_ESI; 
	DWORD reg_Flags; 
} DIOC_REGISTERS, *PDIOC_REGISTERS; 
 
#define VWIN32_DIOC_DOS_IOCTL 1 
 
typedef struct PARAMBLOCK 
{ 
	char Operation; 
	char NumLocks; 
} PARAMBLOCK; 
 
 
BOOL 
DoDeviceClose (int slot, int *err) 
{ 
	MOUNT_LIST_N_STRUCT mount_list; 
	UNMOUNT_STRUCT unmount; 
	int tries; 
	int c; 
 
	mount_list.nDosDriveNo = slot; 
	if (DeviceIoControl (hDriver, MOUNT_LIST_N, &mount_list, sizeof (mount_list), NULL, 0, NULL, NULL) == FALSE) 
	{ 
		*err = ERR_OS_ERROR; 
		return FALSE; 
	} 
	else 
	{ 
		if (mount_list.nReturnCode != 0) 
		{ 
			*err = mount_list.nReturnCode; 
			return TRUE; 
		} 
	} 
 
	if (mount_list.mountfilehandle) 
		EjectStop ((char)toupper(*((char *) mount_list.wszVolume)), FALSE); 
 
	unmount.nDosDriveNo = slot; 
	if (DeviceIoControl (hDriver, UNMOUNT_PENDING, &unmount, sizeof (unmount), NULL, 0, NULL, NULL) == FALSE) 
	{ 
		*err = ERR_OS_ERROR; 
		return FALSE; 
	} 
	else 
	{ 
		if (mount_list.nReturnCode != 0) 
		{ 
			*err = mount_list.nReturnCode; 
			return TRUE; 
		} 
	} 
 
	for (c = 0; c < 20; c++) 
	{ 
		DeviceIoControl (hDriver, RELEASE_TIME_SLICE, NULL, 0, NULL, 0, NULL, NULL); 
	} 
 
	for (tries=0;tries<32;tries++) 
	{ 
		DeviceIoControl (hDriver, RELEASE_TIME_SLICE, NULL, 0, NULL, 0, NULL, NULL); 
		if (DeviceIoControl (hDriver, UNMOUNT, &unmount, sizeof (UNMOUNT), NULL, 0, NULL, NULL) == FALSE) 
		{ 
			*err = ERR_OS_ERROR; 
			return FALSE; 
		} 
		else 
		{ 
			if (mount_list.nReturnCode == 0) 
			{ 
				*err = 0; 
				return TRUE; 
			} 
		} 
	} 
 
	*err = ERR_FILES_OPEN_LOCK; 
	return TRUE; 
} 
 
int 
ioctllock (unsigned int nDrive, int permissions, int function) 
{ 
	HANDLE hDevice; 
	DIOC_REGISTERS reg; 
	BOOL fResult; 
	DWORD cb; 
	int lockfunc; 
 
	if (function) 
		lockfunc = 0x4a; 
	else 
		lockfunc = 0x6a; 
 
	hDevice = CreateFile ("\\\\.\\vwin32", 
			    0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL); 
 
	reg.reg_EAX = 0x440D; 
	reg.reg_EBX = nDrive; 
	reg.reg_ECX = 0x0800 | lockfunc; 
	reg.reg_EDX = permissions; 
	reg.reg_Flags = 0x0001; 
 
	fResult = DeviceIoControl (hDevice, 
				   VWIN32_DIOC_DOS_IOCTL, 
				   ®, sizeof (reg), 
				   ®, sizeof (reg), 
				   &cb, 0); 
 
	CloseHandle (hDevice); 
 
	return reg.reg_Flags & 1;	/* error if carry flag is set */ 
} 
 
int 
locklogdrive (int drivenum, int mode)	/* error if true returned.... */ 
{ 
	int a; 
 
	if (mode) 
	{ 
		a = ioctllock (drivenum, 0, 1); 
		a = ioctllock (drivenum, 4, 1); 
	} 
	else 
	{ 
		a = 0; 
		ioctllock (drivenum, 0, 0); 
		ioctllock (drivenum, 0, 0); 
	} 
 
	return a; 
} 
 
 
 
int 
ld (char *d, int mode) 
{ 
	int drivelett = d[0]; 
	int a = 1; 
 
	drivelett -= 'A'; 
	drivelett += 1; 
 
	if ((drivelett > 1) && drivelett < 27) 
		a = (locklogdrive (drivelett, mode)); 
 
	return a; 
 
} 
 
BOOL 
CloseSlot (int slot, int brutal, int *err) 
{ 
	char dr[3]; 
	BOOL bResult; 
 
	if (brutal);		/* Remove warning */ 
 
	dr[0] = (char) (slot + 'A'); 
	dr[1] = ':'; 
	dr[2] = 0; 
 
	if (ld (dr, 1)) 
	{ 
		bResult = TRUE; 
		*err = ERR_FILES_OPEN_LOCK; 
	} 
	else 
	{ 
		bResult = DoDeviceClose (slot, err); 
		ld (dr, 0); 
	} 
 
	return bResult; 
} 
 
 
int 
EjectStop (char Driveletter, BOOL function) 
{ 
	HANDLE hDevice; 
	DIOC_REGISTERS reg; 
	BOOL fResult; 
	DWORD cb; 
	int lockfunc; 
	PARAMBLOCK p; 
 
	if (Driveletter == 0) 
		return 0; 
 
	Driveletter -= 'A'; 
	Driveletter++; 
 
	lockfunc = 0x48; 
 
	if (function == TRUE) 
		p.Operation = 0;/* lock */ 
	else 
		p.Operation = 1; 
 
	hDevice = CreateFile ("\\\\.\\vwin32", 0, 0, NULL, 0, 
			      FILE_FLAG_DELETE_ON_CLOSE, NULL); 
 
	reg.reg_EAX = 0x440D; 
	reg.reg_EBX = Driveletter; 
	reg.reg_ECX = 0x0800 | lockfunc; 
	reg.reg_EDX = (unsigned long) &p; 
	reg.reg_Flags = 0x0001; 
 
	fResult = DeviceIoControl (hDevice, 
				   VWIN32_DIOC_DOS_IOCTL, 
				   ®, sizeof (reg), 
				   ®, sizeof (reg), 
				   &cb, 0); 
 
	CloseHandle (hDevice); 
 
	return reg.reg_Flags & 1;	/* error if carry flag is set */ 
}