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.

722 lines
20 KiB

  1. // Set TestUnEval to 1 to enable uneval testing
  2. @set @TestUnEval = 0
  3. //---------------------------------------------------------------------------
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1995
  7. //
  8. // File: utilthrd.js
  9. //
  10. // Contents: Script which contains a bunch of utility functions used by
  11. // other threads. It sets up function pointers on the PrivateData
  12. // object which is how these functions can be utilized.
  13. //
  14. //----------------------------------------------------------------------------
  15. Include('types.js');
  16. Include('utils.js');
  17. //Include('stopwatch.js');
  18. // File System Object
  19. var g_FSObj;
  20. var g_DepthCounter = 0;
  21. function utilthrd_js::OnScriptError(strFile, nLine, nChar, strText, sCode, strSource, strDescription)
  22. {
  23. return CommonOnScriptError("utilthrd_js", strFile, nLine, nChar, strText, sCode, strSource, strDescription);
  24. }
  25. function utilthrd_js::ScriptMain()
  26. {
  27. JAssert(typeof(PrivateData) == 'object', 'PrivateData not initialized!');
  28. g_FSObj = new ActiveXObject("Scripting.FileSystemObject"); // Parse input Parameter List
  29. PrivateData.objUtil.fnLoadXML = XMLLoad;
  30. PrivateData.objUtil.fnUneval = uneval;
  31. PrivateData.objUtil.fnDeleteFileNoThrow = DeleteFileNoThrow;
  32. PrivateData.objUtil.fnMoveFileNoThrow = MoveFileNoThrow;
  33. PrivateData.objUtil.fnCreateFolderNoThrow = CreateFolderNoThrow;
  34. PrivateData.objUtil.fnDirScanNoThrow = DirScanNoThrow;
  35. PrivateData.objUtil.fnCopyFileNoThrow = CopyFileNoThrow;
  36. PrivateData.objUtil.fnCreateHistoriedFile = CreateHistoriedFile;
  37. PrivateData.objUtil.fnCreateNumberedFile = CreateNumberedFile;
  38. // PrivateData.objUtil.fnBeginWatch = BeginWatch;
  39. // PrivateData.objUtil.fnDumpTimes = DumpTimes;
  40. PrivateData.objUtil.fnMyEval = MyEval;
  41. g_DepthCounter = 0;
  42. SignalThreadSync('UtilityThreadReady');
  43. CommonVersionCheck(/* $DROPVERSION: */ "V(########) F(!!!!!!!!!!!!!!)" /* $ */);
  44. @if (@TestUnEval == 1)
  45. LogMsg("TESTUNEVAL IS " + @TestUnEval);
  46. var o1 = new Object();
  47. var o2 = new Object();
  48. var o3 = new Object();
  49. var o4 = new Object();
  50. var or1, or2, or3, or4;
  51. o1.a = "hello 'there' bozo";
  52. o2.a = 'hello "there" bozo';
  53. o3.a = "hello \\there\\ bo \\\\ zo";
  54. o4.a = "hello \n foo \r bar";
  55. or1 = evtest(o1);
  56. or2 = evtest(o2);
  57. or3 = evtest(o3);
  58. or4 = evtest(o4);
  59. debugger;
  60. @end
  61. WaitForSync('UtilityThreadExit', 0);
  62. }
  63. @if (@TestUnEval == 1)
  64. function evtest(obj)
  65. {
  66. var u;
  67. var result;
  68. try
  69. {
  70. u = PrivateData.objUtil.fnUneval(obj);
  71. }
  72. catch(ex)
  73. {
  74. debugger;
  75. return;
  76. }
  77. try
  78. {
  79. result = MyEval(u);
  80. }
  81. catch(ex)
  82. {
  83. debugger;
  84. return;
  85. }
  86. return result;
  87. }
  88. @end
  89. //+---------------------------------------------------------------------------
  90. //
  91. // Function: uneval
  92. //
  93. // Synopsis: Takes an object and returns a string. The string can be given
  94. // to the 'eval' function which will then return a copy of the
  95. // object.
  96. //
  97. // Arguments: [obj] -- Object to 'stringize';
  98. //
  99. //----------------------------------------------------------------------------
  100. function uneval(obj)
  101. {
  102. ++g_DepthCounter;
  103. try
  104. {
  105. if (!unevalInitialized)
  106. {
  107. initUneval();
  108. unevalInitialized = true;
  109. }
  110. if (g_DepthCounter != 1)
  111. LogMsg("Oops - uneval reentered!");
  112. PrivateData.objUtil.unevalNextID = 0;
  113. var s = 'var undefined;' + unevalDecl(obj) + unevalInst(obj);
  114. unevalClear(obj);
  115. }
  116. catch(ex)
  117. {
  118. LogMsg("Uneval threw " + ex);
  119. --g_DepthCounter;
  120. throw(ex);
  121. }
  122. --g_DepthCounter;
  123. return s;
  124. }
  125. //+---------------------------------------------------------------------------
  126. //
  127. // Function: XMLLoad
  128. //
  129. // Synopsis: Loads an XML file into the given object
  130. //
  131. // Arguments: [obj] -- Object to set values into (must be a 'new Object()')
  132. // [url] -- URL of XML file
  133. // [strSchema] -- If not null, the loaded XML file must reference
  134. // a schema by the given name.
  135. // [aStrMap] -- String mapping for substitutions
  136. //
  137. // Returns: 'ok', or a string giving error information
  138. //
  139. // Notes: To see what this function does, consider the following XML:
  140. //
  141. // <root>
  142. // <Template Name="Template1" fBuild="false">
  143. // <URL>foobar.xml</URL>
  144. // </Template>
  145. // <Template Name="Template2" fBuild="true">
  146. // <URL>barfoo.xml</URL>
  147. // </Template>
  148. // </root>
  149. //
  150. // This function, given the above XML file, will make 'obj' look
  151. // the same as if the following JScript had been written:
  152. //
  153. // obj.Template = new Array();
  154. //
  155. // obj.Template[0].Name = 'Template1';
  156. // obj.Template[0].fBuild = false;
  157. // obj.Template[0].URL = 'foobar.xml';
  158. //
  159. // obj.Template[1].Name = 'Template2';
  160. // obj.Template[1].fBuild = true;
  161. // obj.Template[1].URL = 'barfoo.xml';
  162. //
  163. //----------------------------------------------------------------------------
  164. function XMLLoad(obj, url, strSchema, aStrMap)
  165. {
  166. var newurl;
  167. var objXML = new ActiveXObject("Microsoft.XMLDOM");
  168. var aNewStrMap = new Array();
  169. newurl = url;
  170. InitStringMaps(aStrMap, aNewStrMap);
  171. try
  172. {
  173. var fRet;
  174. var fDownloaded = false;
  175. var strError;
  176. objXML.async = false;
  177. if (url.slice(0, 5) == 'XML: ')
  178. {
  179. fDownloaded = true;
  180. newurl = CreateLocalTemplate(g_FSObj, url.slice(5), strSchema);
  181. }
  182. if (!newurl)
  183. {
  184. return 'Unable to make local copy of XML file';
  185. }
  186. fRet = objXML.load(newurl);
  187. if (fDownloaded)
  188. {
  189. g_FSObj.DeleteFile(newurl, true);
  190. }
  191. if (!fRet)
  192. {
  193. with (objXML.parseError)
  194. {
  195. if (reason.length > 0)
  196. {
  197. strError = 'error loading XML file: ' + reason + '\n(' + newurl + ' line ' + line + ') :\n"' + srcText + '"';
  198. if (errorCode == -2146697208) // W3_EVENT_CANNOT_CREATE_CLIENT_CONN
  199. strError += "\nYou may have exceeded the maximum number of connections to this IIS server";
  200. return strError;
  201. }
  202. else
  203. return '1: could not load XML file: ' + newurl;
  204. }
  205. }
  206. }
  207. catch(ex)
  208. {
  209. return '2: could not load XML file ' + newurl + ': ' + ex;
  210. }
  211. if (!objXML.documentElement)
  212. {
  213. return '3: could not load XML file: ' + newurl;
  214. }
  215. try
  216. {
  217. ReadXMLNodesIntoObject(obj, objXML.documentElement, aNewStrMap, (strSchema != null));
  218. }
  219. catch(ex)
  220. {
  221. return "ReadXMLNodesIntoObject failed: " + ex;
  222. }
  223. return 'ok';
  224. }
  225. //+---------------------------------------------------------------------------
  226. //
  227. // Function: CreateLocalTemplate
  228. //
  229. // Synopsis: Creates a temporary file with the XML that was downloaded to
  230. // us by the UI, and copies the schema file into the same
  231. // directory so it can be referenced.
  232. //
  233. // Arguments: [objFS] -- FileSystem object
  234. // [xml] -- XML given to us by the UI.
  235. // [strSchema] -- Name of the schema file we should copy.
  236. //
  237. // Notes: Will throw exceptions on errors.
  238. //
  239. //----------------------------------------------------------------------------
  240. function CreateLocalTemplate(objFS, xml, strSchema)
  241. {
  242. var tempdir = objFS.GetSpecialFolder(2 /* Temp Folder */).Path;
  243. var tempfile = objFS.GetTempName();
  244. var xmlfile;
  245. xmlfile = objFS.CreateTextFile(tempdir + '\\' + tempfile, true);
  246. xmlfile.Write(xml);
  247. xmlfile.Close();
  248. xmlfile = null;
  249. DeleteFileNoThrow(tempdir + '\\' + strSchema, true);
  250. objFS.CopyFile(ScriptPath + '\\' + strSchema, tempdir + '\\' + strSchema, true);
  251. return tempdir + '\\' + tempfile;
  252. }
  253. //+---------------------------------------------------------------------------
  254. //
  255. // Function: ReadXMLNodesIntoObject
  256. //
  257. // Synopsis: Given an XML element node, read in the values and/or subobjects
  258. // of that node into the given object.
  259. //
  260. // Arguments: [obj] -- Object to read values into
  261. // [node] -- XML node that contains the data we're reading
  262. // [aStrMap] -- String mapping for substitutions
  263. // [fSchema] -- If true, all attributes and elements must have
  264. // a matching schema definition.
  265. //
  266. //----------------------------------------------------------------------------
  267. function ReadXMLNodesIntoObject(obj, node, aStrMap, fSchema)
  268. {
  269. var childnode;
  270. var nodelist;
  271. var attlist;
  272. var att;
  273. attlist = node.attributes;
  274. for (att = attlist.nextNode();
  275. att;
  276. att = attlist.nextNode())
  277. {
  278. AddNodeToObject(att, obj, aStrMap, fSchema);
  279. }
  280. nodelist = node.childNodes;
  281. for (childnode = nodelist.nextNode();
  282. childnode;
  283. childnode = nodelist.nextNode())
  284. {
  285. AddNodeToObject(childnode, obj, aStrMap, fSchema);
  286. }
  287. return true;
  288. }
  289. function AddNodeToObject(node, obj, aStrMap, fSchema)
  290. {
  291. var name;
  292. var type;
  293. var value;
  294. var fIsArray;
  295. var cChildren;
  296. var define;
  297. var subobj = obj;
  298. // Do we recognize this node type? If not, skip it.
  299. if ( node.nodeTypeString != 'element'
  300. && node.nodeTypeString != 'attribute')
  301. {
  302. return;
  303. }
  304. name = node.nodeName;
  305. define = node.definition;
  306. if (node.nodeTypeString == 'element')
  307. {
  308. type = node.getAttribute("type");
  309. }
  310. else
  311. {
  312. // We never want the type attribute to get put as a value on the obj.
  313. // It should merely affect how we create it.
  314. if (name == 'type')
  315. {
  316. return;
  317. }
  318. type = null;
  319. }
  320. if ( fSchema
  321. && name != 'xmlns'
  322. && ( !define
  323. || define.getAttribute("name") != name))
  324. {
  325. var err = new Error(-1, 'Element ' + name + ' has no type information! Verify that a schema was referenced.');
  326. throw(err);
  327. }
  328. // If the only child of this node is a text node, then we just grab
  329. // the value. Otherwise we walk its children (elements & attributes).
  330. cChildren = node.childNodes.length + ((node.attributes) ? node.attributes.length : 0);
  331. // Don't consider the type attribute to be a 'child'
  332. if (type != null)
  333. {
  334. JAssert(cChildren > 0, 'Invalid number of children during XML parse!');
  335. cChildren--;
  336. }
  337. if ( cChildren == 0
  338. || ( cChildren == 1
  339. && node.childNodes.length == 1
  340. && ( node.firstChild.nodeTypeString == 'text'
  341. || node.firstChild.nodeTypeString == 'cdatasection')))
  342. {
  343. value = node.nodeTypedValue;
  344. if (typeof(value) == 'string')
  345. {
  346. // Make sure boolean values end up as booleans not strings
  347. if (value.toLowerCase() == 'true')
  348. {
  349. value = true;
  350. }
  351. else if (value.toLowerCase() == 'false')
  352. {
  353. value = false;
  354. }
  355. else
  356. {
  357. value = value.Substitute(aStrMap);
  358. }
  359. }
  360. if (obj[name] != null || (type && type == 'array'))
  361. {
  362. // The value of this field was already set. Turn it into an
  363. // array.
  364. EnsureArray(obj, name);
  365. obj[name][obj[name].length] = value;
  366. }
  367. else
  368. {
  369. obj[name] = value;
  370. }
  371. }
  372. else
  373. {
  374. fIsArray = false;
  375. if (obj[name] != null || (type && type == 'array'))
  376. {
  377. // We've already encountered one of these. Make it into an array.
  378. fIsArray = true;
  379. EnsureArray(obj, name);
  380. }
  381. subobj = new Object();
  382. if (fIsArray)
  383. {
  384. obj[name][obj[name].length] = subobj;
  385. }
  386. else
  387. {
  388. obj[name] = subobj;
  389. }
  390. }
  391. if (node.nodeTypeString == 'element')
  392. {
  393. ReadXMLNodesIntoObject(subobj, node, aStrMap, fSchema);
  394. }
  395. }
  396. // DeleteFileNoThrow(strFileName, fForce)
  397. // Wrap the FSObj.DeleteFile call to prevent it from
  398. // throwing its errors.
  399. // This is good when you do not really care if the
  400. // file you are trying to delete does not exist.
  401. function DeleteFileNoThrow(strFileName, fForce)
  402. {
  403. try
  404. {
  405. LogMsg("DELETE FILE " + strFileName);
  406. g_FSObj.DeleteFile(strFileName, true);
  407. }
  408. catch(ex)
  409. {
  410. return ex;
  411. }
  412. return null;
  413. }
  414. // MoveFileNoThrow(strSrc, strDst)
  415. // Wrap the FSObj.MoveFile call to prevent it from
  416. // throwing its errors.
  417. function MoveFileNoThrow(strSrc, strDst)
  418. {
  419. try
  420. {
  421. LogMsg("Move file from " + strSrc + " to " + strDst);
  422. g_FSObj.MoveFile(strSrc, strDst);
  423. }
  424. catch(ex)
  425. {
  426. LogMsg("MoveFile failed from " + strSrc + " to " + strDst + " " + ex);
  427. return ex;
  428. }
  429. return null;
  430. }
  431. // CopyFileNoThrow(strSrc, strDst)
  432. // Wrap the FSObj.CopyFile call to prevent it from
  433. // throwing its errors.
  434. function CopyFileNoThrow(strSrc, strDst)
  435. {
  436. try
  437. {
  438. LogMsg("COPY FILE from " + strSrc + " to " + strDst);
  439. g_FSObj.CopyFile(strSrc, strDst, true);
  440. }
  441. catch(ex)
  442. {
  443. LogMsg("Copy failed from " + strSrc + " to " + strDst + " " + ex);
  444. return ex;
  445. }
  446. return null;
  447. }
  448. // CreateFolderNoThrow(strSrc, strDst)
  449. // Wrap the FSObj.MakeFolder call to prevent it from
  450. // throwing its errors.
  451. function CreateFolderNoThrow(strName)
  452. {
  453. try
  454. {
  455. LogMsg(strName);
  456. g_FSObj.CreateFolder(strName);
  457. }
  458. catch(ex)
  459. {
  460. return ex;
  461. }
  462. return null;
  463. }
  464. // DirScanNoThrow(strDir)
  465. // Wrap the FSObj.Directory scan functionality to prevent it from
  466. // throwing its errors.
  467. function DirScanNoThrow(strDir)
  468. {
  469. var aFiles = new Array();
  470. try
  471. {
  472. LogMsg("DIRSCAN " + strDir);
  473. var folder;
  474. var fc;
  475. folder = g_FSObj.GetFolder(strDir);
  476. fc = new Enumerator(folder.files);
  477. for (; !fc.atEnd(); fc.moveNext())
  478. {
  479. aFiles[aFiles.length] = fc.item().Name; // fc.item() returns entire path, fc.item().Name is just the filename
  480. }
  481. }
  482. catch(ex)
  483. {
  484. aFiles.ex = ex;
  485. }
  486. return aFiles;
  487. }
  488. // CreateNumberedFileName(strFileName, nNumber, cDigits, strSeperator)
  489. // Add a number to the supplied filename.
  490. // Ensure that the number has cDigits digits.
  491. // Prefix the number with strSeperator.
  492. // For example:
  493. // foo.txt --> foo_001.txt
  494. function CreateNumberedFileName(strFileName, nNumber, cDigits, strSeperator)
  495. {
  496. var i;
  497. var strNumber;
  498. var strBase;
  499. var strExt;
  500. strNumber = PadDigits(nNumber, cDigits);
  501. strSplit = strFileName.SplitFileName();
  502. return strSplit[0] + strSplit[1] + strSeperator + strNumber + strSplit[2];
  503. }
  504. // CreateHistoriedFile(strBaseName, nLimit)
  505. // Create a numbered history of files base on the
  506. // supplied filename. For example, if you supply "log.txt"
  507. // this function will renumber files
  508. // log.txt -> log_01.txt
  509. // log_01.txt -> log_02.txt
  510. // log_10.txt -> deleted
  511. //
  512. function CreateHistoriedFile(strBaseName, nLimit)
  513. {
  514. var i;
  515. var strNewName;
  516. var strOldName;
  517. var cDigits = 3;
  518. var file;
  519. var strTempDir;
  520. try
  521. {
  522. strTempDir = g_FSObj.GetSpecialFolder(2).Path; // Temp Folder
  523. strBaseName = strTempDir + '\\' + LocalMachine + '_' + strBaseName;
  524. if (nLimit)
  525. {
  526. strNewName = CreateNumberedFileName(strBaseName, nLimit, cDigits, "_");
  527. DeleteFileNoThrow(strNewName, true);
  528. for(i = nLimit - 1; i > 0; --i)
  529. {
  530. strOldName = CreateNumberedFileName(strBaseName, i, cDigits, "_");
  531. MoveFileNoThrow(strOldName, strNewName);
  532. strNewName = strOldName;
  533. }
  534. MoveFileNoThrow(strBaseName, strNewName);
  535. }
  536. file = g_FSObj.CreateTextFile(strBaseName, true);
  537. }
  538. catch(ex)
  539. {
  540. LogMsg("an error occurred while executing 'CreateHistoriedFile('" + strBaseName + "') " + ex);
  541. throw ex;
  542. }
  543. return file;
  544. }
  545. // CreateNumberedFile(strBaseName, nLimit)
  546. // This is similar to CreateHistoriedFile(), but it uses a more
  547. // robust naming scheme.
  548. // Here the newly created file is numbered one greater than
  549. // any other same named logfiles in the given directory.
  550. // So, the first time you call this function the created file
  551. // would be called
  552. // log.01.txt
  553. // The next time it will be
  554. // log.02.txt
  555. //
  556. // Note: This function preceeds the number with a dot instead of
  557. // underscore to prevent confusion with CreateHistoriedFile().
  558. //
  559. // Returns:
  560. // array of TextString and the filename
  561. function CreateNumberedFile(strBaseName, nLimit)
  562. {
  563. var i;
  564. var strFileName;
  565. var cDigits = 3;
  566. var file;
  567. try
  568. {
  569. // First, locate the highest index in the directory.
  570. var folder;
  571. var enumFolder;
  572. var re;
  573. var reResult;
  574. var nLargestIndex = 0;
  575. var strTempDir;
  576. strTempDir = g_FSObj.GetSpecialFolder(2).Path; // Temp Folder
  577. strBaseName = strTempDir + '\\' + LocalMachine + '_' + strBaseName;
  578. strSplit = strBaseName.SplitFileName();
  579. // Make an RE of the form: "/^filenamebase.([0-9]+]).ext$/i"
  580. re = new RegExp("^" + g_FSObj.GetBaseName(strBaseName) + ".([0-9]+)" + strSplit[2] + "$", "i");
  581. folder = g_FSObj.GetFolder(g_FSObj.GetParentFolderName(strBaseName));
  582. enumFolder = new Enumerator(folder.files);
  583. // First, scan for the largest index for the given filename
  584. for (; !enumFolder.atEnd(); enumFolder.moveNext())
  585. {
  586. strFileName = enumFolder.item();
  587. reResult = re.exec(strFileName.Name);
  588. if (reResult != null)
  589. {
  590. if (Number(reResult[1]) > nLargestIndex)
  591. nLargestIndex = Number(reResult[1]);
  592. if (reResult[1].length > cDigits)
  593. cDigits = reResult[1].length;
  594. }
  595. }
  596. // Create a file with the next largest index
  597. strFileName = CreateNumberedFileName(strBaseName, nLargestIndex + 1, cDigits, ".");
  598. OUTPUTDEBUGSTRING("strFileName is " + strFileName);
  599. file = g_FSObj.CreateTextFile(strFileName, true);
  600. // Now attempt to delete any files older than "nLimit"
  601. enumFolder = new Enumerator(folder.files);
  602. for (; !enumFolder.atEnd(); enumFolder.moveNext())
  603. {
  604. strFileName = enumFolder.item();
  605. reResult = re.exec(strFileName.Name);
  606. if (reResult != null)
  607. {
  608. if (Number(reResult[1]) < nLargestIndex - nLimit)
  609. {
  610. OUTPUTDEBUGSTRING("Deleteing file " + strFileName.Name);
  611. DeleteFileNoThrow(strFileName.Path, true);
  612. }
  613. }
  614. }
  615. }
  616. catch(ex)
  617. {
  618. OUTPUTDEBUGSTRING("an error occurred while executing 'CreateNumberedFile('" + strBaseName + "') " + ex);
  619. throw ex;
  620. }
  621. return [file, strBaseName];
  622. }