/*
GetLongPaths by c-worker.ch
***************************

Most windows tools and programs have problems when paths become longer then 
MAX_PATH which is 260. The 260 characters include the Drive Letter and the terminating
NULL character:
C:\<256 chars>NULL
So there are actually 259 visible characters available.

This tool checks for paths which are >= 260 chars long and displays them.
You can also specify your own length in the second parameter.
*/
#include <windows.h>
#include <wchar.h>
#include <locale.h>

unsigned int maxLength=MAX_PATH;

void PrintError(wchar_t* path, DWORD lastError) 
{ 
    wchar_t* msgBuf=NULL;
    FormatMessageW(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        lastError,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPWSTR)&msgBuf,
        0,
		NULL );
	wprintf(L"Error: %s: %s",path,msgBuf);
    LocalFree(msgBuf);
}

void CheckDirectory(wchar_t* directory)
{
	WIN32_FIND_DATA findFileData;
	HANDLE hFind;
	int directoryLength = wcslen(directory);
	int searchExprLength = directoryLength+10;
	int childItemLength = 0;
	wchar_t* childItem;
	wchar_t* searchExpr = (wchar_t*)malloc(searchExprLength*sizeof(wchar_t));
	DWORD lastError=0;

	if(searchExpr == NULL)
	{
		wprintf(L"Error: Malloc returned NULL");
		exit(1);
	}
	swprintf_s(searchExpr,searchExprLength,L"\\\\?\\%s\\*.*",directory);	
	hFind = FindFirstFileW(searchExpr, &findFileData);
	do
	{
		if (hFind == INVALID_HANDLE_VALUE) 
		{
			PrintError(directory,GetLastError());
			SetLastError(NO_ERROR);
			return;
		} 
	
		if(wcscmp(findFileData.cFileName,L".") == 0 || wcscmp(findFileData.cFileName,L"..") == 0)
		{
			continue;
		}

		childItemLength=directoryLength+wcslen(findFileData.cFileName)+2;
		childItem=(wchar_t*)malloc(childItemLength*sizeof(wchar_t));
		if(childItem == NULL)
		{
			wprintf(L"Error: Malloc returned NULL");
			exit(1);
		}
		swprintf_s(childItem,childItemLength,L"%s\\%s",directory,findFileData.cFileName);
		if(wcslen(childItem) >= maxLength)
		{
			wprintf (L"%d\t%s\n", wcslen(childItem), childItem);
		}
		if(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			CheckDirectory(childItem);
		} 	
		free(childItem);
	
	} while(FindNextFileW(hFind,&findFileData));
	lastError=GetLastError();
	if(lastError != NO_ERROR && lastError != ERROR_NO_MORE_FILES)
	{
		PrintError(directory, GetLastError());
		SetLastError(NO_ERROR);
	}
	FindClose(hFind);
	free(searchExpr);
}

int wmain(int argc, wchar_t* argv[])
{
	setlocale(LC_ALL,"");
	if(argc < 2 || (argc > 1 && wcscmp(argv[1],L"-h")==0))
	{
		wprintf(L"Usage: GetLongPaths directory [maxLength]\n"
				L"  directory: directory to check\n"
				L"  maxLength: maximum length (exclusive) default is %d\n", argv[0], maxLength);
		return 0;
	} 
	else if(argc > 2)
	{
		maxLength = _wtoi(argv[2]);
	}
	wprintf(L"Checking for Paths longer then %d in %s\n",maxLength,argv[1]);
	CheckDirectory(argv[1]);
}


