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.

329 lines
8.4 KiB

  1. #include "windows.h"
  2. #include "ntverp.h"
  3. #include <string>
  4. #include <xstring>
  5. #include <utility>
  6. #include <vector>
  7. using namespace std;
  8. bool g_BufferStdInFully = false;
  9. bool g_LockPerItem = false;
  10. HANDLE ObtainFileHandle(wstring& wsFileName);
  11. class CTargetFile
  12. {
  13. wstring m_wsTargetName;
  14. HANDLE hFile;
  15. public:
  16. CTargetFile(wstring& wsT) : m_wsTargetName(wsT), hFile(INVALID_HANDLE_VALUE) { };
  17. ~CTargetFile()
  18. {
  19. CloseFile();
  20. }
  21. BOOL EnsureOpen()
  22. {
  23. if (hFile == INVALID_HANDLE_VALUE)
  24. {
  25. hFile = ObtainFileHandle(m_wsTargetName);
  26. }
  27. return hFile != INVALID_HANDLE_VALUE;
  28. }
  29. BOOL CloseFile()
  30. {
  31. if (hFile != INVALID_HANDLE_VALUE)
  32. {
  33. CloseHandle(hFile);
  34. hFile = INVALID_HANDLE_VALUE;
  35. }
  36. return hFile == INVALID_HANDLE_VALUE;
  37. }
  38. BOOL SetFilePointerToEnd()
  39. {
  40. DWORD dwResult = SetFilePointer(hFile, 0, NULL, FILE_END);
  41. if ((dwResult == INVALID_SET_FILE_POINTER) && GetLastError())
  42. {
  43. dwResult = GetLastError();
  44. return FALSE;
  45. }
  46. return TRUE;
  47. }
  48. BOOL AppendData(PBYTE pbData, DWORD dwDataSize, DWORD& dwWritten)
  49. {
  50. LONG dwHighFileOffset = 0;
  51. DWORD dwResult = 0;
  52. BOOL fResult = FALSE;
  53. OVERLAPPED ol;
  54. if (EnsureOpen() && SetFilePointerToEnd())
  55. {
  56. fResult = WriteFile(hFile, pbData, dwDataSize, &dwWritten, NULL);
  57. if (!fResult)
  58. {
  59. dwResult = GetLastError();
  60. }
  61. }
  62. return fResult;
  63. }
  64. };
  65. //
  66. // Append from stdin
  67. //
  68. BOOL AppendStdIn(CTargetFile& Target)
  69. {
  70. HANDLE hStdInput;
  71. DWORD dwReadChars, dwWritten;
  72. vector<BYTE> vbDataBlob;
  73. vector<BYTE> vbDataBlobIntermediate;
  74. vbDataBlobIntermediate.resize(4096);
  75. hStdInput = GetStdHandle(STD_INPUT_HANDLE);
  76. if ((hStdInput == INVALID_HANDLE_VALUE) || !hStdInput)
  77. {
  78. return FALSE;
  79. }
  80. while (ReadFile(hStdInput, &vbDataBlobIntermediate.front(), vbDataBlobIntermediate.size(), &dwReadChars, NULL))
  81. {
  82. if (!dwReadChars)
  83. {
  84. break;
  85. }
  86. else
  87. {
  88. if (g_BufferStdInFully)
  89. {
  90. vbDataBlob.insert(
  91. vbDataBlob.end(),
  92. vbDataBlobIntermediate.begin(),
  93. vbDataBlobIntermediate.end());
  94. }
  95. else
  96. {
  97. if (!Target.AppendData(&vbDataBlobIntermediate.front(), dwReadChars, dwWritten))
  98. {
  99. return FALSE;
  100. }
  101. }
  102. }
  103. }
  104. if ((dwReadChars == 0) && g_BufferStdInFully)
  105. {
  106. if (!Target.AppendData(&vbDataBlob.front(), vbDataBlob.size(), dwWritten))
  107. {
  108. return FALSE;
  109. }
  110. }
  111. return (dwReadChars == 0);
  112. }
  113. vector< wstring > AppendingSources;
  114. BOOL WorkHorse(wstring& wsTargetFile)
  115. {
  116. BOOL bOk = FALSE;
  117. bool bHasReadStdIn = false;
  118. CTargetFile TargetFile(wsTargetFile);
  119. if (!g_LockPerItem) TargetFile.EnsureOpen();
  120. for (vector<wstring>::const_iterator i = AppendingSources.begin();
  121. i != AppendingSources.end();
  122. i++)
  123. {
  124. if (*i == L"-")
  125. {
  126. if (g_LockPerItem) TargetFile.EnsureOpen();
  127. if (!bHasReadStdIn)
  128. {
  129. bHasReadStdIn = true;
  130. if (!AppendStdIn(TargetFile))
  131. {
  132. goto Exit;
  133. }
  134. }
  135. else
  136. {
  137. fwprintf(stderr, L"Can't read from stdin multiple times - found '-' twice!\n");
  138. SetLastError(ERROR_INVALID_PARAMETER);
  139. goto Exit;
  140. }
  141. if (g_LockPerItem) TargetFile.CloseFile();
  142. }
  143. else
  144. {
  145. fwprintf(stderr, L"We don't support reading in files yet, sorry.\n");
  146. SetLastError(ERROR_INVALID_PARAMETER);
  147. goto Exit;
  148. }
  149. }
  150. bOk = TRUE;
  151. Exit:
  152. return bOk;
  153. }
  154. HANDLE
  155. ObtainFileHandle(wstring& wsFileName)
  156. {
  157. HANDLE hFile = INVALID_HANDLE_VALUE;
  158. DWORD dwSleepTime = 250; // Start at 250ms sleep
  159. float flBackoffRate = 1.1f; // Backoff at 1.1x the sleep length
  160. DWORD dwMaxSleepTime = 5000; // Don't ever sleep for more than 5 seconds at a time
  161. DWORD dwMaxTicksAtThisSleepTime = 10; // Try the sleep time 10 times in a row
  162. DWORD dwTicksAtThisSleepTime = dwMaxTicksAtThisSleepTime;
  163. DWORD dwError = 0;
  164. //
  165. // We attempt to lock the file based on no sharing. If it fails with a sharing
  166. // violation, then we back off for a while and try again later.
  167. //
  168. while (true)
  169. {
  170. hFile = CreateFileW(
  171. wsFileName.c_str(),
  172. GENERIC_WRITE,
  173. 0,
  174. NULL,
  175. OPEN_ALWAYS,
  176. FILE_ATTRIBUTE_NORMAL,
  177. NULL);
  178. dwError = ::GetLastError();
  179. // If we've gotten a good handle back, stop looking.
  180. if ((hFile != INVALID_HANDLE_VALUE) && (hFile != NULL))
  181. {
  182. break;
  183. }
  184. else
  185. {
  186. // If the error was a sharing violation, then back off for a bit and
  187. // try again.
  188. if (dwError == ERROR_SHARING_VIOLATION)
  189. {
  190. Sleep(dwSleepTime);
  191. if (dwTicksAtThisSleepTime == 0)
  192. {
  193. dwTicksAtThisSleepTime = dwMaxTicksAtThisSleepTime;
  194. dwSleepTime = (DWORD)((float)dwSleepTime * flBackoffRate);
  195. continue;
  196. }
  197. }
  198. // Otherwise, something else bad happened, so quit trying
  199. else
  200. {
  201. hFile = INVALID_HANDLE_VALUE;
  202. break;
  203. }
  204. }
  205. }
  206. return hFile;
  207. }
  208. void PrintUsage()
  209. {
  210. wprintf(L"<-file <output>> [-verbose] [-bufferstdin] [-atomicperitem] <[-] [file [...]]>\n");
  211. wprintf(L"\n");
  212. wprintf(L"-bufferstdin Buffer all of stdin (-) before writing\n");
  213. wprintf(L"-atomicperitem Lock the file per item, not per run\n");
  214. wprintf(L"-file <name> What file should be written out to\n");
  215. wprintf(L"-verbose Up the verbosity of debug spew (if any)\n");
  216. wprintf(L"- Read from stdin into the output file.\n");
  217. }
  218. int __cdecl wmain(int argc, WCHAR** argv)
  219. {
  220. wstring wsAppendTarget;
  221. vector<wstring> wstParams;
  222. bool bInGatheringData = false;
  223. DWORD dwVerbosity = 0;
  224. HANDLE hFile = INVALID_HANDLE_VALUE;
  225. for (int i = 1; i < argc; i++)
  226. {
  227. wstParams.push_back(argv[i]);
  228. }
  229. if (wstParams.empty())
  230. {
  231. PrintUsage();
  232. return 1;
  233. }
  234. //
  235. // Syntax:
  236. //
  237. // <-file <output>> [-verbose] [-] file1 file2 ...
  238. //
  239. // - - Indicates that the console should be read for input at this point
  240. // -file <output file> - Specify output destination
  241. // -verbose - How noisy? +1 noise level per instance
  242. //
  243. for (vector<wstring>::iterator i = wstParams.begin(); i != wstParams.end(); i++)
  244. {
  245. if (bInGatheringData)
  246. {
  247. AppendingSources.push_back(*i);
  248. }
  249. else if (*i == wstring(L"-file"))
  250. {
  251. wsAppendTarget = *++i;
  252. }
  253. else if (*i == wstring(L"-?"))
  254. {
  255. PrintUsage();
  256. return 1;
  257. }
  258. else if (*i == wstring(L"-bufferstdin"))
  259. {
  260. g_BufferStdInFully = true;
  261. }
  262. else if (*i == wstring(L"-atomicperitem"))
  263. {
  264. g_LockPerItem = true;
  265. }
  266. else if (*i == L"-verbose")
  267. {
  268. dwVerbosity++;
  269. }
  270. else
  271. {
  272. bInGatheringData = true;
  273. AppendingSources.push_back(*i);
  274. }
  275. }
  276. //
  277. // No target or sources?
  278. //
  279. if ((wsAppendTarget.size() == 0) || (AppendingSources.size() == 0))
  280. {
  281. PrintUsage();
  282. return 1;
  283. }
  284. WorkHorse(wsAppendTarget);
  285. }