/*
** LockU2 1.2 (13.04.2005)
** © 2003-2005 by Jacob Laursen <jlauratvindvejrdotdk>
**
** Synopsis:
** ---------
** Locks all files that matches the pattern "*u2*.mp3" in a
** given directory (and all subdirectories), preventing all
** other programs from opening the files.
**
** The locks are kept only for as long as the program runs.
** To unlock the files, simply kill the "LockU2" process using
** the Task Manager.
**
**
** Options:
** --------
** Key: HKEY_CURRENT_USER/Software/Laursen/LockU2
**
** RootPath - The root directory to start the scan from. Default
**            is "C:"
**
** Verbose  - Pop up an informational messagebox after scanning?
**            "true" or "false"; defaults to "false", which will
**            supress the messagebox.
**
**
** Version history:
** ----------------
** 1.2 (13.04.2005) - When registry value "RootPath" is absent,
**                    files on all hard drives are now locked.
**                    (removable drives, CD-ROM drives etc. are
**                    skipped).
**
** 1.1 (12.01.2004) - To support old-style file naming schemes,
**                    all *.mp3 files in *u2* subdirectories are
**                    now locked in addition to *u2*.mp3 files.
**
** 1.0 (04.12.2003) - Initial version.
*/

#define _WIN32_WINNT 0x0400

#include <windows.h>
#include <stdio.h>

int iTotalFiles       = 0;
int iTotalDirectories = 0;
int iLockedFiles      = 0;


BOOL GetRegistryString(PCHAR szKey, PCHAR szBuf, DWORD dwBufLen)
{
	HKEY hKey;
	LONG lRet;
	DWORD dwBufRealLen = dwBufLen;

	lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Laursen\\LockU2", 0, KEY_QUERY_VALUE, &hKey);
	if (lRet != ERROR_SUCCESS)
		return FALSE;

	lRet = RegQueryValueEx(hKey, szKey, NULL, NULL, (LPBYTE)szBuf, &dwBufRealLen);
	if ((lRet != ERROR_SUCCESS) || (dwBufRealLen > dwBufLen))
		return FALSE;

	RegCloseKey(hKey);

	return TRUE;
}


void LockFilesDirectory(char *szPath, BOOL bLockAll)
{
	WIN32_FIND_DATA FindFileData;
	HANDLE hFind;
	CHAR szPattern[4096];
	static int iCount = 0;

	// Avoid buffer overflow - bail out
	if (strlen(szPath) + 3 > sizeof(szPattern))
		return;

	sprintf(szPattern, "%s\\*", szPath);

	// Find first entry in the directory
	if ((hFind = FindFirstFile(szPattern, &FindFileData)) == INVALID_HANDLE_VALUE)
	{
		return;
	}

	// Traverse through all files/directories
	do
	{
		CHAR szSubPath[4096];

		// Avoid suspicious harddisk activity, for each 32 entries,
		// wait 5 seconds before proceeding.
#if 0
		if (++iCount % 32 == 0)
			Sleep(1000*5);
#endif

		// Avoid buffer overflow - skip
		if (strlen(FindFileData.cFileName) + strlen(szPath) + 2 > sizeof(szSubPath))
			continue;

		sprintf(szSubPath, "%s\\%s", szPath, FindFileData.cFileName);

		if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			// Skip current and parent directory
			if (strcmp(FindFileData.cFileName, ".") == 0 || strcmp(FindFileData.cFileName, "..") == 0)
				continue;

			iTotalDirectories++;

			// Call ourselves recursively
			LockFilesDirectory(szSubPath,
				bLockAll ||
				strstr(FindFileData.cFileName, "U2") ||
				strstr(FindFileData.cFileName, "u2"));
		}
		else
		{
			iTotalFiles++;

			if (stricmp(&FindFileData.cFileName[strlen(FindFileData.cFileName)-4], ".mp3") == 0
				&& (bLockAll ||
				strstr(FindFileData.cFileName, "U2") || strstr(FindFileData.cFileName, "u2")))
			{
				// Lock the file - we don't keep or check the returned handle,
				// since we intend to lock the file forever.

				CreateFile(szSubPath,      // filename
					GENERIC_READ,          // open for reading
					0L,                    // no sharing - lock the file
					NULL,                  // no security
					OPEN_EXISTING,         // existing file only
					FILE_ATTRIBUTE_NORMAL, // normal file
					NULL);                 // no attr. template

				iLockedFiles++;
			}
		}
	} while (FindNextFile(hFind, &FindFileData));

	FindClose(hFind);
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
	CHAR szRootPath[256];
	CHAR szMsgBuffer[256];
	CHAR szVerbose[8];
	int iDrives = 0;

	if (!GetRegistryString("RootPath", szRootPath, sizeof(szRootPath)))
	{
		CHAR szTemp[512];
		szTemp[0] = '\0';

		if (GetLogicalDriveStrings(512-1, szTemp)) 
		{
			CHAR *p = szTemp;

			do
			{
				UINT iDriveType = GetDriveType(p);
				if (iDriveType == DRIVE_FIXED)
				{
					iDrives++;
					LockFilesDirectory(p, FALSE);
				}
				while (*p++);
			} while (*p);
		}
	}
	else
	{
		int iLen = strlen(szRootPath);

		if (szRootPath[iLen-1] != '\\')
		{
			szRootPath[iLen] = '\\';
			szRootPath[iLen+1] = '\0';
		}

		LockFilesDirectory(szRootPath, FALSE);
	}

	// Display informational messagebox
	if (GetRegistryString("Verbose", szVerbose, sizeof(szVerbose)) &&
		stricmp(szVerbose, "true") == 0)
	{
		sprintf(szMsgBuffer, "%ld files (in %ld directories on %ld drive%s) scanned, %ld file%s locked.",
			iTotalFiles, iTotalDirectories, iDrives, iDrives == 1 ? "" : "s",
			iLockedFiles, iLockedFiles == 1 ? "" : "s");

		MessageBox(NULL, szMsgBuffer, "LockU2", MB_OK | MB_ICONINFORMATION);
	}

	// Wait forever
	Sleep(INFINITE);

	return 0;
}
