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.

1053 lines
28 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. filelog.c
  5. Abstract:
  6. Routines for logging files in copy logs.
  7. Author:
  8. Ted Miller (tedm) 14-Jun-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Define name of system log file and various strings used
  15. // within it.
  16. //
  17. PCTSTR SystemLogFileName = TEXT("repair\\setup.log");
  18. PCTSTR NtFileSectionName = TEXT("Files.WinNT");
  19. //
  20. // Define structure used internally to represent a file log file.
  21. //
  22. typedef struct _SETUP_FILE_LOG {
  23. PCTSTR FileName;
  24. BOOL QueryOnly;
  25. BOOL SystemLog;
  26. } SETUP_FILE_LOG, *PSETUP_FILE_LOG;
  27. #ifdef UNICODE
  28. //
  29. // ANSI version
  30. //
  31. HSPFILELOG
  32. SetupInitializeFileLogA(
  33. IN PCSTR LogFileName, OPTIONAL
  34. IN DWORD Flags
  35. )
  36. {
  37. PWSTR p;
  38. DWORD d;
  39. HSPFILELOG h;
  40. if(LogFileName) {
  41. d = pSetupCaptureAndConvertAnsiArg(LogFileName,&p);
  42. if(d != NO_ERROR) {
  43. SetLastError(d);
  44. return(INVALID_HANDLE_VALUE);
  45. }
  46. } else {
  47. p = NULL;
  48. }
  49. h = SetupInitializeFileLogW(p,Flags);
  50. d = GetLastError();
  51. if(p) {
  52. MyFree(p);
  53. }
  54. SetLastError(d);
  55. return(h);
  56. }
  57. #else
  58. //
  59. // Unicode stub
  60. //
  61. HSPFILELOG
  62. SetupInitializeFileLogW(
  63. IN PCWSTR LogFileName, OPTIONAL
  64. IN DWORD Flags
  65. )
  66. {
  67. UNREFERENCED_PARAMETER(LogFileName);
  68. UNREFERENCED_PARAMETER(Flags);
  69. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  70. return(INVALID_HANDLE_VALUE);
  71. }
  72. #endif
  73. HSPFILELOG
  74. SetupInitializeFileLog(
  75. IN PCTSTR LogFileName, OPTIONAL
  76. IN DWORD Flags
  77. )
  78. /*++
  79. Routine Description:
  80. Initialize a file for logging or query. The caller may specify that he
  81. wishes to use the system log, which is where the system tracks which
  82. files are installed as part of Windows NT; or the caller may specify
  83. any other random file to be used as a log.
  84. If the user specifies the system log not for query only, the function fails
  85. unless the user is administrator. However this only guarantees security
  86. on the log when the system is installed on a drive with a filesystem that
  87. supports ACLs; the log is simply a file and anyone can access it unless
  88. setup can secure it via ACLs.
  89. Arguments:
  90. LogFileName - if specified, supplies the filename of the file to be used
  91. as the log file. Must be specified if Flags does not include
  92. SPFILELOG_SYSTEMLOG. Must not be specified if Flags includes
  93. SPFILELOG_SYSTEMLOG.
  94. Flags - supplies a combination of the following values:
  95. SPFILELOG_SYSTEMLOG - use the Windows NT system file log, which is used
  96. to track what files are installed as part of Windows NT. The user must
  97. be administrator to specify this option unless SPFILELOG_QUERYONLY
  98. is specified, and LogFileName must not be specified. May not be specified
  99. in combination with SPFILELOG_FORCENEW.
  100. SPFILELOG_FORCENEW - if the log file exists, it will be overwritten.
  101. If the log file exists and this flag is not specified then additional
  102. files are added to the existing log. May not be specified in combination
  103. with SPFILELOG_SYSTEMLOG.
  104. SPFILELOG_QUERYONLY - open the log file for querying only. The user
  105. Return Value:
  106. Handle to file log or INVALID_HANDLE_VALUE if the function fails;
  107. extended error info is available via GetLastError() in this case.
  108. --*/
  109. {
  110. TCHAR SysLogFileName[MAX_PATH];
  111. PCTSTR FileName;
  112. PSETUP_FILE_LOG FileLog;
  113. DWORD Err;
  114. HANDLE hFile;
  115. //
  116. // Validate args.
  117. //
  118. Err = ERROR_INVALID_PARAMETER;
  119. if(Flags & SPFILELOG_SYSTEMLOG) {
  120. if((Flags & SPFILELOG_FORCENEW) || LogFileName) {
  121. goto clean0;
  122. }
  123. //
  124. // User must be administrator to gain write access to system log.
  125. //
  126. if(!(Flags & SPFILELOG_QUERYONLY) && !pSetupIsUserAdmin()) {
  127. Err = ERROR_ACCESS_DENIED;
  128. goto clean0;
  129. }
  130. //
  131. // uses actual windows directory instead of hydra remapped
  132. //
  133. lstrcpyn(SysLogFileName,WindowsDirectory,MAX_PATH);
  134. pSetupConcatenatePaths(SysLogFileName,SystemLogFileName,MAX_PATH,NULL);
  135. FileName = SysLogFileName;
  136. } else {
  137. if(LogFileName) {
  138. if(!lstrcpyn(SysLogFileName,LogFileName,MAX_PATH)) {
  139. //
  140. // lstrcpyn faulted, LogFileName must be bad
  141. //
  142. Err = ERROR_INVALID_PARAMETER;
  143. goto clean0;
  144. }
  145. FileName = SysLogFileName;
  146. } else {
  147. goto clean0;
  148. }
  149. }
  150. //
  151. // Allocate a log file structure.
  152. //
  153. Err = ERROR_NOT_ENOUGH_MEMORY;
  154. if(FileLog = MyMalloc(sizeof(SETUP_FILE_LOG))) {
  155. FileLog->FileName = DuplicateString(FileName);
  156. if(!FileLog->FileName) {
  157. goto clean1;
  158. }
  159. } else {
  160. goto clean0;
  161. }
  162. FileLog->QueryOnly = ((Flags & SPFILELOG_QUERYONLY) != 0);
  163. FileLog->SystemLog = ((Flags & SPFILELOG_SYSTEMLOG) != 0);
  164. //
  165. // See if the file exists.
  166. //
  167. if(FileExists(FileName,NULL)) {
  168. //
  169. // If it's the system log, take ownership of the file.
  170. //
  171. if(FileLog->SystemLog) {
  172. Err = TakeOwnershipOfFile(FileName);
  173. if(Err != NO_ERROR) {
  174. goto clean2;
  175. }
  176. }
  177. //
  178. // Set attribute to normal. This ensures we can delete/open/create the file
  179. // as appropriate below.
  180. //
  181. if(!SetFileAttributes(FileName,FILE_ATTRIBUTE_NORMAL)) {
  182. Err = GetLastError();
  183. goto clean2;
  184. }
  185. //
  186. // Delete the file now if the caller specified the force_new flag.
  187. //
  188. if((Flags & SPFILELOG_FORCENEW) && !DeleteFile(FileName)) {
  189. Err = GetLastError();
  190. goto clean2;
  191. }
  192. }
  193. //
  194. // Make sure we can open/create the file by attempting to do that now.
  195. //
  196. hFile = CreateFile(
  197. FileName,
  198. GENERIC_READ | (FileLog->QueryOnly ? 0 : GENERIC_WRITE),
  199. FILE_SHARE_READ | FILE_SHARE_WRITE,
  200. NULL,
  201. OPEN_ALWAYS, // Open if exists, create if not
  202. FILE_ATTRIBUTE_NORMAL,
  203. NULL
  204. );
  205. if(hFile == INVALID_HANDLE_VALUE) {
  206. Err = GetLastError();
  207. goto clean2;
  208. }
  209. CloseHandle(hFile);
  210. return((HSPFILELOG)FileLog);
  211. clean2:
  212. MyFree(FileLog->FileName);
  213. clean1:
  214. MyFree(FileLog);
  215. clean0:
  216. SetLastError(Err);
  217. return(INVALID_HANDLE_VALUE);
  218. }
  219. BOOL
  220. SetupTerminateFileLog(
  221. IN HSPFILELOG FileLogHandle
  222. )
  223. /*++
  224. Routine Description:
  225. Releases resources associated with a file log.
  226. Arguments:
  227. FileLogHandle - supplies the handle to the file log, as returned
  228. by SetupInitializeLogFile.
  229. Return Value:
  230. Boolean value indicating outcome. If FALSE, the caller can use
  231. GetLastError() to get extended error info.
  232. --*/
  233. {
  234. PSETUP_FILE_LOG FileLog;
  235. DWORD Err;
  236. FileLog = (PSETUP_FILE_LOG)FileLogHandle;
  237. Err = NO_ERROR;
  238. try {
  239. MyFree(FileLog->FileName);
  240. MyFree(FileLog);
  241. } except(EXCEPTION_EXECUTE_HANDLER) {
  242. Err = ERROR_INVALID_PARAMETER;
  243. }
  244. SetLastError(Err);
  245. return(Err == NO_ERROR);
  246. }
  247. #ifdef UNICODE
  248. //
  249. // ANSI version
  250. //
  251. BOOL
  252. SetupLogFileA(
  253. IN HSPFILELOG FileLogHandle,
  254. IN PCSTR LogSectionName, OPTIONAL
  255. IN PCSTR SourceFilename,
  256. IN PCSTR TargetFilename,
  257. IN DWORD Checksum, OPTIONAL
  258. IN PCSTR DiskTagfile, OPTIONAL
  259. IN PCSTR DiskDescription, OPTIONAL
  260. IN PCSTR OtherInfo, OPTIONAL
  261. IN DWORD Flags
  262. )
  263. {
  264. PWSTR logsectionname = NULL;
  265. PWSTR sourcefilename = NULL;
  266. PWSTR targetfilename = NULL;
  267. PWSTR disktagfile = NULL;
  268. PWSTR diskdescription = NULL;
  269. PWSTR otherinfo = NULL;
  270. DWORD d;
  271. BOOL b;
  272. if(LogSectionName) {
  273. d = pSetupCaptureAndConvertAnsiArg(LogSectionName,&logsectionname);
  274. } else {
  275. d = NO_ERROR;
  276. }
  277. if(d == NO_ERROR) {
  278. d = pSetupCaptureAndConvertAnsiArg(SourceFilename,&sourcefilename);
  279. }
  280. if(d == NO_ERROR) {
  281. d = pSetupCaptureAndConvertAnsiArg(TargetFilename,&targetfilename);
  282. }
  283. if((d == NO_ERROR) && DiskTagfile) {
  284. d = pSetupCaptureAndConvertAnsiArg(DiskTagfile,&disktagfile);
  285. }
  286. if((d == NO_ERROR) && DiskDescription) {
  287. d = pSetupCaptureAndConvertAnsiArg(DiskDescription,&diskdescription);
  288. }
  289. if((d == NO_ERROR) && OtherInfo) {
  290. d = pSetupCaptureAndConvertAnsiArg(OtherInfo,&otherinfo);
  291. }
  292. if(d == NO_ERROR) {
  293. b = SetupLogFileW(
  294. FileLogHandle,
  295. logsectionname,
  296. sourcefilename,
  297. targetfilename,
  298. Checksum,
  299. disktagfile,
  300. diskdescription,
  301. otherinfo,
  302. Flags
  303. );
  304. d = GetLastError();
  305. } else {
  306. b = FALSE;
  307. }
  308. if(logsectionname) {
  309. MyFree(logsectionname);
  310. }
  311. if(sourcefilename) {
  312. MyFree(sourcefilename);
  313. }
  314. if(targetfilename) {
  315. MyFree(targetfilename);
  316. }
  317. if(disktagfile) {
  318. MyFree(disktagfile);
  319. }
  320. if(diskdescription) {
  321. MyFree(diskdescription);
  322. }
  323. if(otherinfo) {
  324. MyFree(otherinfo);
  325. }
  326. SetLastError(d);
  327. return(b);
  328. }
  329. #else
  330. //
  331. // Unicode stub
  332. //
  333. BOOL
  334. SetupLogFileW(
  335. IN HSPFILELOG FileLogHandle,
  336. IN PCWSTR LogSectionName, OPTIONAL
  337. IN PCWSTR SourceFilename,
  338. IN PCWSTR TargetFilename,
  339. IN DWORD Checksum, OPTIONAL
  340. IN PCWSTR DiskTagfile, OPTIONAL
  341. IN PCWSTR DiskDescription, OPTIONAL
  342. IN PCWSTR OtherInfo, OPTIONAL
  343. IN DWORD Flags
  344. )
  345. {
  346. UNREFERENCED_PARAMETER(FileLogHandle);
  347. UNREFERENCED_PARAMETER(LogSectionName);
  348. UNREFERENCED_PARAMETER(SourceFilename);
  349. UNREFERENCED_PARAMETER(TargetFilename);
  350. UNREFERENCED_PARAMETER(Checksum);
  351. UNREFERENCED_PARAMETER(DiskTagfile);
  352. UNREFERENCED_PARAMETER(DiskDescription);
  353. UNREFERENCED_PARAMETER(OtherInfo);
  354. UNREFERENCED_PARAMETER(Flags);
  355. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  356. return(FALSE);
  357. }
  358. #endif
  359. BOOL
  360. SetupLogFile(
  361. IN HSPFILELOG FileLogHandle,
  362. IN PCTSTR LogSectionName, OPTIONAL
  363. IN PCTSTR SourceFilename,
  364. IN PCTSTR TargetFilename,
  365. IN DWORD Checksum, OPTIONAL
  366. IN PCTSTR DiskTagfile, OPTIONAL
  367. IN PCTSTR DiskDescription, OPTIONAL
  368. IN PCTSTR OtherInfo, OPTIONAL
  369. IN DWORD Flags
  370. )
  371. /*++
  372. Routine Description:
  373. Logs a file into a file log.
  374. Arguments:
  375. FileLogHandle - supplies the handle to the file log, as returned
  376. by SetupInitializeLogFile(). The caller must not have passed
  377. SPFILELOG_QUERYONLY when the log file was opened/initialized.
  378. LogSectionName - required if SPFILELOG_SYSTEMLOG was not passed when
  379. the file log was opened/initialized; optional otherwise.
  380. Supplies the name for a logical grouping of files within the log.
  381. SourceFilename - supplies the name of the file as it exists on the
  382. source media from which it was installed. This name should be in
  383. whatever format is meaningful to the caller.
  384. TargetFilename - supplies the name of the file as it exists on the
  385. Target. This name should be in whatever format is meaningful to
  386. the caller.
  387. Checksum - supplies a 32-bit checksum value. Required for the system log.
  388. DiskTagfile - Gives the tagfile for the media from which the file
  389. was installed. Required for the system log if SPFILELOG_OEMFILE
  390. is specified. Ignored for the system log if SPFILELOG_OEMFILE is
  391. not specified.
  392. DiskDescription - Gives the human-readable description for the media
  393. from which the file was installed. Required for the system log if
  394. SPFILELOG_OEMFILE is specified. Ignored for the system log if
  395. SPFILELOG_OEMFILE is not specified.
  396. OtherInfo - supplies additional information to be associated with the
  397. file.
  398. Flags - may supply SPFILELOG_OEMFILE, which is meaningful only for
  399. the system log and indicates that the file is not an MS-supplied file.
  400. Can be used to convert an existing file's entry such as when an oem
  401. overwrites an MS-supplied system file.
  402. Return Value:
  403. Boolean value indicating outcome. If FALSE, the caller can use
  404. GetLastError() to get extended error info.
  405. --*/
  406. {
  407. PSETUP_FILE_LOG FileLog;
  408. DWORD Err;
  409. BOOL b;
  410. TCHAR LineToWrite[512];
  411. TCHAR sourceFilename[MAX_PATH];
  412. PTSTR p,Directory;
  413. FileLog = (PSETUP_FILE_LOG)FileLogHandle;
  414. try {
  415. //
  416. // Validate params. Handle must be for non-queryonly.
  417. // If for the system log and oem file is specified,
  418. // caller must have passed disk tagfile and description.
  419. // There's really no way to validate the checksum because
  420. // 0 is a perfectly valid one.
  421. // If not the system log, caller must have passed a section name.
  422. //
  423. if(FileLog->QueryOnly
  424. || ( FileLog->SystemLog
  425. && (Flags & SPFILELOG_OEMFILE)
  426. && (!DiskTagfile || !DiskDescription))
  427. || (!FileLog->SystemLog && !LogSectionName))
  428. {
  429. Err = ERROR_INVALID_PARAMETER;
  430. } else {
  431. //
  432. // Use default section if not specified.
  433. //
  434. if(!LogSectionName) {
  435. MYASSERT(FileLog->SystemLog);
  436. LogSectionName = NtFileSectionName;
  437. }
  438. //
  439. // IF THIS LOGIC IS CHANGED BE SURE TO CHANGE
  440. // SetupQueryFileLog() AS WELL!
  441. //
  442. // Split up the source filename into filename and
  443. // directory if appropriate.
  444. //
  445. lstrcpyn(sourceFilename,SourceFilename,MAX_PATH);
  446. if(FileLog->SystemLog && (Flags & SPFILELOG_OEMFILE)) {
  447. if(p = _tcsrchr(sourceFilename,TEXT('\\'))) {
  448. *p++ = 0;
  449. Directory = p;
  450. } else {
  451. Directory = TEXT("\\");
  452. }
  453. } else {
  454. Directory = TEXT("");
  455. }
  456. _sntprintf(
  457. LineToWrite,
  458. sizeof(LineToWrite)/sizeof(LineToWrite[0]),
  459. TEXT("%s,%x,%s,%s,\"%s\""),
  460. sourceFilename,
  461. Checksum,
  462. Directory,
  463. DiskTagfile ? DiskTagfile : TEXT(""),
  464. DiskDescription ? DiskDescription : TEXT("")
  465. );
  466. b = WritePrivateProfileString(
  467. LogSectionName,
  468. TargetFilename,
  469. LineToWrite,
  470. FileLog->FileName
  471. );
  472. Err = b ? NO_ERROR : GetLastError();
  473. }
  474. } except(EXCEPTION_EXECUTE_HANDLER) {
  475. Err = ERROR_INVALID_PARAMETER;
  476. }
  477. SetLastError(Err);
  478. return(Err == NO_ERROR);
  479. }
  480. #ifdef UNICODE
  481. //
  482. // ANSI version
  483. //
  484. BOOL
  485. SetupRemoveFileLogEntryA(
  486. IN HSPFILELOG FileLogHandle,
  487. IN PCSTR LogSectionName, OPTIONAL
  488. IN PCSTR TargetFilename OPTIONAL
  489. )
  490. {
  491. PWSTR logsectionname,targetfilename;
  492. DWORD d;
  493. BOOL b;
  494. if(LogSectionName) {
  495. d = pSetupCaptureAndConvertAnsiArg(LogSectionName,&logsectionname);
  496. if(d != NO_ERROR) {
  497. SetLastError(d);
  498. return(FALSE);
  499. }
  500. } else {
  501. logsectionname = NULL;
  502. }
  503. if(TargetFilename) {
  504. d = pSetupCaptureAndConvertAnsiArg(TargetFilename,&targetfilename);
  505. if(d != NO_ERROR) {
  506. if(logsectionname) {
  507. MyFree(logsectionname);
  508. }
  509. SetLastError(d);
  510. return(FALSE);
  511. }
  512. } else {
  513. targetfilename = NULL;
  514. }
  515. b = SetupRemoveFileLogEntryW(FileLogHandle,logsectionname,targetfilename);
  516. d = GetLastError();
  517. if(logsectionname) {
  518. MyFree(logsectionname);
  519. }
  520. if(targetfilename) {
  521. MyFree(targetfilename);
  522. }
  523. SetLastError(d);
  524. return(b);
  525. }
  526. #else
  527. //
  528. // Unicode stub
  529. //
  530. BOOL
  531. SetupRemoveFileLogEntryW(
  532. IN HSPFILELOG FileLogHandle,
  533. IN PCWSTR LogSectionName, OPTIONAL
  534. IN PCWSTR TargetFilename OPTIONAL
  535. )
  536. {
  537. UNREFERENCED_PARAMETER(FileLogHandle);
  538. UNREFERENCED_PARAMETER(LogSectionName);
  539. UNREFERENCED_PARAMETER(TargetFilename);
  540. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  541. return(FALSE);
  542. }
  543. #endif
  544. BOOL
  545. SetupRemoveFileLogEntry(
  546. IN HSPFILELOG FileLogHandle,
  547. IN PCTSTR LogSectionName, OPTIONAL
  548. IN PCTSTR TargetFilename OPTIONAL
  549. )
  550. /*++
  551. Routine Description:
  552. Removes an entry or section from a file log.
  553. Arguments:
  554. FileLogHandle - supplies the handle to the file log, as returned
  555. by SetupInitializeLogFile(). The caller must not have passed
  556. SPFILELOG_QUERYONLY when the log file was opened/initialized.
  557. LogSectionName - Supplies the name for a logical grouping of files
  558. within the log. Required for non-system logs; optional for the
  559. system log.
  560. TargetFilename - supplies the name of the file as it exists on the
  561. Target. This name should be in whatever format is meaningful to
  562. the caller. If not specified, the entire section specified by
  563. LogSectionName is removed. Removing the main section for NT files
  564. is not allowed.
  565. Return Value:
  566. Boolean value indicating outcome. If FALSE, the caller can use
  567. GetLastError() to get extended error info.
  568. --*/
  569. {
  570. DWORD Err;
  571. PSETUP_FILE_LOG FileLog;
  572. BOOL b;
  573. FileLog = (PSETUP_FILE_LOG)FileLogHandle;
  574. try {
  575. Err = NO_ERROR;
  576. if(FileLog->QueryOnly) {
  577. Err = ERROR_INVALID_PARAMETER;
  578. } else {
  579. if(!LogSectionName) {
  580. if(FileLog->SystemLog) {
  581. LogSectionName = NtFileSectionName;
  582. } else {
  583. Err = ERROR_INVALID_PARAMETER;
  584. }
  585. }
  586. //
  587. // Diallow removing the main nt files section.
  588. //
  589. if((Err == NO_ERROR)
  590. && FileLog->SystemLog
  591. && !TargetFilename
  592. && !lstrcmpi(LogSectionName,NtFileSectionName))
  593. {
  594. Err = ERROR_INVALID_PARAMETER;
  595. }
  596. }
  597. if(Err == NO_ERROR) {
  598. b = WritePrivateProfileString(LogSectionName,TargetFilename,NULL,FileLog->FileName);
  599. Err = b ? NO_ERROR : GetLastError();
  600. }
  601. } except(EXCEPTION_EXECUTE_HANDLER) {
  602. Err = ERROR_INVALID_PARAMETER;
  603. }
  604. return(Err == NO_ERROR);
  605. }
  606. #ifdef UNICODE
  607. //
  608. // ANSI version
  609. //
  610. BOOL
  611. SetupQueryFileLogA(
  612. IN HSPFILELOG FileLogHandle,
  613. IN PCSTR LogSectionName, OPTIONAL
  614. IN PCSTR TargetFilename,
  615. IN SetupFileLogInfo DesiredInfo,
  616. OUT PSTR DataOut, OPTIONAL
  617. IN DWORD ReturnBufferSize,
  618. OUT PDWORD RequiredSize OPTIONAL
  619. )
  620. {
  621. PWSTR logsectionname;
  622. PWSTR targetfilename;
  623. PWSTR unicodeBuffer = NULL;
  624. DWORD unicodeSize = 2048;
  625. PSTR ansidata;
  626. DWORD requiredsize;
  627. DWORD d;
  628. BOOL b;
  629. d = pSetupCaptureAndConvertAnsiArg(TargetFilename,&targetfilename);
  630. if(d != NO_ERROR) {
  631. SetLastError(d);
  632. return(FALSE);
  633. }
  634. if(LogSectionName) {
  635. d = pSetupCaptureAndConvertAnsiArg(LogSectionName,&logsectionname);
  636. if(d != NO_ERROR) {
  637. MyFree(targetfilename);
  638. SetLastError(d);
  639. return(FALSE);
  640. }
  641. } else {
  642. logsectionname = NULL;
  643. }
  644. unicodeBuffer = MyMalloc(unicodeSize*sizeof(WCHAR));
  645. if(!unicodeBuffer) {
  646. if(targetfilename) {
  647. MyFree(targetfilename);
  648. }
  649. if(logsectionname) {
  650. MyFree(logsectionname);
  651. }
  652. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  653. return FALSE;
  654. }
  655. b = SetupQueryFileLogW(
  656. FileLogHandle,
  657. logsectionname,
  658. targetfilename,
  659. DesiredInfo,
  660. unicodeBuffer,
  661. unicodeSize,
  662. &requiredsize
  663. );
  664. d = GetLastError();
  665. if(b) {
  666. d = NO_ERROR;
  667. if(ansidata = pSetupUnicodeToAnsi(unicodeBuffer)) {
  668. requiredsize = lstrlenA(ansidata)+1;
  669. if(RequiredSize) {
  670. try {
  671. *RequiredSize = requiredsize;
  672. } except(EXCEPTION_EXECUTE_HANDLER) {
  673. b = FALSE;
  674. d = ERROR_INVALID_PARAMETER;
  675. }
  676. }
  677. if(b && DataOut) {
  678. if(ReturnBufferSize >= requiredsize) {
  679. if(!lstrcpyA(DataOut,ansidata)) {
  680. //
  681. // lstrcpy faulted, ReturnBuffer must be invalid
  682. //
  683. d = ERROR_INVALID_PARAMETER;
  684. b = FALSE;
  685. }
  686. } else {
  687. d = ERROR_INSUFFICIENT_BUFFER;
  688. b = FALSE;
  689. }
  690. }
  691. MyFree(ansidata);
  692. } else {
  693. b = FALSE;
  694. d = ERROR_NOT_ENOUGH_MEMORY;
  695. }
  696. }
  697. MyFree(targetfilename);
  698. if(logsectionname) {
  699. MyFree(logsectionname);
  700. }
  701. if(unicodeBuffer) {
  702. MyFree(unicodeBuffer);
  703. }
  704. SetLastError(d);
  705. return(b);
  706. }
  707. #else
  708. //
  709. // Unicode stub
  710. //
  711. BOOL
  712. SetupQueryFileLogW(
  713. IN HSPFILELOG FileLogHandle,
  714. IN PCWSTR LogSectionName, OPTIONAL
  715. IN PCWSTR TargetFilename,
  716. IN SetupFileLogInfo DesiredInfo,
  717. OUT PWSTR DataOut, OPTIONAL
  718. IN DWORD ReturnBufferSize,
  719. OUT PDWORD RequiredSize OPTIONAL
  720. )
  721. {
  722. UNREFERENCED_PARAMETER(FileLogHandle);
  723. UNREFERENCED_PARAMETER(LogSectionName);
  724. UNREFERENCED_PARAMETER(TargetFilename);
  725. UNREFERENCED_PARAMETER(DesiredInfo);
  726. UNREFERENCED_PARAMETER(DataOut);
  727. UNREFERENCED_PARAMETER(ReturnBufferSize);
  728. UNREFERENCED_PARAMETER(RequiredSize);
  729. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  730. return(FALSE);
  731. }
  732. #endif
  733. BOOL
  734. SetupQueryFileLog(
  735. IN HSPFILELOG FileLogHandle,
  736. IN PCTSTR LogSectionName, OPTIONAL
  737. IN PCTSTR TargetFilename,
  738. IN SetupFileLogInfo DesiredInfo,
  739. OUT PTSTR DataOut, OPTIONAL
  740. IN DWORD ReturnBufferSize,
  741. OUT PDWORD RequiredSize OPTIONAL
  742. )
  743. /*++
  744. Routine Description:
  745. Returns information from a setup file log.
  746. Arguments:
  747. FileLogHandle - supplies handle to open file log, as returned by
  748. SetupInitializeFileLog().
  749. LogSectionName - required for non-system logs; if not specified
  750. for the system log a default is supplied. Supplies the name
  751. for a logical grouping within the log that is meaningful
  752. to the caller.
  753. TargetFilename - supplies name of file for which log information
  754. is desired.
  755. DesiredInfo - supplies an ordinal indicating what information
  756. is desired about the file.
  757. DataOut - If specified, points to a buffer that receives the
  758. requested information for the file. Note that not all info
  759. is provided for every file; an error is not returned if an entry
  760. for the file exists in the log but is empty.
  761. ReturnBufferSize - supplies size of the buffer (in chars) pointed to
  762. by DataOut. If the buffer is too small and DataOut is specified,
  763. no data is stored and the function returns FALSE. If DataOut is
  764. not specified this value is ignored.
  765. RequiredSize - receives the number of characters (including the
  766. terminating nul) required to hold the result.
  767. Return Value:
  768. Boolean value indicating result. If FALSE, extended error info is
  769. available from GetLastError().
  770. --*/
  771. {
  772. DWORD Err;
  773. PSETUP_FILE_LOG FileLog;
  774. BOOL b;
  775. TCHAR ProfileValue[2*MAX_PATH];
  776. INT n;
  777. DWORD d;
  778. PTCHAR Field,End,Info;
  779. UINT InfoLength;
  780. BOOL Quoted;
  781. FileLog = (PSETUP_FILE_LOG)FileLogHandle;
  782. try {
  783. //
  784. // Validate arguments.
  785. // Section name must be supplied for non-system log.
  786. //
  787. if((!FileLog->SystemLog && !LogSectionName)
  788. || (DesiredInfo >= SetupFileLogMax) || !TargetFilename) {
  789. Err = ERROR_INVALID_PARAMETER;
  790. } else {
  791. if(!LogSectionName) {
  792. MYASSERT(FileLog->SystemLog);
  793. LogSectionName = NtFileSectionName;
  794. }
  795. //
  796. // Query the log file via profile API.
  797. //
  798. d = GetPrivateProfileString(
  799. LogSectionName,
  800. TargetFilename,
  801. TEXT(""),
  802. ProfileValue,
  803. sizeof(ProfileValue)/sizeof(ProfileValue[0]),
  804. FileLog->FileName
  805. );
  806. if(d) {
  807. //
  808. // We want to retreive the Nth item in the value we just
  809. // retreived, where N is based on what the caller wants.
  810. // This routine assumes that the SetupFileLogInfo enum is
  811. // in the same order as items appear in a line in the log!
  812. //
  813. Field = ProfileValue;
  814. n = 0;
  815. nextfield:
  816. //
  817. // Find the end of the current field, which is
  818. // the first comma, or the end of the value.
  819. // Skip leading spaces.
  820. //
  821. while(*Field == TEXT(' ')) {
  822. Field++;
  823. }
  824. End = Field;
  825. Quoted = FALSE;
  826. while(*End) {
  827. if(*End == TEXT('\"')) {
  828. Quoted = !Quoted;
  829. } else {
  830. if(!Quoted && *End == TEXT(',')) {
  831. //
  832. // Got the end of the field.
  833. //
  834. break;
  835. }
  836. }
  837. End++;
  838. }
  839. //
  840. // At this point, Field points to the start of the field
  841. // and End points at the character that terminated it.
  842. //
  843. if(n == DesiredInfo) {
  844. Info = Field;
  845. InfoLength = (UINT)(End-Field);
  846. //
  847. // Compensate for trailing space.
  848. //
  849. while (*--End == TEXT(' ')) {
  850. InfoLength--;
  851. }
  852. } else {
  853. //
  854. // Skip trailing spaces and the comma, if any.
  855. //
  856. while(*End == ' ') {
  857. End++;
  858. }
  859. if(*End == ',') {
  860. //
  861. // More fields exist.
  862. //
  863. Field = End+1;
  864. n++;
  865. goto nextfield;
  866. } else {
  867. //
  868. // Item doesn't exist.
  869. //
  870. Info = TEXT("");
  871. InfoLength = 0;
  872. }
  873. }
  874. if(RequiredSize) {
  875. *RequiredSize = InfoLength+1;
  876. }
  877. Err = NO_ERROR;
  878. if(DataOut) {
  879. if(ReturnBufferSize > InfoLength) {
  880. lstrcpyn(DataOut,Info,InfoLength+1);
  881. } else {
  882. Err = ERROR_INSUFFICIENT_BUFFER;
  883. }
  884. }
  885. } else {
  886. Err = ERROR_FILE_NOT_FOUND;
  887. }
  888. }
  889. } except(EXCEPTION_EXECUTE_HANDLER) {
  890. Err = ERROR_INVALID_PARAMETER;
  891. }
  892. SetLastError(Err);
  893. return(Err == NO_ERROR);
  894. }