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.

284 lines
6.2 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <tchar.h>
  4. #include <shellapi.h>
  5. #include <setupapi.h>
  6. #include <spapip.h>
  7. #include <sfcapip.h>
  8. #define ALLOWRENAMES TEXT("AllowProtectedRenames")
  9. extern void RestartDialog(VOID *, VOID *, UINT);
  10. void
  11. PrintUsage(
  12. void
  13. )
  14. {
  15. printf("allows copying a protected system file\n");
  16. printf("if the file is in use, you will have to reboot.\n");
  17. printf("Usage: sfpcopy -q [source] [destination]\n");
  18. printf(" q: silent mode: if the file is in use, force a reboot\n");
  19. return;
  20. }
  21. BOOL
  22. FileExists(
  23. IN PCTSTR FileName,
  24. OUT PWIN32_FIND_DATA FindData OPTIONAL
  25. )
  26. /*++
  27. Routine Description:
  28. Determine if a file exists and is accessible.
  29. Errormode is set (and then restored) so the user will not see
  30. any pop-ups.
  31. Arguments:
  32. FileName - supplies full path of file to check for existance.
  33. FindData - if specified, receives find data for the file.
  34. Return Value:
  35. TRUE if the file exists and is accessible.
  36. FALSE if not. GetLastError() returns extended error info.
  37. --*/
  38. {
  39. WIN32_FIND_DATA findData;
  40. HANDLE FindHandle;
  41. UINT OldMode;
  42. DWORD Error;
  43. OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  44. FindHandle = FindFirstFile(FileName,&findData);
  45. if(FindHandle == INVALID_HANDLE_VALUE) {
  46. Error = GetLastError();
  47. } else {
  48. FindClose(FindHandle);
  49. if(FindData) {
  50. *FindData = findData;
  51. }
  52. Error = NO_ERROR;
  53. }
  54. SetErrorMode(OldMode);
  55. SetLastError(Error);
  56. return (Error == NO_ERROR);
  57. }
  58. BOOL
  59. pSetupProtectedRenamesFlag(
  60. BOOL bSet
  61. )
  62. {
  63. HKEY hKey;
  64. long rslt = ERROR_SUCCESS;
  65. rslt = RegOpenKeyEx(
  66. HKEY_LOCAL_MACHINE,
  67. TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
  68. 0,
  69. KEY_SET_VALUE,
  70. &hKey
  71. );
  72. if (rslt == ERROR_SUCCESS) {
  73. DWORD Value = bSet ? 1 : 0;
  74. rslt = RegSetValueEx(
  75. hKey,
  76. TEXT("AllowProtectedRenames"),
  77. 0,
  78. REG_DWORD,
  79. (LPBYTE)&Value,
  80. sizeof(DWORD)
  81. );
  82. RegCloseKey(hKey);
  83. }
  84. return(rslt == ERROR_SUCCESS);
  85. }
  86. int _cdecl
  87. wmain(
  88. int argc,
  89. WCHAR *argv[]
  90. )
  91. {
  92. LPTSTR TargetName = NULL,SourceName=NULL;
  93. TCHAR TargetDir[MAX_PATH];
  94. TCHAR TempFile[MAX_PATH];
  95. LPTSTR p;
  96. BOOL SilentMode = FALSE;
  97. BOOL NeedReboot = FALSE;
  98. HANDLE hSfp;
  99. DWORD Result = NO_ERROR;
  100. //
  101. // parse args
  102. //
  103. while (--argc) {
  104. argv++;
  105. if ((argv[0][0] == TEXT('-')) || (argv[0][0] == TEXT('/'))) {
  106. switch (argv[0][1]) {
  107. case TEXT('q'):
  108. case TEXT('Q'):
  109. SilentMode = TRUE;
  110. goto Next;
  111. break;
  112. default:
  113. PrintUsage();
  114. return -1;
  115. }
  116. }
  117. if (!SourceName) {
  118. SourceName = argv[0];
  119. } else if (!TargetName) {
  120. TargetName = argv[0];
  121. } else {
  122. PrintUsage();
  123. return -1;
  124. }
  125. Next:
  126. ;
  127. }
  128. //
  129. // Validate files are really there
  130. //
  131. if (!SourceName || !TargetName) {
  132. PrintUsage();
  133. return -1;
  134. }
  135. if (!FileExists(SourceName,NULL)) {
  136. printf("Invalid Source File\n");
  137. PrintUsage();
  138. return -1;
  139. }
  140. if (!FileExists(TargetName,NULL)) {
  141. printf("Invalid Target File\n");
  142. PrintUsage();
  143. return -1;
  144. }
  145. //
  146. // unprotect the file
  147. //
  148. hSfp = SfcConnectToServer( NULL );
  149. if (hSfp) {
  150. if (SfcIsFileProtected(hSfp,TargetName)) {
  151. Result = SfcFileException(
  152. hSfp,
  153. (PWSTR) TargetName,
  154. (DWORD) -1
  155. );
  156. if (Result != NO_ERROR) {
  157. printf("Couldn't unprotect file, ec = %d\n", Result);
  158. goto exit;
  159. }
  160. } else {
  161. if (!SilentMode) {
  162. printf("target file is not protected\n");
  163. }
  164. }
  165. SfcClose(hSfp);
  166. }
  167. //
  168. // copy the file
  169. //
  170. _tcscpy(TargetDir,TargetName);
  171. p = _tcsrchr(TargetDir,TEXT('\\'));
  172. if (p) {
  173. *p = (TCHAR)NULL;
  174. }
  175. GetTempFileName(TargetDir,TEXT("sfp"),0,TempFile);
  176. _tprintf( TEXT("Copying %s --> %s\n"), SourceName, TargetName);
  177. Result = 1;
  178. if (CopyFile(SourceName,TempFile,FALSE)) {
  179. if (!MoveFileEx(TempFile,TargetName,MOVEFILE_REPLACE_EXISTING)) {
  180. if (MoveFileEx(
  181. TempFile,
  182. TargetName,
  183. MOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOT)
  184. )
  185. {
  186. NeedReboot = TRUE;
  187. Result = NO_ERROR;
  188. }
  189. } else {
  190. Result = NO_ERROR;
  191. }
  192. } else {
  193. Result = GetLastError();
  194. }
  195. if (Result != NO_ERROR) {
  196. Result = GetLastError();
  197. printf("Failed to copy file, ec = %d\n", Result);
  198. }
  199. //
  200. // Reboot if necessary
  201. //
  202. if (Result == NO_ERROR && NeedReboot) {
  203. pSetupProtectedRenamesFlag(TRUE);
  204. if (SilentMode) {
  205. HANDLE hToken;
  206. TOKEN_PRIVILEGES tkp; // Get a token for this process.
  207. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken)) {
  208. printf("Can't force silent reboot\n");
  209. goto verbose;
  210. }
  211. LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
  212. tkp.PrivilegeCount = 1; // one privilege to set
  213. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  214. // Get the shutdown privilege for this process.
  215. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
  216. //
  217. // Shut down the system and force all applications to close.
  218. //
  219. if (! ExitWindowsEx(EWX_REBOOT|EWX_FORCE , 0) ) {
  220. printf("Can't force silent reboot\n");
  221. goto verbose;
  222. }
  223. } else {
  224. verbose:
  225. RestartDialog(NULL,NULL,EWX_REBOOT);
  226. }
  227. }
  228. exit:
  229. return Result;
  230. }