windows-nt/Source/XPSP1/NT/admin/wizards/shrwiz/wizdir.cpp

841 lines
24 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// WizDir.cpp : implementation file
//
#include "stdafx.h"
#include "shrwiz.h"
#include "WizDir.h"
#include <shlobj.h>
#include "icanon.h"
#include <macfile.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
void OpenBrowseDialog(IN HWND hwndParent, IN LPCTSTR lpszComputer, OUT LPTSTR lpszDir);
BOOL
IsValidLocalAbsolutePath(
IN LPCTSTR lpszPath
);
BOOL
VerifyDirectory(
IN LPCTSTR lpszServer,
IN LPCTSTR lpszDir
);
/////////////////////////////////////////////////////////////////////////////
// CWizFolder property page
IMPLEMENT_DYNCREATE(CWizFolder, CPropertyPage)
CWizFolder::CWizFolder() : CPropertyPage(CWizFolder::IDD)
{
//{{AFX_DATA_INIT(CWizFolder)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CWizFolder::~CWizFolder()
{
}
void CWizFolder::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CWizFolder)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CWizFolder, CPropertyPage)
//{{AFX_MSG_MAP(CWizFolder)
ON_BN_CLICKED(IDC_BROWSEFOLDER, OnBrowsefolder)
ON_BN_CLICKED(IDC_CHECK_MAC, OnCheckMac)
ON_BN_CLICKED(IDC_CHECK_MS, OnCheckMs)
ON_BN_CLICKED(IDC_CHECK_NETWARE, OnCheckNetware)
ON_EN_CHANGE(IDC_SHARENAME, OnChangeSharename)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_SETPAGEFOCUS, OnSetPageFocus)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CWizFolder message handlers
#define SHARE_NAME_LIMIT NNLEN
#define SFM_SHARE_NAME_LIMIT AFP_VOLNAME_LEN
#define SHARE_DESCRIPTION_LIMIT MAXCOMMENTSZ
BOOL CWizFolder::OnInitDialog()
{
CPropertyPage::OnInitDialog();
GetDlgItem(IDC_FOLDER)->SendMessage(EM_LIMITTEXT, _MAX_DIR - 1, 0);
GetDlgItem(IDC_SHARENAME)->SendMessage(EM_LIMITTEXT, SHARE_NAME_LIMIT, 0);
GetDlgItem(IDC_MACSHARENAME)->SendMessage(EM_LIMITTEXT, SFM_SHARE_NAME_LIMIT, 0);
GetDlgItem(IDC_SHAREDESCRIPTION)->SendMessage(EM_LIMITTEXT, SHARE_DESCRIPTION_LIMIT, 0);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
LRESULT CWizFolder::OnWizardNext()
{
CWaitCursor wait;
Reset(); // init all related place holders
CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
pApp->m_bSMB = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MS))->GetCheck());
pApp->m_bFPNW = (1 == ((CButton *)GetDlgItem(IDC_CHECK_NETWARE))->GetCheck());
pApp->m_bSFM = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck());
if (!pApp->m_bSMB && !pApp->m_bFPNW && !pApp->m_bSFM)
{
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_CLIENT_REQUIRED);
GetDlgItem(IDC_CHECK_MS)->SetFocus();
return -1;
}
CString cstrFolder;
GetDlgItemText(IDC_FOLDER, cstrFolder);
cstrFolder.TrimLeft();
cstrFolder.TrimRight();
if (cstrFolder.IsEmpty())
{
CString cstrField;
cstrField.LoadString(IDS_FOLDER_LABEL);
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_TEXT_REQUIRED, cstrField);
GetDlgItem(IDC_FOLDER)->SetFocus();
return -1;
}
// Removing the ending backslash, otherwise, GetFileAttribute/NetShareAdd will fail.
if (!IsValidLocalAbsolutePath(cstrFolder))
{
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_INVALID_FOLDER);
GetDlgItem(IDC_FOLDER)->SetFocus();
return -1;
} else
{
int iLen = cstrFolder.GetLength();
if (cstrFolder[iLen - 1] == _T('\\') &&
cstrFolder[iLen - 2] != _T(':'))
cstrFolder.SetAt(iLen - 1, _T('\0'));
}
if (!VerifyDirectory(pApp->m_cstrTargetComputer, cstrFolder))
{
GetDlgItem(IDC_FOLDER)->SetFocus();
return -1;
}
pApp->m_cstrFolder = cstrFolder;
DWORD dwStatus = 0;
if (pApp->m_bSMB || pApp->m_bFPNW)
{
CString cstrShareName;
GetDlgItemText(IDC_SHARENAME, cstrShareName);
cstrShareName.TrimLeft();
cstrShareName.TrimRight();
if (cstrShareName.IsEmpty())
{
CString cstrField;
cstrField.LoadString(IDS_SHARENAME_LABEL);
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_TEXT_REQUIRED, cstrField);
GetDlgItem(IDC_SHARENAME)->SetFocus();
return -1;
}
dwStatus = I_NetNameValidate(
const_cast<LPTSTR>(static_cast<LPCTSTR>(pApp->m_cstrTargetComputer)),
const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrShareName)),
NAMETYPE_SHARE,
0);
if (dwStatus)
{
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_INVALID_SHARENAME, cstrShareName);
GetDlgItem(IDC_SHARENAME)->SetFocus();
return -1;
}
if (pApp->m_bSMB && ShareNameExists(cstrShareName, CLIENT_TYPE_SMB) ||
pApp->m_bFPNW && ShareNameExists(cstrShareName, CLIENT_TYPE_FPNW))
{
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_DUPLICATE_SHARENAME, cstrShareName);
GetDlgItem(IDC_SHARENAME)->SetFocus();
return -1;
}
pApp->m_cstrShareName = cstrShareName;
}
if (pApp->m_bSMB)
{
CString cstrShareDescription;
GetDlgItemText(IDC_SHAREDESCRIPTION, cstrShareDescription);
cstrShareDescription.TrimLeft();
cstrShareDescription.TrimRight();
pApp->m_cstrShareDescription = cstrShareDescription;
}
if (pApp->m_bSFM)
{
CString cstrMACShareName;
GetDlgItemText(IDC_MACSHARENAME, cstrMACShareName);
cstrMACShareName.TrimLeft();
cstrMACShareName.TrimRight();
if (cstrMACShareName.IsEmpty())
{
CString cstrField;
cstrField.LoadString(IDS_MACSHARENAME_LABEL);
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_TEXT_REQUIRED, cstrField);
GetDlgItem(IDC_MACSHARENAME)->SetFocus();
return -1;
} else
{
dwStatus = I_NetNameValidate(
const_cast<LPTSTR>(static_cast<LPCTSTR>(pApp->m_cstrTargetComputer)),
const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrMACShareName)),
NAMETYPE_SHARE,
0);
if (dwStatus)
{
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_INVALID_SHARENAME, cstrMACShareName);
GetDlgItem(IDC_MACSHARENAME)->SetFocus();
return -1;
}
}
if (ShareNameExists(cstrMACShareName, CLIENT_TYPE_SFM))
{
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_DUPLICATE_SHARENAME, cstrMACShareName);
GetDlgItem(IDC_MACSHARENAME)->SetFocus();
return -1;
}
pApp->m_cstrMACShareName = cstrMACShareName;
}
pApp->m_bNextButtonClicked = TRUE;
return CPropertyPage::OnWizardNext();
}
void CWizFolder::OnBrowsefolder()
{
CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
LPTSTR lpszComputer = const_cast<LPTSTR>(static_cast<LPCTSTR>(pApp->m_cstrTargetComputer));
CString cstrPath;
TCHAR szDir[MAX_PATH * 2] = _T(""); // double the size in case the remote path is itself close to MAX_PATH
OpenBrowseDialog(m_hWnd, lpszComputer, szDir);
if (szDir[0])
{
if (pApp->m_bIsLocal)
cstrPath = szDir;
else
{ // szDir is in the form of \\server\share or \\server\share\path....
LPTSTR pShare = _tcschr(szDir + 2, _T('\\'));
pShare++;
LPTSTR pLeftOver = _tcschr(pShare, _T('\\'));
if (pLeftOver && *pLeftOver)
*pLeftOver++ = _T('\0');
SHARE_INFO_2 *psi = NULL;
if (NERR_Success == NetShareGetInfo(lpszComputer, pShare, 2, (LPBYTE *)&psi))
{
cstrPath = psi->shi2_path;
if (pLeftOver && *pLeftOver)
{
if (_T('\\') != cstrPath.Right(1))
cstrPath += _T('\\');
cstrPath += pLeftOver;
}
NetApiBufferFree(psi);
}
}
}
if (!cstrPath.IsEmpty())
SetDlgItemText(IDC_FOLDER, cstrPath);
}
void CWizFolder::OnCheckClient()
{
BOOL bSMB = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MS))->GetCheck());
BOOL bFPNW = (1 == ((CButton *)GetDlgItem(IDC_CHECK_NETWARE))->GetCheck());
BOOL bSFM = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck());
GetDlgItem(IDC_SHARENAME)->EnableWindow(bSMB || bFPNW);
if (!bSMB && !bFPNW)
SetDlgItemText(IDC_SHARENAME, _T(""));
GetDlgItem(IDC_SHAREDESCRIPTION)->EnableWindow(bSMB);
if (!bSMB)
SetDlgItemText(IDC_SHAREDESCRIPTION, _T(""));
GetDlgItem(IDC_MACSHARENAME)->EnableWindow(bSFM);
if (!bSFM)
SetDlgItemText(IDC_MACSHARENAME, _T(""));
}
void CWizFolder::OnCheckMac()
{
OnCheckClient();
if (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck())
{
CString cstrShareName;
GetDlgItemText(IDC_SHARENAME, cstrShareName);
SetDlgItemText(IDC_MACSHARENAME, cstrShareName.Left(SFM_SHARE_NAME_LIMIT));
}
}
void CWizFolder::OnCheckMs()
{
OnCheckClient();
}
void CWizFolder::OnCheckNetware()
{
OnCheckClient();
}
void CWizFolder::OnChangeSharename()
{
BOOL bSMB = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MS))->GetCheck());
BOOL bFPNW = (1 == ((CButton *)GetDlgItem(IDC_CHECK_NETWARE))->GetCheck());
BOOL bSFM = (1 == ((CButton *)GetDlgItem(IDC_CHECK_MAC))->GetCheck());
if ((bSMB || bFPNW) && bSFM)
{
CString cstrShareName;
GetDlgItemText(IDC_SHARENAME, cstrShareName);
SetDlgItemText(IDC_MACSHARENAME, cstrShareName.Left(SFM_SHARE_NAME_LIMIT));
}
}
BOOL CWizFolder::OnSetActive()
{
((CPropertySheet *)GetParent())->SetWizardButtons(PSWIZB_NEXT);
CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
if (pApp->m_bNextButtonClicked)
{
SetDlgItemText(IDC_COMPUTER, pApp->m_cstrTargetComputer);
SetDlgItemText(IDC_FOLDER, pApp->m_cstrFolder);
SetDlgItemText(IDC_SHARENAME, pApp->m_cstrShareName);
SetDlgItemText(IDC_SHAREDESCRIPTION, pApp->m_cstrShareDescription);
SetDlgItemText(IDC_SHARENAME_MAC, pApp->m_cstrMACShareName);
CheckDlgButton(IDC_CHECK_MS, 1);
CheckDlgButton(IDC_CHECK_NETWARE, 0);
CheckDlgButton(IDC_CHECK_MAC, 0);
OnCheckMs();
GetDlgItem(IDC_CHECK_NETWARE)->EnableWindow(pApp->m_bServerFPNW);
GetDlgItem(IDC_CHECK_MAC)->EnableWindow(pApp->m_bServerSFM);
GetDlgItem(IDC_MACSHARENAME_STATIC)->ShowWindow(pApp->m_bServerSFM ? SW_SHOW : SW_HIDE);
GetDlgItem(IDC_SHARENAME_MAC)->ShowWindow(pApp->m_bServerSFM ? SW_SHOW : SW_HIDE);
if (!(pApp->m_bServerFPNW) && !(pApp->m_bServerSFM))
{
// hide the whole group if only SMB
GetDlgItem(IDC_CLIENTS_GROUP)->ShowWindow(SW_HIDE);
GetDlgItem(IDC_CHECK_MS)->EnableWindow(FALSE);
GetDlgItem(IDC_CHECK_MS)->ShowWindow(SW_HIDE);
GetDlgItem(IDC_CHECK_NETWARE)->ShowWindow(SW_HIDE);
GetDlgItem(IDC_CHECK_MAC)->ShowWindow(SW_HIDE);
} else
{
GetDlgItem(IDC_CLIENTS_GROUP)->ShowWindow(SW_SHOW);
GetDlgItem(IDC_CHECK_MS)->EnableWindow(TRUE);
GetDlgItem(IDC_CHECK_MS)->ShowWindow(SW_SHOW);
GetDlgItem(IDC_CHECK_NETWARE)->ShowWindow(SW_SHOW);
GetDlgItem(IDC_CHECK_MAC)->ShowWindow(SW_SHOW);
}
} else
{
CheckDlgButton(IDC_CHECK_MS, pApp->m_bSMB);
CheckDlgButton(IDC_CHECK_NETWARE, pApp->m_bFPNW);
CheckDlgButton(IDC_CHECK_MAC, pApp->m_bSFM);
OnCheckClient();
}
BOOL fRet = CPropertyPage::OnSetActive();
PostMessage(WM_SETPAGEFOCUS, 0, 0L);
return fRet;
}
//
// Q148388 How to Change Default Control Focus on CPropertyPage
//
LRESULT CWizFolder::OnSetPageFocus(WPARAM wParam, LPARAM lParam)
{
GetDlgItem(IDC_FOLDER)->SetFocus();
return 0;
}
BOOL CWizFolder::ShareNameExists(IN LPCTSTR lpszShareName, IN CLIENT_TYPE iType)
{
BOOL bReturn = FALSE;
CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
switch (iType)
{
case CLIENT_TYPE_SMB:
{
bReturn = SMBShareNameExists(pApp->m_cstrTargetComputer, lpszShareName);
break;
}
case CLIENT_TYPE_FPNW:
{
ASSERT(pApp->m_hLibFPNW);
bReturn = FPNWShareNameExists(pApp->m_cstrTargetComputer, lpszShareName, pApp->m_hLibFPNW);
break;
}
case CLIENT_TYPE_SFM:
{
ASSERT(pApp->m_hLibSFM);
bReturn = SFMShareNameExists(pApp->m_cstrTargetComputer, lpszShareName, pApp->m_hLibSFM);
break;
}
default:
break;
}
return bReturn;
}
void CWizFolder::Reset()
{
CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
pApp->m_cstrFolder.Empty();
pApp->m_cstrShareName.Empty();
pApp->m_cstrShareDescription.Empty();
pApp->m_cstrMACShareName.Empty();
pApp->m_bSMB = FALSE;
pApp->m_bFPNW = FALSE;
pApp->m_bSFM = FALSE;
}
////////////////////////////////////////////////////////////
// OpenBrowseDialog
//
//
// 7/11/2001 LinanT bug#426953
// Since connection made by Terminal Service may bring some client side resources
// (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
// the OK button when browsing to a non-local folder. We don't have this problem
// when browsing a remote machine.
//
typedef struct _LOCAL_DISKS
{
LPTSTR pszDisks;
DWORD dwNumOfDisks;
} LOCAL_DISKS;
#define DISK_ENTRY_LENGTH 3 // Drive letter, colon, NULL
#define DISK_NAME_LENGTH 2 // Drive letter, colon
BOOL InDiskList(IN LPCTSTR pszDir, IN LOCAL_DISKS *pDisks)
{
if (!pszDir || !pDisks)
return FALSE;
DWORD i = 0;
PTSTR pszDisk = pDisks->pszDisks;
for (; pszDisk && i < pDisks->dwNumOfDisks; i++)
{
if (!_tcsnicmp(pszDisk, pszDir, DISK_NAME_LENGTH))
return TRUE;
pszDisk += DISK_ENTRY_LENGTH;
}
return FALSE;
}
int CALLBACK
BrowseCallbackProc(
IN HWND hwnd,
IN UINT uMsg,
IN LPARAM lp,
IN LPARAM pData
)
{
switch(uMsg) {
case BFFM_SELCHANGED:
{
// enable the OK button if the selected path is local to that computer.
BOOL bEnableOK = FALSE;
TCHAR szDir[MAX_PATH];
if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
{
if (pData)
{
// we're looking at a local computer, verify if szDir is on a local disk
bEnableOK = InDiskList(szDir, (LOCAL_DISKS *)pData);
} else
{
// no such problem when browsing at a remote computer, always enable OK button.
bEnableOK = TRUE;
}
}
SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bEnableOK);
break;
}
default:
break;
}
return 0;
}
void OpenBrowseDialog(IN HWND hwndParent, IN LPCTSTR lpszComputer, OUT LPTSTR lpszDir)
{
ASSERT(lpszComputer && *lpszComputer);
HRESULT hr = S_OK;
LOCAL_DISKS localDisks = {0};
CString cstrComputer;
if (*lpszComputer != _T('\\') || *(lpszComputer + 1) != _T('\\'))
{
cstrComputer = _T("\\\\");
cstrComputer += lpszComputer;
} else
{
cstrComputer = lpszComputer;
}
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
LPMALLOC pMalloc;
hr = SHGetMalloc(&pMalloc);
if (SUCCEEDED(hr))
{
LPSHELLFOLDER pDesktopFolder;
hr = SHGetDesktopFolder(&pDesktopFolder);
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidlRoot;
if (IsLocalComputer(lpszComputer))
{
hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlRoot);
if (SUCCEEDED(hr))
{
//
// 7/11/2001 LinanT bug#426953
// Since connection made by Terminal Service may bring some client side resources
// (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
// the OK button when browsing to a non-local folder. We don't have this problem
// when browsing a remote machine.
//
//
// Get an array of local disk names, this information is later used
// in the browse dialog to disable OK button if non-local path is selected.
//
DWORD dwTotalEntries = 0;
DWORD nStatus = NetServerDiskEnum(
NULL, // local computer
0, // level must be zero
(LPBYTE *)&(localDisks.pszDisks),
-1, // dwPrefMaxLen,
&(localDisks.dwNumOfDisks),
&dwTotalEntries,
NULL);
if (NERR_Success != nStatus)
{
hr = HRESULT_FROM_WIN32(nStatus);
}
}
} else
{
ULONG chEaten = 0;
hr = pDesktopFolder->ParseDisplayName(NULL, NULL,
const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrComputer)),
&chEaten, &pidlRoot, NULL);
}
if (SUCCEEDED(hr))
{
CString cstrLabel;
cstrLabel.LoadString(IDS_BROWSE_FOLDER);
BROWSEINFO bi;
ZeroMemory(&bi,sizeof(bi));
bi.hwndOwner = hwndParent;
bi.pszDisplayName = 0;
bi.lpszTitle = cstrLabel;
bi.pidlRoot = pidlRoot;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_SHAREABLE | BIF_USENEWUI;
bi.lpfn = BrowseCallbackProc;
if (localDisks.pszDisks)
bi.lParam = (LPARAM)&localDisks; // pass the structure to the browse dialog
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
if (pidl) {
SHGetPathFromIDList(pidl, lpszDir);
pMalloc->Free(pidl);
}
pMalloc->Free(pidlRoot);
}
pDesktopFolder->Release();
}
pMalloc->Release();
}
CoUninitialize();
}
if (localDisks.pszDisks)
NetApiBufferFree(localDisks.pszDisks);
if (FAILED(hr))
DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONWARNING, hr, IDS_CANNOT_BROWSE_FOLDER, lpszComputer);
}
BOOL
IsValidLocalAbsolutePath(
IN LPCTSTR lpszPath
)
{
DWORD dwPathType = 0;
DWORD dwStatus = I_NetPathType(
NULL,
const_cast<LPTSTR>(lpszPath),
&dwPathType,
0);
if (dwStatus)
return FALSE;
if (dwPathType ^ ITYPE_PATH_ABSD)
return FALSE;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: IsAnExistingFolder
//
// Synopsis: Check if pszPath is pointing at an existing folder.
//
// S_OK: The specified path points to an existing folder.
// S_FALSE: The specified path doesn't point to an existing folder.
// hr: Failed to get info on the specified path, or
// the path exists but doesn't point to a folder.
// The function reports error msg for both failures if desired.
//----------------------------------------------------------------------------
HRESULT
IsAnExistingFolder(
IN HWND hwnd,
IN LPCTSTR pszPath,
IN BOOL bDisplayErrorMsg
)
{
if (!hwnd)
hwnd = GetActiveWindow();
HRESULT hr = S_OK;
DWORD dwRet = GetFileAttributes(pszPath);
if (-1 == dwRet)
{
DWORD dwErr = GetLastError();
if (ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr)
{
// the specified path doesn't exist
hr = S_FALSE;
}
else
{
hr = HRESULT_FROM_WIN32(dwErr);
if (ERROR_NOT_READY == dwErr)
{
// fix for bug#358033/408803: ignore errors from GetFileAttributes in order to
// allow the root of movable drives to be shared without media inserted in.
int len = _tcslen(pszPath);
if (len > 3 &&
pszPath[len - 1] == _T('\\') &&
pszPath[len - 2] == _T(':'))
{
// pszPath is pointing at the root of the drive, ignore the error
hr = S_OK;
}
}
if ( FAILED(hr) && bDisplayErrorMsg )
DisplayMessageBox(hwnd, MB_OK, dwErr, IDS_FAILED_TO_GETINFO_FOLDER, pszPath);
}
} else if ( 0 == (dwRet & FILE_ATTRIBUTE_DIRECTORY) )
{
// the specified path is not pointing to a folder
if (bDisplayErrorMsg)
DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, 0, IDS_PATH_NOT_FOLDER, pszPath);
hr = E_FAIL;
}
return hr;
}
// create the directories layer by layer
HRESULT
CreateLayeredDirectory(
IN LPCTSTR lpszServer,
IN LPCTSTR lpszDir
)
{
ASSERT(IsValidLocalAbsolutePath(lpszDir));
BOOL bLocal = IsLocalComputer(lpszServer);
CString cstrFullPath;
GetFullPath(lpszServer, lpszDir, cstrFullPath);
// add prefix to skip the CreateDirectory limit of 248 chars
CString cstrFullPathNoParsing = (bLocal ? _T("\\\\?\\") : _T("\\\\?\\UNC"));
cstrFullPathNoParsing += (bLocal ? cstrFullPath : cstrFullPath.Right(cstrFullPath.GetLength() - 1));
HRESULT hr = IsAnExistingFolder(NULL, cstrFullPathNoParsing, FALSE);
ASSERT(S_FALSE == hr);
LPTSTR pch = _tcschr(cstrFullPathNoParsing, (bLocal ? _T(':') : _T('$')));
ASSERT(pch);
// pszPath holds "\\?\C:\a\b\c\d" or "\\?\UNC\server\share\a\b\c\d"
// pszLeft holds "a\b\c\d"
LPTSTR pszPath = const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrFullPathNoParsing));
LPTSTR pszLeft = pch + 2;
LPTSTR pszRight = NULL;
ASSERT(pszLeft && *pszLeft);
//
// this loop will find out the 1st non-existing sub-dir to create, and
// the rest of non-existing sub-dirs
//
while (pch = _tcsrchr(pszLeft, _T('\\'))) // backwards search for _T('\\')
{
*pch = _T('\0');
hr = IsAnExistingFolder(NULL, pszPath, TRUE);
if (FAILED(hr))
return S_FALSE; // errormsg has already been reported by IsAnExistingFolder().
if (S_OK == hr)
{
//
// pszPath is pointing to the parent dir of the 1st non-existing sub-dir.
// Once we restore the _T('\\'), pszPath will point at the 1st non-existing subdir.
//
*pch = _T('\\');
break;
} else
{
//
// pszPath is pointing to a non-existing folder, continue with the loop.
//
if (pszRight)
*(pszRight - 1) = _T('\\');
pszRight = pch + 1;
}
}
// We're ready to create directories:
// pszPath points to the 1st non-existing dir, e.g., "C:\a\b" or "\\server\share\a\b"
// pszRight points to the rest of non-existing sub dirs, e.g., "c\d"
//
do
{
if (!CreateDirectory(pszPath, NULL))
return HRESULT_FROM_WIN32(GetLastError());
if (!pszRight || !*pszRight)
break;
*(pszRight - 1) = _T('\\');
if (pch = _tcschr(pszRight, _T('\\'))) // forward search for _T('\\')
{
*pch = _T('\0');
pszRight = pch + 1;
} else
{
pszRight = NULL;
}
} while (1);
return S_OK;
}
BOOL
VerifyDirectory(
IN LPCTSTR lpszServer,
IN LPCTSTR lpszDir
)
{
ASSERT(lpszDir && *lpszDir);
ASSERT(IsValidLocalAbsolutePath(lpszDir));
HWND hwnd = ::GetActiveWindow();
BOOL bLocal = IsLocalComputer(lpszServer);
HRESULT hr = VerifyDriveLetter(lpszServer, lpszDir);
if (FAILED(hr))
{ /*
// fix for bug#351212: ignore error and leave permission checkings to NetShareAdd apis
DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszDir);
return FALSE;
*/
hr = S_OK;
} else if (S_OK != hr)
{
DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, 0, IDS_INVALID_DRIVE, lpszDir);
return FALSE;
}
if (!bLocal)
{
hr = IsAdminShare(lpszServer, lpszDir);
if (FAILED(hr))
{
DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszDir);
return FALSE;
} else if (S_OK != hr)
{
// there is no matching $ shares, hence, no need to call GetFileAttribute, CreateDirectory,
// assume lpszDir points to an existing directory
return TRUE;
}
}
CString cstrPath;
GetFullPath(lpszServer, lpszDir, cstrPath);
// add prefix to skip the GetFileAttribute limit when the path is on a remote server
CString cstrPathNoParsing = (bLocal ? _T("\\\\?\\") : _T("\\\\?\\UNC"));
cstrPathNoParsing += (bLocal ? cstrPath : cstrPath.Right(cstrPath.GetLength() - 1));
hr = IsAnExistingFolder(hwnd, cstrPathNoParsing, TRUE); // error has already been reported.
if (FAILED(hr) || S_OK == hr)
return (S_OK == hr);
if ( IDYES != DisplayMessageBox(hwnd, MB_YESNO|MB_ICONQUESTION, 0, IDS_CREATE_NEW_DIR, cstrPath) )
return FALSE;
// create the directories layer by layer
hr = CreateLayeredDirectory(lpszServer, lpszDir);
if (FAILED(hr))
DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, hr, IDS_FAILED_TO_CREATE_NEW_DIR, cstrPath);
return (S_OK == hr);
}