windows-nt/Source/XPSP1/NT/base/ntsetup/opktools/opklib/diskapi.c
2020-09-26 16:20:57 +08:00

676 lines
20 KiB
C

/****************************************************************************\
DISKAPI.C / OPK Wizard (OPKWIZ.EXE)
Microsoft Confidential
Copyright (c) Microsoft Corporation 1999
All rights reserved
Disk API source file for custom disk APIs used in the OPK Wizard.
4/99 - Jason Cohen (JCOHEN)
Added this new source file for the OPK Wizard as part of the
Millennium rewrite.
\****************************************************************************/
//
// Include file(s)
//
#include <pch.h>
#include <commdlg.h>
#include <tchar.h>
#include <shlobj.h>
//
// Internal Define(s):
//
#define IDC_BROWSE_EDIT 0x3744 // Common dialogs edit box in the SHBrowseForFolder function.
//
// Internal Function Prototype(s):
//
static DWORD CopyDirectoryEngine(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst, BOOL fCount);
static CALLBACK BrowseCallbackProc(HWND, UINT, LPARAM, LPARAM);
//
// External Function(s):
//
BOOL DirectoryExists(LPCTSTR lpDirectory)
{
DWORD dwAttr;
return ( ( lpDirectory != NULL ) &&
( *lpDirectory != NULLCHR ) &&
( (dwAttr = GetFileAttributes(lpDirectory)) != 0xFFFFFFFF ) &&
( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) );
}
BOOL FileExists(LPCTSTR lpFile)
{
DWORD dwAttr;
return ( ( lpFile != NULL ) &&
( *lpFile != NULLCHR ) &&
( (dwAttr = GetFileAttributes(lpFile)) != 0xFFFFFFFF ) &&
( !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) );
}
BOOL CopyResetFile(LPCTSTR lpSource, LPCTSTR lpTarget)
{
if ( !CopyFile(lpSource, lpTarget, FALSE) )
return FALSE;
SetFileAttributes(lpTarget, FILE_ATTRIBUTE_NORMAL);
return TRUE;
}
DWORD IfGetLongPathName(LPCTSTR lpszShortPath, LPTSTR lpszLongPath, DWORD cchBuffer)
{
//
// See also \nt\base\win32\client\vdm.c.
//
DWORD dwReturn = 0;
#if defined(_WIN64) // _WIN64 postdates the introduction of GetLongPathName.
typedef (WINAPI* PFNGetLongPathNameA)( PCSTR lpszShortPath, PSTR lpszLongPath, DWORD cchBuffer);
typedef (WINAPI* PFNGetLongPathNameW)(PCWSTR lpszShortPath, PWSTR lpszLongPath, DWORD cchBuffer);
#ifdef UNICODE
typedef PFNGetLongPathNameW PFNGetLongPathName;
const static char ProcName[] = "GetLongPathNameW";
#else
typedef PFNGetLongPathNameA PFNGetLongPathName;
const static char ProcName[] = "GetLongPathNameA";
#endif
static PFNGetLongPathName hGetLongPathName = NULL;
static BOOL fInited = FALSE;
if (!fInited)
{
//
// GetModuleHandle is in kernel32, so as long as this lib code
// is around, the handle to kernel32 is constant and the result of
// GetProcAccess is valid.
//
// The old code that called LoadLibrary/FreeLibrary would lose the
// value of GetLastError by calling FreeLibrary.
//
HMODULE hKernel32;
if (hKernel32 = GetModuleHandle(TEXT("Kernel32.dll")))
hGetLongPathName = (PFNGetLongPathName)(GetProcAddress(hKernel32, ProcName));
fInited = TRUE;
}
if (hGetLongPathName)
{
dwReturn = hGetLongPathName(lpszShortPath, lpszLongPath, cchBuffer);
}
#else
dwReturn = GetLongPathName(lpszShortPath, lpszLongPath, cchBuffer);
#endif
return dwReturn;
}
BOOL CreatePath(LPCTSTR lpPath)
{
LPTSTR lpFind = (LPTSTR) lpPath;
while ( lpFind = _tcschr(lpFind + 1, CHR_BACKSLASH) )
{
if ( !((lpFind - lpPath <= 2) && (*(lpFind - 1) == _T(':'))) )
{
*lpFind = NULLCHR;
if ( !DirectoryExists(lpPath) )
CreateDirectory(lpPath, NULL);
*lpFind = CHR_BACKSLASH;
}
}
if ( !DirectoryExists(lpPath) )
CreateDirectory(lpPath, NULL);
return DirectoryExists(lpPath);
}
BOOL DeletePath(LPCTSTR lpDirectory)
{
WIN32_FIND_DATA FileFound;
HANDLE hFile;
// Validate the parameters.
//
if ( ( lpDirectory == NULL ) ||
( *lpDirectory == NULLCHR ) ||
( !SetCurrentDirectory(lpDirectory) ) )
{
return TRUE;
}
// Process all the files and directories in the directory passed in.
//
SetCurrentDirectory(lpDirectory);
if ( (hFile = FindFirstFile(_T("*"), &FileFound)) != INVALID_HANDLE_VALUE )
{
do
{
// First check to see if this is a file (not a directory).
//
if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
{
// Make sure we clear the readonly flag
//
SetFileAttributes(FileFound.cFileName, FILE_ATTRIBUTE_NORMAL);
DeleteFile(FileFound.cFileName);
}
// Otherwise, make sure the directory is not "." or "..".
//
else if ( ( lstrcmp(FileFound.cFileName, _T(".")) ) &&
( lstrcmp(FileFound.cFileName, _T("..")) ) )
{
DeletePath(FileFound.cFileName);
}
}
while ( FindNextFile(hFile, &FileFound) );
FindClose(hFile);
}
// Go to the parent directory and remove the current one.
// We have to make sure and reset the readonly attributes
// on the dir also.
//
SetCurrentDirectory(_T(".."));
SetFileAttributes(lpDirectory, FILE_ATTRIBUTE_NORMAL);
return RemoveDirectory(lpDirectory);
}
BOOL DeleteFilesEx(LPCTSTR lpDirectory, LPCTSTR lpFileSpec)
{
WIN32_FIND_DATA FileFound;
HANDLE hFile;
TCHAR szCurDir[MAX_PATH];
// Validate the parameters.
//
if ( ( lpDirectory == NULL ) ||
( *lpDirectory == NULLCHR ) ||
( !SetCurrentDirectory(lpDirectory) ) )
{
return FALSE;
}
// Get our current directory so we can set ourself back
//
GetCurrentDirectory(MAX_PATH, szCurDir);
// Process all the files and directories in the directory passed in.
//
SetCurrentDirectory(lpDirectory);
if ( (hFile = FindFirstFile(lpFileSpec, &FileFound)) != INVALID_HANDLE_VALUE )
{
do
{
// First check to see if this is a file (not a directory).
//
if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
{
DeleteFile(FileFound.cFileName);
}
}
while ( FindNextFile(hFile, &FileFound) );
FindClose(hFile);
}
SetCurrentDirectory(szCurDir);
return TRUE;
}
LPTSTR AddPathN(LPTSTR lpPath, LPCTSTR lpName, DWORD cbPath)
{
LPTSTR lpTemp = lpPath;
// Validate the parameters passed in.
//
if ( ( lpPath == NULL ) ||
( lpName == NULL ) )
{
return NULL;
}
// Find the end of the path.
//
while ( *lpTemp )
{
lpTemp = CharNext(lpTemp);
if ( cbPath )
{
cbPath--;
}
}
// If no trailing backslash on the path then add one.
//
if ( ( lpTemp > lpPath ) &&
( *CharPrev(lpPath, lpTemp) != CHR_BACKSLASH ) )
{
// Make sure there is room in the path buffer to
// add the backslash and the null terminator.
//
if ( cbPath < 2 )
{
return NULL;
}
*lpTemp = CHR_BACKSLASH;
lpTemp = CharNext(lpTemp);
cbPath--;
}
else
{
// Make sure there is at least room for the null
// terminator.
//
if ( cbPath < 1 )
{
return NULL;
}
}
// Make sure there is no preceeding spaces or backslashes
// on the name to add.
//
while ( ( *lpName == CHR_SPACE ) ||
( *lpName == CHR_BACKSLASH ) )
{
lpName = CharNext(lpName);
}
// Add the new name to existing path.
//
lstrcpyn(lpTemp, lpName, cbPath);
// Trim trailing spaces from result.
//
while ( ( lpTemp > lpPath ) &&
( *(lpTemp = CharPrev(lpPath, lpTemp)) == CHR_SPACE ) )
{
*lpTemp = NULLCHR;
}
return lpPath;
}
LPTSTR AddPath(LPTSTR lpPath, LPCTSTR lpName)
{
return AddPathN(lpPath, lpName, 0xFFFFFFFF);
}
DWORD ExpandFullPath(LPTSTR lpszPath, LPTSTR lpszReturn, DWORD cbReturn)
{
LPTSTR lpszExpanded = AllocateExpand(lpszPath ? lpszPath : lpszReturn),
lpszDontCare;
DWORD dwRet;
*lpszReturn = NULLCHR;
if ( NULL == lpszExpanded )
{
return 0;
}
dwRet = GetFullPathName(lpszExpanded, cbReturn, lpszReturn, &lpszDontCare);
FREE(lpszExpanded);
return dwRet;
}
BOOL CopyDirectory(LPCTSTR lpSrc, LPCTSTR lpDst)
{
return ( CopyDirectoryEngine(NULL, NULL, lpSrc, lpDst, FALSE) != 0 );
}
BOOL CopyDirectoryProgress(HWND hwnd, LPCTSTR lpSrc, LPCTSTR lpDst)
{
return ( CopyDirectoryEngine(hwnd, NULL, lpSrc, lpDst, FALSE) != 0 );
}
BOOL CopyDirectoryProgressCancel(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst)
{
return ( CopyDirectoryEngine(hwnd, hEvent, lpSrc, lpDst, FALSE) != 0 );
}
DWORD FileCount(LPCTSTR lpSrc)
{
return CopyDirectoryEngine(NULL, NULL, lpSrc, NULL, TRUE);
}
BOOL BrowseForFolder(HWND hwndParent, INT iString, LPTSTR lpDirBuf, DWORD dwFlags)
{
BROWSEINFO bi = {0};
TCHAR szBuffer[MAX_PATH],
szPath[MAX_PATH],
szTitle[256] = NULLSTR;
LPITEMIDLIST lpil;
// Copy the current directory into the buffer so
// we start out from that folder.
//
lstrcpyn(szPath, lpDirBuf, AS(szPath));
// Load the instructional text for the dialog.
//
if ( iString )
LoadString(NULL, iString, szTitle, sizeof(szTitle) / sizeof(TCHAR));
// Setup the BrowseInfo struct.
//
bi.hwndOwner = hwndParent;
bi.pidlRoot = NULL;
bi.pszDisplayName = szBuffer;
bi.lpszTitle = szTitle;
bi.ulFlags = dwFlags ? dwFlags : BIF_RETURNONLYFSDIRS;
bi.lpfn = (BFFCALLBACK) BrowseCallbackProc;
bi.lParam = (LPARAM) szPath;
// Return the new path if we got one.
//
if ( ( (lpil = SHBrowseForFolder(&bi)) != NULL ) &&
( SHGetPathFromIDList(lpil, szPath) && szPath[0] && DirectoryExists(szPath) ) )
{
lstrcpy(lpDirBuf, szPath);
return TRUE;
}
return FALSE;
}
BOOL BrowseForFile(HWND hwnd, INT iTitle, INT iFilter, INT iExtension, LPTSTR lpFileName, DWORD cbFileName, LPTSTR lpDirectory, DWORD dwFlags)
{
OPENFILENAME ofn = {sizeof(ofn)};
TCHAR szTitle[256] = NULLSTR,
szFilter[256] = NULLSTR,
szExtension[256] = NULLSTR,
szFullPath[MAX_PATH] = NULLSTR;
LPTSTR lpSearch,
lpNext,
lpFilePart = NULL;
// Load all the strings we need for the open file structure.
//
if ( iTitle )
LoadString(NULL, iTitle, szTitle, sizeof(szTitle) / sizeof(TCHAR));
if ( iFilter )
LoadString(NULL, iFilter, szFilter, sizeof(szFilter) / sizeof(TCHAR));
if ( iExtension )
LoadString(NULL, iExtension, szExtension, sizeof(szExtension) / sizeof(TCHAR));
// Replace all the | in the filter string with \0.
//
lpSearch = szFilter;
while ( *lpSearch )
{
lpNext = CharNext(lpSearch);
if ( *lpSearch == _T('|') )
*lpSearch = NULLCHR;
lpSearch = lpNext;
}
// Figure out what the default directory and file will be.
//
if ( *lpFileName && GetFullPathName(lpFileName, STRSIZE(szFullPath), szFullPath, &lpFilePart) && szFullPath[0] )
{
// If the whole path is a directory, there is no file part.
//
if ( DirectoryExists(szFullPath) )
lpFilePart = NULL;
// Copy off the file name part.
//
if ( lpFilePart && ( (DWORD) lstrlen(lpFilePart) < cbFileName ) )
lstrcpy(lpFileName, lpFilePart);
else
*lpFileName = NULLCHR;
// Now chop off the file name so we are left with the directory.
//
if ( lpFilePart )
*lpFilePart = NULLCHR;
}
else
{
// No cool default directory or file name to use, so we use the
// directory passed in and no file name.
//
*lpFileName = NULLCHR;
szFullPath[0] = NULLCHR;
}
// Setup the open file struture.
//
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = szFilter[0] ? szFilter : NULL;
ofn.nFilterIndex = szFilter[0] ? 1 : 0;
ofn.lpstrFile = lpFileName;
ofn.nMaxFile = cbFileName;
ofn.lpstrInitialDir = ( szFullPath[0] && DirectoryExists(szFullPath) ) ? szFullPath : lpDirectory;
ofn.lpstrTitle = szTitle[0] ? szTitle : NULL;
ofn.lpstrDefExt = szExtension[0] ? szExtension : NULL;
ofn.Flags = dwFlags ? dwFlags : (OFN_HIDEREADONLY | OFN_FILEMUSTEXIST);
// Make sure the buffer is zero'ed out if the function failes.
//
if ( !GetOpenFileName(&ofn) )
*lpFileName = NULLCHR;
// Return true only if we are passing back a file name.
//
return ( *lpFileName != NULLCHR );
}
//
// Internal Functions:
//
static DWORD CopyDirectoryEngine(HWND hwnd, HANDLE hEvent, LPCTSTR lpSrc, LPCTSTR lpDst, BOOL fCount)
{
WIN32_FIND_DATA FileFound;
HANDLE hFile;
BOOL bReturn = TRUE;
DWORD dwReturn = 0;
TCHAR szDst[MAX_PATH];
LPTSTR lpFileName,
lpSearch = NULL;
// If a source directory was passed in, set the current directory
// to it because that is we we are going to search for files.
//
if ( lpSrc )
{
// If the source isn't a directory, it is a file or file pattern we are
// copying.
//
if ( DirectoryExists(lpSrc) )
{
// Now make sure we set the current directory to the source directory.
//
bReturn = SetCurrentDirectory(lpSrc);
}
else
{
// We have to separate the path from the file or file pattern.
//
if ( lpSearch = _tcsrchr(lpSrc, CHR_BACKSLASH) )
{
// Set the current directory to the path part of the source buffer.
//
TCHAR szPath[MAX_PATH];
lstrcpyn(szPath, lpSrc, 1 + (int)(lpSearch - lpSrc));
if ( *(lpSearch = CharNext(lpSearch)) == NULLCHR )
lpSearch = NULL;
bReturn = SetCurrentDirectory(szPath);
}
else
lpSearch = (LPTSTR) lpSrc;
}
}
// Make sure the source directory existed, create the
// destination directory, and make sure it exists also.
//
if ( bReturn && ( fCount || ( bReturn = CreatePath(lpDst) ) ) )
{
// Setup the destination buffer with a pointer to the
// end of the path.
//
if ( !fCount )
{
lstrcpy(szDst, lpDst);
AddPath(szDst, NULLSTR);
lpFileName = szDst + lstrlen(szDst);
}
// Process all the files and directories in the directory passed in.
//
if ( (hFile = FindFirstFile(lpSearch ? lpSearch : _T("*"), &FileFound)) != INVALID_HANDLE_VALUE )
{
do
{
// Create the full path destination name.
//
if ( !fCount )
lstrcpy(lpFileName, FileFound.cFileName);
// First check to see if this is a file (not a directory).
//
if ( !( FileFound.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
{
// Copy the file from the source to the destination.
//
fCount ? (dwReturn++) : (bReturn = CopyResetFile(FileFound.cFileName, szDst));
// Increase the progress bar. This is the only difference between
// CopyDirectroy() and CopyDirectoryProgress().
//
if ( hwnd )
SendMessage(hwnd, PBM_STEPIT, 0, 0);
}
// Otherwise, make sure the directory is not "." or "..".
//
else if ( lstrcmp(FileFound.cFileName, _T(".")) &&
lstrcmp(FileFound.cFileName, _T("..")) &&
SetCurrentDirectory(FileFound.cFileName) )
{
// Process all the files there.
//
DWORD dwBuffer = CopyDirectoryEngine(hwnd, hEvent, NULL, szDst, fCount);
fCount ? (dwReturn += dwBuffer) : (bReturn = (dwBuffer != 0));
SetCurrentDirectory(_T(".."));
}
// Check event to see if the user canceled.
//
if ( hEvent && ( WaitForSingleObject(hEvent, 0) != WAIT_TIMEOUT ) )
bReturn = FALSE;
}
while ( bReturn && FindNextFile(hFile, &FileFound) );
FindClose(hFile);
}
}
return bReturn ? (fCount ? dwReturn : 1) : 0;
}
static CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
TCHAR szPathName[MAX_PATH];
LPTSTR lpszData = (LPTSTR) lpData;
switch ( uMsg )
{
case BFFM_INITIALIZED:
// Initialize the dialog with the OK button and current directory.
//
if ( lpszData && *lpszData )
{
LPTSTR lpEnd;
// Make sure there is a trailing backslash so that a drive passed in
// works (like c:).
//
szPathName[0] = NULLCHR;
if ( GetFullPathName(lpszData, STRSIZE(szPathName), szPathName, NULL) && szPathName[0] )
lstrcpy(lpszData, szPathName);
// For some dumb reason, the BFFM_SETSELECTION doesn't like it when there
// is a trailing backslash on the path.
//
if ( ( lstrlen(lpszData) > 3 ) &&
( lpEnd = CharPrev(lpszData, lpszData + lstrlen(lpszData)) ) &&
( *lpEnd == CHR_BACKSLASH ) )
{
*lpEnd = NULLCHR;
}
// Update the tree with the default dir and enable/disable the OK button
// if there is a valid directory.
//
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
SendMessage(hwnd, BFFM_ENABLEOK, 0, (DirectoryExists(lpszData) != 0));
}
else
SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
break;
case BFFM_SELCHANGED:
// Turn the id into a folder name.
//
szPathName[0] = NULLCHR;
if ( SHGetPathFromIDList((LPITEMIDLIST) lParam, szPathName) && szPathName[0] && DirectoryExists(szPathName) )
{
SetDlgItemText(hwnd, IDC_BROWSE_EDIT, szPathName);
SendMessage(hwnd, BFFM_ENABLEOK, 0, 1);
}
else
SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
break;
case BFFM_VALIDATEFAILED:
SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
return TRUE;
}
return 0;
}
BOOL CreateUnicodeFile(LPCTSTR lpFile)
{
HANDLE hFile;
DWORD dwWritten = 0;
WCHAR cHeader = 0xFEFF;
BOOL bReturn = FALSE;
// If we have a file name and the file does not exist, attempt to create
//
if ( lpFile && *lpFile && !FileExists(lpFile))
{
if ( (hFile = CreateFile(lpFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
{
WriteFile(hFile, &cHeader, sizeof(cHeader), &dwWritten, NULL);
CloseHandle(hFile);
bReturn = TRUE;
}
}
return bReturn;
}