Source code of Windows XP (NT5)
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.

801 lines
20 KiB

  1. /******************************************************************************
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. * respoint.cpp
  7. *
  8. * Abstract:
  9. * CRestorePoint, CRestorePointEnum class functions
  10. *
  11. * Revision History:
  12. * Brijesh Krishnaswami (brijeshk) 03/17/2000
  13. * created
  14. *
  15. *****************************************************************************/
  16. #include "precomp.h"
  17. #include "srapi.h"
  18. #ifdef THIS_FILE
  19. #undef THIS_FILE
  20. #endif
  21. static char __szTraceSourceFile[] = __FILE__;
  22. #define THIS_FILE __szTraceSourceFile
  23. // constructors
  24. // use this constructor to read in an existing rp
  25. // then need to call Read() to initialize rp members
  26. CRestorePoint::CRestorePoint()
  27. {
  28. m_pRPInfo = NULL;
  29. lstrcpy(m_szRPDir, L"");
  30. m_itCurChgLogEntry = m_ChgLogList.end();
  31. m_fForward = TRUE;
  32. m_fDefunct = FALSE;
  33. }
  34. // initialize
  35. BOOL
  36. CRestorePoint::Load(RESTOREPOINTINFOW *prpinfo)
  37. {
  38. if (prpinfo)
  39. {
  40. if (! m_pRPInfo)
  41. {
  42. m_pRPInfo = (RESTOREPOINTINFOW *) SRMemAlloc(sizeof(RESTOREPOINTINFOW));
  43. if (! m_pRPInfo)
  44. return FALSE;
  45. }
  46. CopyMemory(m_pRPInfo, prpinfo, sizeof(RESTOREPOINTINFOW));
  47. }
  48. return TRUE;
  49. }
  50. // destructor
  51. // call FindClose here
  52. // if no enumeration was done, this is a no-op
  53. CRestorePoint::~CRestorePoint()
  54. {
  55. if (m_pRPInfo)
  56. SRMemFree(m_pRPInfo);
  57. FindClose();
  58. }
  59. // return first/last change log entry in this restore point
  60. // assumes Read() has already been called
  61. DWORD
  62. CRestorePoint::FindFirstChangeLogEntry(
  63. LPWSTR pszDrive,
  64. BOOL fForward,
  65. CChangeLogEntry& cle)
  66. {
  67. DWORD dwRc = ERROR_SUCCESS;
  68. WCHAR szChgLogPrefix[MAX_PATH];
  69. WIN32_FIND_DATA FindData;
  70. INT64 llSeqNum;
  71. WCHAR szPath[MAX_PATH];
  72. TENTER("CRestorePoint::FindFirstChangeLogEntry");
  73. m_fForward = fForward;
  74. lstrcpy(m_szDrive, pszDrive);
  75. // read the first/last change log in this restore point
  76. // all entries inside a change log will always be read in forward order
  77. MakeRestorePath(szPath, m_szDrive, m_szRPDir);
  78. wsprintf(szChgLogPrefix, L"%s\\%s", szPath, s_cszChangeLogPrefix);
  79. if (! m_FindFile._FindFirstFile(szChgLogPrefix,
  80. s_cszChangeLogSuffix,
  81. &FindData,
  82. m_fForward,
  83. FALSE))
  84. {
  85. TRACE(0, "No changelog in %S", szPath);
  86. dwRc = ERROR_NO_MORE_ITEMS;
  87. goto done;
  88. }
  89. lstrcat(szPath, L"\\");
  90. lstrcat(szPath, FindData.cFileName);
  91. // build list of entries in increasing order of sequence number
  92. dwRc = BuildList(szPath);
  93. if (ERROR_SUCCESS != dwRc)
  94. {
  95. TRACE(0, "! BuildList : %ld", dwRc);
  96. goto done;
  97. }
  98. TRACE(0, "Enumerating %S in %S", FindData.cFileName, m_szRPDir);
  99. // if there was no entry in this change log, go to the next
  100. if (m_ChgLogList.empty())
  101. {
  102. dwRc = FindNextChangeLogEntry(cle);
  103. goto done;
  104. }
  105. // get the first/last entry
  106. if (m_fForward)
  107. {
  108. m_itCurChgLogEntry = m_ChgLogList.begin();
  109. }
  110. else
  111. {
  112. m_itCurChgLogEntry = m_ChgLogList.end();
  113. m_itCurChgLogEntry--;
  114. }
  115. // read in the change log entry into the object
  116. cle.Load(*m_itCurChgLogEntry, m_szRPDir);
  117. done:
  118. TLEAVE();
  119. return dwRc;
  120. }
  121. // return next/prev change log entry in this restore point
  122. // assumes Read() has already been called
  123. DWORD
  124. CRestorePoint::FindNextChangeLogEntry(
  125. CChangeLogEntry& cle)
  126. {
  127. DWORD dwRc = ERROR_SUCCESS;
  128. WCHAR szPath[MAX_PATH];
  129. WCHAR szChangeLogPath[MAX_PATH];
  130. WCHAR szChgLogPrefix[MAX_PATH];
  131. WIN32_FIND_DATA FindData;
  132. INT64 llSeqNum;
  133. TENTER("CRestorePoint::FindNextChangeLogEntry");
  134. // go to the next entry in the list
  135. m_fForward ? m_itCurChgLogEntry++ : m_itCurChgLogEntry--;
  136. // check if we've reached the end of this change log
  137. // end is the same for both forward and reverse enumeration
  138. if (m_itCurChgLogEntry == m_ChgLogList.end())
  139. {
  140. // if so, read the next change log into memory
  141. // nuke the current list
  142. FindClose();
  143. MakeRestorePath(szPath, m_szDrive, m_szRPDir);
  144. wsprintf(szChgLogPrefix, L"%s\\%s", szPath, s_cszChangeLogPrefix);
  145. while (m_ChgLogList.empty())
  146. {
  147. if (FALSE == m_FindFile._FindNextFile(szChgLogPrefix,
  148. s_cszChangeLogSuffix,
  149. &FindData))
  150. {
  151. dwRc = ERROR_NO_MORE_ITEMS;
  152. TRACE(0, "No more change logs");
  153. goto done;
  154. }
  155. lstrcpy(szChangeLogPath, szPath);
  156. lstrcat(szChangeLogPath, L"\\");
  157. lstrcat(szChangeLogPath, FindData.cFileName);
  158. dwRc = BuildList(szChangeLogPath);
  159. if (ERROR_SUCCESS != dwRc)
  160. {
  161. TRACE(0, "BuildList : error=%ld", dwRc);
  162. goto done;
  163. }
  164. TRACE(0, "Enumerating %S in %S", FindData.cFileName, m_szRPDir);
  165. }
  166. // get the first/last entry
  167. if (m_fForward)
  168. {
  169. m_itCurChgLogEntry = m_ChgLogList.begin();
  170. }
  171. else
  172. {
  173. m_itCurChgLogEntry = m_ChgLogList.end();
  174. m_itCurChgLogEntry--;
  175. }
  176. }
  177. // read in the change log entry fields into the object
  178. cle.Load(*m_itCurChgLogEntry, m_szRPDir);
  179. done:
  180. TLEAVE();
  181. return dwRc;
  182. }
  183. DWORD
  184. CRestorePoint::BuildList(
  185. LPWSTR pszChgLog)
  186. {
  187. DWORD dwRc = ERROR_INTERNAL_ERROR;
  188. HANDLE hChgLog = INVALID_HANDLE_VALUE;
  189. DWORD dwRead;
  190. DWORD dwEntrySize;
  191. PVOID pBlob = NULL;
  192. SR_LOG_ENTRY* pEntry = NULL;
  193. PSR_LOG_HEADER pLogHeader = NULL;
  194. DWORD cbSize;
  195. TENTER("CChangeLogEntry::BuildList");
  196. if (FALSE==IsFileOwnedByAdminOrSystem(pszChgLog))
  197. {
  198. // this is not a valid log.
  199. // ignore this log and go to the next one
  200. TRACE(0, "Change log %S not owned by admin or system", pszChgLog);
  201. dwRc = ERROR_SUCCESS;
  202. goto done;
  203. }
  204. hChgLog = CreateFile(pszChgLog, // file name
  205. GENERIC_READ, // access mode
  206. FILE_SHARE_READ, // share mode
  207. NULL, // SD
  208. OPEN_EXISTING, // how to create
  209. FILE_ATTRIBUTE_NORMAL, // file attributes
  210. NULL);
  211. if (INVALID_HANDLE_VALUE == hChgLog)
  212. {
  213. dwRc = GetLastError();
  214. TRACE(0, "! CreateFile on %S : %ld", pszChgLog, dwRc);
  215. goto done;
  216. }
  217. // read header size
  218. if (FALSE == ReadFile(hChgLog,
  219. &cbSize,
  220. sizeof(DWORD),
  221. &dwRead,
  222. NULL) || dwRead == 0 || cbSize == 0)
  223. {
  224. // if the file could not be read,
  225. // assume that it is a 0-sized log, and go to the next log
  226. dwRc = GetLastError();
  227. TRACE(0, "Zero sized log : %ld", pszChgLog, dwRc);
  228. dwRc = ERROR_SUCCESS;
  229. goto done;
  230. }
  231. pLogHeader = (SR_LOG_HEADER *) SRMemAlloc(cbSize);
  232. if (! pLogHeader)
  233. {
  234. TRACE(0, "Out of memory");
  235. goto done;
  236. }
  237. // read header
  238. pLogHeader->Header.RecordSize = cbSize;
  239. if (FALSE == ReadFile(hChgLog,
  240. (PVOID) ( ((BYTE *) pLogHeader) + sizeof(DWORD)),
  241. cbSize - sizeof(DWORD),
  242. &dwRead,
  243. NULL))
  244. {
  245. dwRc = GetLastError();
  246. TRACE(0, "! ReadFile on %S : %ld", pszChgLog, dwRc);
  247. goto done;
  248. }
  249. // check log's integrity
  250. if( pLogHeader->LogVersion != SR_LOG_VERSION ||
  251. pLogHeader->MagicNum != SR_LOG_MAGIC_NUMBER )
  252. {
  253. TRACE(0, "! LogHeader for %S : invalid or corrupt", pszChgLog);
  254. goto done;
  255. }
  256. // now read the entries
  257. do
  258. {
  259. // get the size of the entry
  260. if (FALSE == ReadFile(hChgLog, &dwEntrySize, sizeof(DWORD), &dwRead, NULL))
  261. {
  262. TRACE(0, "ReadFile failed, error=%ld", GetLastError());
  263. break;
  264. }
  265. if (0 == dwRead) // end of file
  266. {
  267. TRACE(0, "End of file");
  268. dwRc = ERROR_NO_MORE_ITEMS;
  269. break;
  270. }
  271. if (dwRead != sizeof(DWORD)) // error reading entry
  272. {
  273. TRACE(0, "Readfile could not read a DWORD");
  274. break;
  275. }
  276. if (0 == dwEntrySize) // reached the last entry
  277. {
  278. TRACE(0, "No more entries");
  279. dwRc = ERROR_NO_MORE_ITEMS;
  280. break;
  281. }
  282. // get the entry itself
  283. pEntry = (SR_LOG_ENTRY *) SRMemAlloc(dwEntrySize);
  284. if (! pEntry)
  285. {
  286. TRACE(0, "Out of memory");
  287. break;
  288. }
  289. pEntry->Header.RecordSize = dwEntrySize;
  290. // skip the size field
  291. pBlob = (PVOID) ((PBYTE) pEntry + sizeof(dwEntrySize));
  292. if (FALSE == ReadFile(hChgLog, pBlob, dwEntrySize - sizeof(dwEntrySize), &dwRead, NULL))
  293. {
  294. TRACE(0, "! ReadFile on %S : %ld", pszChgLog, GetLastError());
  295. break;
  296. }
  297. if (dwRead != dwEntrySize - sizeof(dwEntrySize)) // error reading entry
  298. {
  299. TRACE(0, "! Readfile: ToRead=%ld, Read=%ld bytes",
  300. dwEntrySize - sizeof(dwEntrySize), dwRead);
  301. break;
  302. }
  303. // insert entry into list
  304. dwRc = InsertEntryIntoList(pEntry);
  305. } while (ERROR_SUCCESS == dwRc);
  306. if (ERROR_NO_MORE_ITEMS == dwRc)
  307. {
  308. dwRc = ERROR_SUCCESS;
  309. }
  310. done:
  311. if (INVALID_HANDLE_VALUE != hChgLog)
  312. CloseHandle(hChgLog);
  313. SRMemFree(pLogHeader);
  314. TLEAVE();
  315. return dwRc;
  316. }
  317. // release memory and empty the list
  318. DWORD CRestorePoint::FindClose()
  319. {
  320. // nuke the list
  321. for (m_itCurChgLogEntry = m_ChgLogList.begin();
  322. m_itCurChgLogEntry != m_ChgLogList.end();
  323. m_itCurChgLogEntry++)
  324. {
  325. SRMemFree(*m_itCurChgLogEntry);
  326. }
  327. m_ChgLogList.clear();
  328. return ERROR_SUCCESS;
  329. }
  330. // insert change log entry into list
  331. DWORD
  332. CRestorePoint::InsertEntryIntoList(
  333. SR_LOG_ENTRY* pEntry)
  334. {
  335. TENTER("CRestorePoint::InsertEntryIntoList");
  336. m_ChgLogList.push_back(pEntry);
  337. TLEAVE();
  338. return ERROR_SUCCESS;
  339. }
  340. // populate members
  341. DWORD
  342. CRestorePoint::ReadLog()
  343. {
  344. DWORD dwRc = ERROR_SUCCESS;
  345. WCHAR szLog[MAX_PATH];
  346. WCHAR szSystemDrive[MAX_PATH];
  347. DWORD dwRead;
  348. TENTER("CRestorePoint::ReadLog");
  349. // construct path of rp.log
  350. GetSystemDrive(szSystemDrive);
  351. MakeRestorePath(szLog, szSystemDrive, m_szRPDir);
  352. lstrcat(szLog, L"\\");
  353. lstrcat(szLog, s_cszRestorePointLogName);
  354. HANDLE hFile = CreateFile (szLog, // file name
  355. GENERIC_READ, // file access
  356. FILE_SHARE_READ, // share mode
  357. NULL, // SD
  358. OPEN_EXISTING, // how to create
  359. 0, // file attributes
  360. NULL); // handle to template file
  361. if (INVALID_HANDLE_VALUE == hFile)
  362. {
  363. dwRc = GetLastError();
  364. trace(0, "! CreateFile on %S : %ld", szLog, dwRc);
  365. goto done;
  366. }
  367. // read the restore point info
  368. if (! m_pRPInfo)
  369. {
  370. m_pRPInfo = (RESTOREPOINTINFOW *) SRMemAlloc(sizeof(RESTOREPOINTINFOW));
  371. if (! m_pRPInfo)
  372. {
  373. dwRc = ERROR_OUTOFMEMORY;
  374. trace(0, "SRMemAlloc failed");
  375. goto done;
  376. }
  377. }
  378. if (FALSE == ReadFile(hFile, m_pRPInfo, sizeof(RESTOREPOINTINFOW), &dwRead, NULL) ||
  379. dwRead != sizeof(RESTOREPOINTINFOW))
  380. {
  381. dwRc = GetLastError();
  382. trace(0, "! ReadFile on %S : %ld", szLog, dwRc);
  383. goto done;
  384. }
  385. m_fDefunct = (m_pRPInfo->dwRestorePtType == CANCELLED_OPERATION);
  386. // read the creation time
  387. if (FALSE == ReadFile(hFile, &m_Time, sizeof(m_Time), &dwRead, NULL) ||
  388. dwRead != sizeof(m_Time))
  389. {
  390. dwRc = GetLastError();
  391. trace(0, "! ReadFile on %S : %ld", szLog, dwRc);
  392. goto done;
  393. }
  394. done:
  395. if (INVALID_HANDLE_VALUE != hFile)
  396. CloseHandle(hFile);
  397. TLEAVE();
  398. return dwRc;
  399. }
  400. DWORD
  401. CRestorePoint::WriteLog()
  402. {
  403. DWORD dwRc = ERROR_SUCCESS;
  404. WCHAR szLog[MAX_PATH];
  405. WCHAR szSystemDrive[MAX_PATH];
  406. DWORD dwWritten;
  407. HANDLE hFile = INVALID_HANDLE_VALUE;
  408. TENTER("CRestorePoint::WriteLog");
  409. if (! m_pRPInfo)
  410. {
  411. ASSERT(0);
  412. dwRc = ERROR_INTERNAL_ERROR;
  413. goto done;
  414. }
  415. // set the creation time to the current time
  416. GetSystemTimeAsFileTime(&m_Time);
  417. // construct path of rp.log
  418. GetSystemDrive(szSystemDrive);
  419. MakeRestorePath(szLog, szSystemDrive, m_szRPDir);
  420. lstrcat(szLog, L"\\");
  421. lstrcat(szLog, s_cszRestorePointLogName);
  422. hFile = CreateFile (szLog, // file name
  423. GENERIC_WRITE, // file access
  424. 0, // share mode
  425. NULL, // SD
  426. CREATE_ALWAYS, // how to create
  427. FILE_FLAG_WRITE_THROUGH, // file attributes
  428. NULL); // handle to template file
  429. if (INVALID_HANDLE_VALUE == hFile)
  430. {
  431. dwRc = GetLastError();
  432. trace(0, "! CreateFile on %S : %ld", szLog, dwRc);
  433. goto done;
  434. }
  435. // write the restore point info
  436. if (FALSE == WriteFile(hFile, m_pRPInfo, sizeof(RESTOREPOINTINFOW), &dwWritten, NULL))
  437. {
  438. dwRc = GetLastError();
  439. trace(0, "! WriteFile on %S : %ld", szLog, dwRc);
  440. goto done;
  441. }
  442. // write the creation time
  443. if (FALSE == WriteFile(hFile, &m_Time, sizeof(m_Time), &dwWritten, NULL))
  444. {
  445. dwRc = GetLastError();
  446. trace(0, "! WriteFile on %S : %ld", szLog, dwRc);
  447. goto done;
  448. }
  449. done:
  450. if (INVALID_HANDLE_VALUE != hFile)
  451. CloseHandle(hFile);
  452. TLEAVE();
  453. return dwRc;
  454. }
  455. BOOL
  456. CRestorePoint::DeleteLog()
  457. {
  458. WCHAR szLog[MAX_PATH];
  459. WCHAR szSystemDrive[MAX_PATH];
  460. GetSystemDrive(szSystemDrive);
  461. MakeRestorePath(szLog, szSystemDrive, m_szRPDir);
  462. lstrcat(szLog, L"\\");
  463. lstrcat(szLog, s_cszRestorePointLogName);
  464. return DeleteFile(szLog);
  465. }
  466. DWORD
  467. CRestorePoint::Cancel()
  468. {
  469. if (m_pRPInfo)
  470. {
  471. m_pRPInfo->dwRestorePtType = CANCELLED_OPERATION;
  472. return WriteLog();
  473. }
  474. else
  475. {
  476. ASSERT(0);
  477. return ERROR_INTERNAL_ERROR;
  478. }
  479. }
  480. DWORD
  481. CRestorePoint::GetNum()
  482. {
  483. return GetID(m_szRPDir);
  484. }
  485. // read the size of the restore point folder from file
  486. DWORD CRestorePoint::ReadSize (const WCHAR *pwszDrive, INT64 *pllSize)
  487. {
  488. DWORD dwErr = ERROR_SUCCESS;
  489. DWORD cbRead = 0;
  490. WCHAR wcsPath[MAX_PATH];
  491. MakeRestorePath(wcsPath, pwszDrive, m_szRPDir);
  492. lstrcat(wcsPath, L"\\");
  493. lstrcat (wcsPath, s_cszRestorePointSize);
  494. HANDLE hFile = CreateFileW ( wcsPath, // file name
  495. GENERIC_READ, // file access
  496. FILE_SHARE_READ, // share mode
  497. NULL, // SD
  498. OPEN_EXISTING, // how to create
  499. 0, // file attributes
  500. NULL); // handle to template file
  501. if (INVALID_HANDLE_VALUE == hFile)
  502. {
  503. dwErr = GetLastError();
  504. return dwErr;
  505. }
  506. if (FALSE == ReadFile (hFile, (BYTE *) pllSize, sizeof(*pllSize),
  507. &cbRead, NULL))
  508. {
  509. dwErr = GetLastError();
  510. }
  511. CloseHandle (hFile);
  512. return dwErr;
  513. }
  514. // write the size of the restore point folder to file
  515. DWORD CRestorePoint::WriteSize (const WCHAR *pwszDrive, INT64 llSize)
  516. {
  517. DWORD dwErr = ERROR_SUCCESS;
  518. DWORD cbWritten = 0;
  519. WCHAR wcsPath[MAX_PATH];
  520. MakeRestorePath(wcsPath, pwszDrive, m_szRPDir);
  521. lstrcat(wcsPath, L"\\");
  522. lstrcat (wcsPath, s_cszRestorePointSize);
  523. HANDLE hFile = CreateFileW ( wcsPath, // file name
  524. GENERIC_WRITE, // file access
  525. 0, // share mode
  526. NULL, // SD
  527. CREATE_ALWAYS, // how to create
  528. 0, // file attributes
  529. NULL); // handle to template file
  530. if (INVALID_HANDLE_VALUE == hFile)
  531. {
  532. dwErr = GetLastError();
  533. return dwErr;
  534. }
  535. if (FALSE == WriteFile (hFile, (BYTE *) &llSize, sizeof(llSize),
  536. &cbWritten, NULL))
  537. {
  538. dwErr = GetLastError();
  539. }
  540. CloseHandle (hFile);
  541. return dwErr;
  542. }
  543. // populate a changelogentry object
  544. void
  545. CChangeLogEntry::Load(SR_LOG_ENTRY *pentry, LPWSTR pszRPDir)
  546. {
  547. PSR_LOG_DEBUG_INFO pDebugRec = NULL;
  548. _pentry = pentry;
  549. _pszPath1 = _pszPath2 = _pszTemp = _pszProcess = _pszShortName = NULL;
  550. _pbAcl = NULL;
  551. _cbAcl = 0;
  552. _fAclInline = FALSE;
  553. lstrcpy(_pszRPDir, pszRPDir);
  554. BYTE *pRec = (PBYTE) & _pentry->SubRecords;
  555. //
  556. // get source path
  557. //
  558. _pszPath1 = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
  559. //
  560. // get temp path if exists
  561. //
  562. if (_pentry->EntryFlags & ENTRYFLAGS_TEMPPATH)
  563. {
  564. pRec += RECORD_SIZE(pRec);
  565. _pszTemp = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
  566. }
  567. //
  568. // get second path if exists
  569. //
  570. if (_pentry->EntryFlags & ENTRYFLAGS_SECONDPATH)
  571. {
  572. pRec += RECORD_SIZE(pRec);
  573. _pszPath2 = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
  574. }
  575. //
  576. // get acl info if exists
  577. //
  578. if (_pentry->EntryFlags & ENTRYFLAGS_ACLINFO)
  579. {
  580. pRec += RECORD_SIZE(pRec);
  581. if (RECORD_TYPE(pRec) == RecordTypeAclInline)
  582. {
  583. _fAclInline = TRUE;
  584. }
  585. _pbAcl = (BYTE *) (pRec + sizeof(RECORD_HEADER));
  586. _cbAcl = RECORD_SIZE(pRec) - sizeof(RECORD_HEADER);
  587. }
  588. //
  589. // get debug info if exists
  590. //
  591. if (_pentry->EntryFlags & ENTRYFLAGS_DEBUGINFO)
  592. {
  593. pRec += RECORD_SIZE(pRec);
  594. pDebugRec = (PSR_LOG_DEBUG_INFO) pRec;
  595. _pszProcess = (LPWSTR) (pDebugRec->ProcessName);
  596. }
  597. //
  598. // get shortname if exists
  599. //
  600. if (_pentry->EntryFlags & ENTRYFLAGS_SHORTNAME)
  601. {
  602. pRec += RECORD_SIZE(pRec);
  603. _pszShortName = (LPWSTR) (pRec + sizeof(RECORD_HEADER));
  604. }
  605. return;
  606. }
  607. // this function will check if any filepath length exceeds
  608. // the max length that restore supports
  609. // if so, it will return FALSE
  610. BOOL
  611. CChangeLogEntry::CheckPathLengths()
  612. {
  613. if (_pszPath1 && lstrlen(_pszPath1) > SR_MAX_FILENAME_PATH-1)
  614. return FALSE;
  615. if (_pszPath2 && lstrlen(_pszPath2) > SR_MAX_FILENAME_PATH-1)
  616. return FALSE;
  617. if (_pszTemp && lstrlen(_pszTemp) > SR_MAX_FILENAME_PATH-1)
  618. return FALSE;
  619. return TRUE;
  620. }