Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

720 lines
21 KiB

  1. // WizDir.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "WizDir.h"
  5. #include <shlobj.h>
  6. #include "icanon.h"
  7. #include <macfile.h>
  8. #ifdef _DEBUG
  9. #define new DEBUG_NEW
  10. #undef THIS_FILE
  11. static char THIS_FILE[] = __FILE__;
  12. #endif
  13. void OpenBrowseDialog(IN HWND hwndParent, IN LPCTSTR lpszComputer, OUT LPTSTR lpszDir);
  14. BOOL
  15. IsValidLocalAbsolutePath(
  16. IN LPCTSTR lpszPath
  17. );
  18. BOOL
  19. VerifyDirectory(
  20. IN LPCTSTR lpszServer,
  21. IN LPCTSTR lpszDir
  22. );
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CWizFolder property page
  25. IMPLEMENT_DYNCREATE(CWizFolder, CPropertyPageEx)
  26. CWizFolder::CWizFolder() : CPropertyPageEx(CWizFolder::IDD, 0, IDS_HEADERTITLE_FOLDER, IDS_HEADERSUBTITLE_FOLDER)
  27. {
  28. //{{AFX_DATA_INIT(CWizFolder)
  29. // NOTE: the ClassWizard will add member initialization here
  30. //}}AFX_DATA_INIT
  31. m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  32. }
  33. CWizFolder::~CWizFolder()
  34. {
  35. }
  36. void CWizFolder::DoDataExchange(CDataExchange* pDX)
  37. {
  38. CPropertyPageEx::DoDataExchange(pDX);
  39. //{{AFX_DATA_MAP(CWizFolder)
  40. // NOTE: the ClassWizard will add DDX and DDV calls here
  41. //}}AFX_DATA_MAP
  42. }
  43. BEGIN_MESSAGE_MAP(CWizFolder, CPropertyPageEx)
  44. //{{AFX_MSG_MAP(CWizFolder)
  45. ON_BN_CLICKED(IDC_BROWSEFOLDER, OnBrowsefolder)
  46. //}}AFX_MSG_MAP
  47. ON_MESSAGE(WM_SETPAGEFOCUS, OnSetPageFocus)
  48. END_MESSAGE_MAP()
  49. /////////////////////////////////////////////////////////////////////////////
  50. // CWizFolder message handlers
  51. BOOL CWizFolder::OnInitDialog()
  52. {
  53. CPropertyPageEx::OnInitDialog();
  54. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  55. SetDlgItemText(IDC_COMPUTER, pApp->m_cstrTargetComputer);
  56. GetDlgItem(IDC_FOLDER)->SendMessage(EM_LIMITTEXT, _MAX_DIR - 1, 0);
  57. return TRUE; // return TRUE unless you set the focus to a control
  58. // EXCEPTION: OCX Property Pages should return FALSE
  59. }
  60. LRESULT CWizFolder::OnWizardNext()
  61. {
  62. CWaitCursor wait;
  63. Reset(); // init all related place holders
  64. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  65. CString cstrFolder;
  66. GetDlgItemText(IDC_FOLDER, cstrFolder);
  67. cstrFolder.TrimLeft();
  68. cstrFolder.TrimRight();
  69. if (cstrFolder.IsEmpty())
  70. {
  71. CString cstrField;
  72. cstrField.LoadString(IDS_FOLDER_LABEL);
  73. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_TEXT_REQUIRED, cstrField);
  74. GetDlgItem(IDC_FOLDER)->SetFocus();
  75. return -1;
  76. }
  77. // Removing the ending backslash, otherwise, GetFileAttribute/NetShareAdd will fail.
  78. int iLen = cstrFolder.GetLength();
  79. if (cstrFolder[iLen - 1] == _T('\\') &&
  80. cstrFolder[iLen - 2] != _T(':'))
  81. cstrFolder.SetAt(iLen - 1, _T('\0'));
  82. if (!IsValidLocalAbsolutePath(cstrFolder))
  83. {
  84. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_INVALID_FOLDER);
  85. GetDlgItem(IDC_FOLDER)->SetFocus();
  86. return -1;
  87. }
  88. //
  89. // need to exclude reserved MS-DOS device name
  90. //
  91. if (pApp->m_pfnIsDosDeviceName)
  92. {
  93. LPTSTR pszPath = const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrFolder));
  94. LPTSTR pszStart = pszPath + 3;
  95. ULONG ulRet = 0;
  96. if (*pszStart)
  97. {
  98. TCHAR *pchCurrent = NULL;
  99. TCHAR *pchNext = NULL;
  100. while (0 == (ulRet = pApp->m_pfnIsDosDeviceName(pszPath)))
  101. {
  102. pchNext = _tcsrchr(pszStart, _T('\\'));
  103. if (pchCurrent)
  104. *pchCurrent = _T('\\');
  105. if (!pchNext)
  106. break;
  107. pchCurrent = pchNext;
  108. *pchNext = _T('\0');
  109. }
  110. if (0 != ulRet && pchCurrent)
  111. *pchCurrent = _T('\\');
  112. }
  113. if (0 != ulRet)
  114. {
  115. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONERROR, 0, IDS_ISDOSDEVICENAME);
  116. GetDlgItem(IDC_FOLDER)->SetFocus();
  117. return -1;
  118. }
  119. }
  120. if (!VerifyDirectory(pApp->m_cstrTargetComputer, cstrFolder))
  121. {
  122. GetDlgItem(IDC_FOLDER)->SetFocus();
  123. return -1;
  124. }
  125. pApp->m_cstrFolder = cstrFolder;
  126. return CPropertyPageEx::OnWizardNext();
  127. }
  128. void CWizFolder::OnBrowsefolder()
  129. {
  130. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  131. LPTSTR lpszComputer = const_cast<LPTSTR>(static_cast<LPCTSTR>(pApp->m_cstrTargetComputer));
  132. CString cstrPath;
  133. TCHAR szDir[MAX_PATH * 2] = _T(""); // double the size in case the remote path is itself close to MAX_PATH
  134. OpenBrowseDialog(m_hWnd, lpszComputer, szDir);
  135. if (szDir[0])
  136. {
  137. if (pApp->m_bIsLocal)
  138. cstrPath = szDir;
  139. else
  140. { // szDir is in the form of \\server\share or \\server\share\path....
  141. LPTSTR pShare = _tcschr(szDir + 2, _T('\\'));
  142. pShare++;
  143. LPTSTR pLeftOver = _tcschr(pShare, _T('\\'));
  144. if (pLeftOver && *pLeftOver)
  145. *pLeftOver++ = _T('\0');
  146. SHARE_INFO_2 *psi = NULL;
  147. if (NERR_Success == NetShareGetInfo(lpszComputer, pShare, 2, (LPBYTE *)&psi))
  148. {
  149. cstrPath = psi->shi2_path;
  150. if (pLeftOver && *pLeftOver)
  151. {
  152. if (_T('\\') != cstrPath.Right(1))
  153. cstrPath += _T('\\');
  154. cstrPath += pLeftOver;
  155. }
  156. NetApiBufferFree(psi);
  157. }
  158. }
  159. }
  160. if (!cstrPath.IsEmpty())
  161. SetDlgItemText(IDC_FOLDER, cstrPath);
  162. }
  163. BOOL CWizFolder::OnSetActive()
  164. {
  165. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  166. ((CPropertySheet *)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
  167. if (!pApp->m_bFolderPathPageInitialized)
  168. {
  169. // in re-run case, reset button behaviors that have been introduced by the last page
  170. GetParent()->SetDlgItemText(ID_WIZNEXT, pApp->m_cstrNextButtonText);
  171. GetParent()->GetDlgItem(ID_WIZBACK)->ShowWindow(SW_SHOW);
  172. GetParent()->GetDlgItem(IDCANCEL)->EnableWindow(TRUE);
  173. SetDlgItemText(IDC_FOLDER, pApp->m_cstrFolder);
  174. pApp->m_bFolderPathPageInitialized = TRUE;
  175. }
  176. BOOL fRet = CPropertyPageEx::OnSetActive();
  177. PostMessage(WM_SETPAGEFOCUS, 0, 0L);
  178. return fRet;
  179. }
  180. //
  181. // Q148388 How to Change Default Control Focus on CPropertyPageEx
  182. //
  183. LRESULT CWizFolder::OnSetPageFocus(WPARAM wParam, LPARAM lParam)
  184. {
  185. GetDlgItem(IDC_FOLDER)->SetFocus();
  186. return 0;
  187. }
  188. void CWizFolder::Reset()
  189. {
  190. CShrwizApp *pApp = (CShrwizApp *)AfxGetApp();
  191. pApp->m_cstrFolder.Empty();
  192. }
  193. ////////////////////////////////////////////////////////////
  194. // OpenBrowseDialog
  195. //
  196. //
  197. // 7/11/2001 LinanT bug#426953
  198. // Since connection made by Terminal Service may bring some client side resources
  199. // (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
  200. // the OK button when browsing to a non-local folder. We don't have this problem
  201. // when browsing a remote machine.
  202. //
  203. #define DISK_ENTRY_LENGTH 4 // Drive letter, colon, whack, NULL
  204. #define DISK_NAME_LENGTH 2 // Drive letter, colon
  205. //
  206. // This function determines if pszDir sits on any of
  207. // the local logical drives.
  208. // Contents in pszLocalDrives look like: c:\<null>d:\<null><null>
  209. //
  210. BOOL InDiskList(IN LPCTSTR pszDir, IN TCHAR *pszLocalDrives)
  211. {
  212. if (!pszDir || !*pszDir || !pszLocalDrives || !*pszLocalDrives)
  213. return FALSE;
  214. DWORD i = 0;
  215. PTSTR pszDisk = pszLocalDrives;
  216. while (*pszDisk)
  217. {
  218. if (!_tcsnicmp(pszDisk, pszDir, DISK_NAME_LENGTH))
  219. return TRUE;
  220. pszDisk += DISK_ENTRY_LENGTH;
  221. }
  222. return FALSE;
  223. }
  224. int CALLBACK
  225. BrowseCallbackProc(
  226. IN HWND hwnd,
  227. IN UINT uMsg,
  228. IN LPARAM lp,
  229. IN LPARAM pData
  230. )
  231. {
  232. switch(uMsg) {
  233. case BFFM_SELCHANGED:
  234. {
  235. // enable the OK button if the selected path is local to that computer.
  236. BOOL bEnableOK = FALSE;
  237. TCHAR szDir[MAX_PATH];
  238. if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
  239. {
  240. if (pData)
  241. {
  242. // we're looking at a local computer, verify if szDir is on a local disk
  243. bEnableOK = InDiskList(szDir, (TCHAR *)pData);
  244. } else
  245. {
  246. // no such problem when browsing at a remote computer, always enable OK button.
  247. bEnableOK = TRUE;
  248. }
  249. }
  250. SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bEnableOK);
  251. break;
  252. }
  253. case BFFM_VALIDATEFAILED:
  254. {
  255. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, 0, IDS_BROWSE_FOLDER_INVALID);
  256. return 1;
  257. }
  258. default:
  259. break;
  260. }
  261. return 0;
  262. }
  263. //
  264. // Since the buffer contents looks like c:\<null>d:\<null><null>,
  265. // we're defining the buffer length to be 4*26+1.
  266. //
  267. #define LOGICAL_DRIVES_BUFFER_LENGTH (4 * 26 + 1)
  268. //
  269. // This function retrieves logical drive letters, filters out
  270. // remote drives, and returns drive letters on the local machine
  271. // in the form of: c:\<null>d:\<null><null>
  272. //
  273. HRESULT GetLocalLogicalDriveStrings
  274. (
  275. UINT nCharsInBuffer, // number of total tchars in the buffer, including the terminating null char
  276. PTSTR pszBuffer
  277. )
  278. {
  279. HRESULT hr = S_OK;
  280. TCHAR szLocalDrives[LOGICAL_DRIVES_BUFFER_LENGTH];
  281. DWORD nChars = GetLogicalDriveStrings(
  282. LOGICAL_DRIVES_BUFFER_LENGTH - 1, // in TCHARs, this size does NOT include the terminating null char.
  283. szLocalDrives);
  284. //
  285. // MSDN:
  286. // If the function above succeeds, the return value is the length,
  287. // in characters, of the strings copied to the buffer, not including
  288. // the terminating null character.
  289. // If the function fails, the return value is zero.
  290. //
  291. if (0 == nChars)
  292. {
  293. hr = HRESULT_FROM_WIN32(GetLastError());
  294. } else
  295. {
  296. if ((nChars + 1 ) > nCharsInBuffer)
  297. {
  298. hr = E_INVALIDARG; // treat small buffer as invalid parameter
  299. } else
  300. {
  301. ZeroMemory(pszBuffer, nCharsInBuffer * sizeof(TCHAR));
  302. PTSTR pszDrive = szLocalDrives;
  303. while (*pszDrive)
  304. {
  305. if (DRIVE_REMOTE != GetDriveType(pszDrive))
  306. {
  307. lstrcpyn(pszBuffer, pszDrive, DISK_ENTRY_LENGTH);
  308. pszBuffer += DISK_ENTRY_LENGTH;
  309. }
  310. pszDrive += DISK_ENTRY_LENGTH;
  311. }
  312. }
  313. }
  314. return hr;
  315. }
  316. void OpenBrowseDialog(IN HWND hwndParent, IN LPCTSTR lpszComputer, OUT LPTSTR lpszDir)
  317. {
  318. ASSERT(lpszComputer && *lpszComputer);
  319. HRESULT hr = S_OK;
  320. TCHAR szLocalDrives[LOGICAL_DRIVES_BUFFER_LENGTH];
  321. ZeroMemory(szLocalDrives, sizeof(szLocalDrives));
  322. CString cstrComputer;
  323. if (*lpszComputer != _T('\\') || *(lpszComputer + 1) != _T('\\'))
  324. {
  325. cstrComputer = _T("\\\\");
  326. cstrComputer += lpszComputer;
  327. } else
  328. {
  329. cstrComputer = lpszComputer;
  330. }
  331. hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  332. if (SUCCEEDED(hr))
  333. {
  334. LPMALLOC pMalloc;
  335. hr = SHGetMalloc(&pMalloc);
  336. if (SUCCEEDED(hr))
  337. {
  338. LPSHELLFOLDER pDesktopFolder;
  339. hr = SHGetDesktopFolder(&pDesktopFolder);
  340. if (SUCCEEDED(hr))
  341. {
  342. LPITEMIDLIST pidlRoot;
  343. if (IsLocalComputer(lpszComputer))
  344. {
  345. hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlRoot);
  346. if (SUCCEEDED(hr))
  347. {
  348. //
  349. // 7/11/2001 LinanT bug#426953
  350. // Since connection made by Terminal Service may bring some client side resources
  351. // (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
  352. // the OK button when browsing to a non-local folder. We don't have this problem
  353. // when browsing a remote machine.
  354. //
  355. //
  356. // Get an array of local disk names, this information is later used
  357. // in the browse dialog to disable OK button if non-local path is selected.
  358. //
  359. // bug#714842: to work around the problem that NetServerDiskEnum
  360. // requires admin privilege, we call GetLogicalDriveStrings and
  361. // filter out remote drives.
  362. //
  363. hr = GetLocalLogicalDriveStrings(
  364. LOGICAL_DRIVES_BUFFER_LENGTH, // in TCHARs, including the terminating null char.
  365. szLocalDrives);
  366. }
  367. } else
  368. {
  369. hr = pDesktopFolder->ParseDisplayName(hwndParent, NULL,
  370. const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrComputer)),
  371. NULL, &pidlRoot, NULL);
  372. }
  373. if (SUCCEEDED(hr))
  374. {
  375. CString cstrLabel;
  376. cstrLabel.LoadString(IDS_BROWSE_FOLDER);
  377. BROWSEINFO bi;
  378. ZeroMemory(&bi,sizeof(bi));
  379. bi.hwndOwner = hwndParent;
  380. bi.pszDisplayName = 0;
  381. bi.lpszTitle = cstrLabel;
  382. bi.pidlRoot = pidlRoot;
  383. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_SHAREABLE | BIF_USENEWUI | BIF_VALIDATE;
  384. bi.lpfn = BrowseCallbackProc;
  385. if (szLocalDrives[0])
  386. bi.lParam = (LPARAM)szLocalDrives; // pass the structure to the browse dialog
  387. LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
  388. if (pidl) {
  389. SHGetPathFromIDList(pidl, lpszDir);
  390. pMalloc->Free(pidl);
  391. }
  392. pMalloc->Free(pidlRoot);
  393. }
  394. pDesktopFolder->Release();
  395. }
  396. pMalloc->Release();
  397. }
  398. CoUninitialize();
  399. }
  400. if (FAILED(hr))
  401. DisplayMessageBox(::GetActiveWindow(), MB_OK|MB_ICONWARNING, hr, IDS_CANNOT_BROWSE_FOLDER, lpszComputer);
  402. }
  403. BOOL
  404. IsValidLocalAbsolutePath(
  405. IN LPCTSTR lpszPath
  406. )
  407. {
  408. DWORD dwPathType = 0;
  409. DWORD dwStatus = I_NetPathType(
  410. NULL,
  411. const_cast<LPTSTR>(lpszPath),
  412. &dwPathType,
  413. 0);
  414. if (dwStatus)
  415. return FALSE;
  416. if (dwPathType ^ ITYPE_PATH_ABSD)
  417. return FALSE;
  418. return TRUE;
  419. }
  420. //+---------------------------------------------------------------------------
  421. //
  422. // Function: IsAnExistingFolder
  423. //
  424. // Synopsis: Check if pszPath is pointing at an existing folder.
  425. //
  426. // S_OK: The specified path points to an existing folder.
  427. // S_FALSE: The specified path doesn't point to an existing folder.
  428. // hr: Failed to get info on the specified path, or
  429. // the path exists but doesn't point to a folder.
  430. // The function reports error msg for both failures if desired.
  431. //----------------------------------------------------------------------------
  432. HRESULT
  433. IsAnExistingFolder(
  434. IN HWND hwnd,
  435. IN LPCTSTR pszPath,
  436. IN BOOL bDisplayErrorMsg
  437. )
  438. {
  439. if (!hwnd)
  440. hwnd = GetActiveWindow();
  441. HRESULT hr = S_OK;
  442. DWORD dwRet = GetFileAttributes(pszPath);
  443. if (-1 == dwRet)
  444. {
  445. DWORD dwErr = GetLastError();
  446. if (ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr)
  447. {
  448. // the specified path doesn't exist
  449. hr = S_FALSE;
  450. }
  451. else
  452. {
  453. hr = HRESULT_FROM_WIN32(dwErr);
  454. if (ERROR_NOT_READY == dwErr)
  455. {
  456. // fix for bug#358033/408803: ignore errors from GetFileAttributes in order to
  457. // allow the root of movable drives to be shared without media inserted in.
  458. int len = _tcslen(pszPath);
  459. if (len > 3 &&
  460. pszPath[len - 1] == _T('\\') &&
  461. pszPath[len - 2] == _T(':'))
  462. {
  463. // pszPath is pointing at the root of the drive, ignore the error
  464. hr = S_OK;
  465. }
  466. }
  467. if ( FAILED(hr) && bDisplayErrorMsg )
  468. DisplayMessageBox(hwnd, MB_OK, dwErr, IDS_FAILED_TO_GETINFO_FOLDER, pszPath);
  469. }
  470. } else if ( 0 == (dwRet & FILE_ATTRIBUTE_DIRECTORY) )
  471. {
  472. // the specified path is not pointing to a folder
  473. if (bDisplayErrorMsg)
  474. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, 0, IDS_PATH_NOT_FOLDER, pszPath);
  475. hr = E_FAIL;
  476. }
  477. return hr;
  478. }
  479. // create the directories layer by layer
  480. HRESULT
  481. CreateLayeredDirectory(
  482. IN LPCTSTR lpszServer,
  483. IN LPCTSTR lpszDir
  484. )
  485. {
  486. ASSERT(IsValidLocalAbsolutePath(lpszDir));
  487. BOOL bLocal = IsLocalComputer(lpszServer);
  488. CString cstrFullPath;
  489. GetFullPath(lpszServer, lpszDir, cstrFullPath);
  490. // add prefix to skip the CreateDirectory limit of 248 chars
  491. CString cstrFullPathNoParsing = (bLocal ? _T("\\\\?\\") : _T("\\\\?\\UNC"));
  492. cstrFullPathNoParsing += (bLocal ? cstrFullPath : cstrFullPath.Right(cstrFullPath.GetLength() - 1));
  493. HRESULT hr = IsAnExistingFolder(NULL, cstrFullPathNoParsing, FALSE);
  494. ASSERT(S_FALSE == hr);
  495. LPTSTR pch = _tcschr(cstrFullPathNoParsing, (bLocal ? _T(':') : _T('$')));
  496. ASSERT(pch);
  497. // pszPath holds "\\?\C:\a\b\c\d" or "\\?\UNC\server\share\a\b\c\d"
  498. // pszLeft holds "a\b\c\d"
  499. LPTSTR pszPath = const_cast<LPTSTR>(static_cast<LPCTSTR>(cstrFullPathNoParsing));
  500. LPTSTR pszLeft = pch + 2;
  501. LPTSTR pszRight = NULL;
  502. ASSERT(pszLeft && *pszLeft);
  503. //
  504. // this loop will find out the 1st non-existing sub-dir to create, and
  505. // the rest of non-existing sub-dirs
  506. //
  507. while (pch = _tcsrchr(pszLeft, _T('\\'))) // backwards search for _T('\\')
  508. {
  509. *pch = _T('\0');
  510. hr = IsAnExistingFolder(NULL, pszPath, TRUE);
  511. if (FAILED(hr))
  512. return S_FALSE; // errormsg has already been reported by IsAnExistingFolder().
  513. if (S_OK == hr)
  514. {
  515. //
  516. // pszPath is pointing to the parent dir of the 1st non-existing sub-dir.
  517. // Once we restore the _T('\\'), pszPath will point at the 1st non-existing subdir.
  518. //
  519. *pch = _T('\\');
  520. break;
  521. } else
  522. {
  523. //
  524. // pszPath is pointing to a non-existing folder, continue with the loop.
  525. //
  526. if (pszRight)
  527. *(pszRight - 1) = _T('\\');
  528. pszRight = pch + 1;
  529. }
  530. }
  531. // We're ready to create directories:
  532. // pszPath points to the 1st non-existing dir, e.g., "C:\a\b" or "\\server\share\a\b"
  533. // pszRight points to the rest of non-existing sub dirs, e.g., "c\d"
  534. //
  535. do
  536. {
  537. if (!CreateDirectory(pszPath, NULL))
  538. return HRESULT_FROM_WIN32(GetLastError());
  539. if (!pszRight || !*pszRight)
  540. break;
  541. *(pszRight - 1) = _T('\\');
  542. if (pch = _tcschr(pszRight, _T('\\'))) // forward search for _T('\\')
  543. {
  544. *pch = _T('\0');
  545. pszRight = pch + 1;
  546. } else
  547. {
  548. pszRight = NULL;
  549. }
  550. } while (1);
  551. return S_OK;
  552. }
  553. BOOL
  554. VerifyDirectory(
  555. IN LPCTSTR lpszServer,
  556. IN LPCTSTR lpszDir
  557. )
  558. {
  559. ASSERT(lpszDir && *lpszDir);
  560. ASSERT(IsValidLocalAbsolutePath(lpszDir));
  561. HWND hwnd = ::GetActiveWindow();
  562. BOOL bLocal = IsLocalComputer(lpszServer);
  563. HRESULT hr = VerifyDriveLetter(lpszServer, lpszDir);
  564. if (FAILED(hr))
  565. { /*
  566. // fix for bug#351212: ignore error and leave permission checkings to NetShareAdd apis
  567. DisplayMessageBox(hwnd, MB_OK, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszDir);
  568. return FALSE;
  569. */
  570. hr = S_OK;
  571. } else if (S_OK != hr)
  572. {
  573. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, 0, IDS_INVALID_DRIVE, lpszDir);
  574. return FALSE;
  575. }
  576. // warn if user has choosen to share out the whole volume
  577. if (3 == lstrlen(lpszDir) &&
  578. _T(':') == lpszDir[1] &&
  579. _T('\\') == lpszDir[2])
  580. {
  581. if (IDNO == DisplayMessageBox(hwnd, MB_YESNO|MB_DEFBUTTON2|MB_ICONWARNING, 0, IDS_WARNING_WHOLE_VOLUME, lpszDir))
  582. return FALSE;
  583. }
  584. if (!bLocal)
  585. {
  586. hr = IsAdminShare(lpszServer, lpszDir);
  587. if (FAILED(hr))
  588. {
  589. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, hr, IDS_FAILED_TO_VALIDATE_FOLDER, lpszDir);
  590. return FALSE;
  591. } else if (S_OK != hr)
  592. {
  593. // there is no matching $ shares, hence, no need to call GetFileAttribute, CreateDirectory,
  594. // assume lpszDir points to an existing directory
  595. return TRUE;
  596. }
  597. }
  598. CString cstrPath;
  599. GetFullPath(lpszServer, lpszDir, cstrPath);
  600. // add prefix to skip the GetFileAttribute limit when the path is on a remote server
  601. CString cstrPathNoParsing = (bLocal ? _T("\\\\?\\") : _T("\\\\?\\UNC"));
  602. cstrPathNoParsing += (bLocal ? cstrPath : cstrPath.Right(cstrPath.GetLength() - 1));
  603. hr = IsAnExistingFolder(hwnd, cstrPathNoParsing, TRUE); // error has already been reported.
  604. if (FAILED(hr) || S_OK == hr)
  605. return (S_OK == hr);
  606. if ( IDYES != DisplayMessageBox(hwnd, MB_YESNO|MB_ICONQUESTION, 0, IDS_CREATE_NEW_DIR, cstrPath) )
  607. return FALSE;
  608. // create the directories layer by layer
  609. hr = CreateLayeredDirectory(lpszServer, lpszDir);
  610. if (FAILED(hr))
  611. DisplayMessageBox(hwnd, MB_OK|MB_ICONERROR, hr, IDS_FAILED_TO_CREATE_NEW_DIR, cstrPath);
  612. return (S_OK == hr);
  613. }